diff --git a/compiler/src/prog8/ast/AstToplevel.kt b/compiler/src/prog8/ast/AstToplevel.kt index 8e9a3509f..96097ee1d 100644 --- a/compiler/src/prog8/ast/AstToplevel.kt +++ b/compiler/src/prog8/ast/AstToplevel.kt @@ -3,6 +3,8 @@ package prog8.ast import prog8.ast.base.* import prog8.ast.expressions.Expression import prog8.ast.expressions.IdentifierReference +import prog8.ast.expressions.InferredTypes +import prog8.ast.expressions.NumericLiteralValue import prog8.ast.walk.IAstVisitor import prog8.ast.statements.* import prog8.ast.walk.AstWalker @@ -242,11 +244,18 @@ interface IAssignable { // just a tag for now } +interface IBuiltinFunctions { + val names: Set + fun constValue(name: String, args: List, position: Position): NumericLiteralValue? + fun returnType(name: String, args: MutableList): InferredTypes.InferredType +} /*********** Everything starts from here, the Program; zero or more modules *************/ -class Program(val name: String, val modules: MutableList, builtinFunctionNames: Set): Node { - val namespace = GlobalNamespace(modules, builtinFunctionNames) + + +class Program(val name: String, val modules: MutableList, val builtinFunctions: IBuiltinFunctions): Node { + val namespace = GlobalNamespace(modules, builtinFunctions.names) val definedLoadAddress: Int get() = modules.first().loadAddress diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index 65b093b7c..0fd291ac2 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -6,10 +6,6 @@ import prog8.ast.base.* import prog8.ast.walk.IAstVisitor import prog8.ast.statements.* import prog8.ast.walk.AstWalker -import prog8.functions.BuiltinFunctions -import prog8.functions.CannotEvaluateException -import prog8.functions.NotConstArgumentException -import prog8.functions.builtinFunctionReturnType import java.util.* import kotlin.math.abs @@ -256,7 +252,7 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference, override fun referencesIdentifier(vararg scopedName: String) = arrayvar.referencesIdentifier(*scopedName) override fun inferType(program: Program): InferredTypes.InferredType { - val target = arrayvar.targetStatement(program.namespace) + val target = arrayvar.targetStatement(program) if (target is VarDecl) { return when (target.datatype) { DataType.STR -> InferredTypes.knownFor(DataType.UBYTE) @@ -711,14 +707,14 @@ internal fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression { data class IdentifierReference(val nameInSource: List, override val position: Position) : Expression(), IAssignable { override lateinit var parent: Node - fun targetStatement(namespace: INameScope) = - if(nameInSource.size==1 && nameInSource[0] in BuiltinFunctions) + fun targetStatement(program: Program) = + if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names) BuiltinFunctionStatementPlaceholder(nameInSource[0], position) else - namespace.lookup(nameInSource, this) + program.namespace.lookup(nameInSource, this) - fun targetVarDecl(namespace: INameScope): VarDecl? = targetStatement(namespace) as? VarDecl - fun targetSubroutine(namespace: INameScope): Subroutine? = targetStatement(namespace) as? Subroutine + fun targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl + fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine override fun equals(other: Any?) = other is IdentifierReference && other.nameInSource==nameInSource override fun hashCode() = nameInSource.hashCode() @@ -754,14 +750,14 @@ data class IdentifierReference(val nameInSource: List, override val posi nameInSource.size==scopedName.size && nameInSource.toTypedArray().contentEquals(scopedName) override fun inferType(program: Program): InferredTypes.InferredType { - return when (val targetStmt = targetStatement(program.namespace)) { + return when (val targetStmt = targetStatement(program)) { is VarDecl -> InferredTypes.knownFor(targetStmt.datatype) is StructDecl -> InferredTypes.knownFor(DataType.STRUCT) else -> InferredTypes.InferredType.unknown() } } - fun memberOfStruct(namespace: INameScope) = this.targetVarDecl(namespace)?.struct + fun memberOfStruct(program: Program) = this.targetVarDecl(program)?.struct fun heapId(namespace: INameScope): Int { val node = namespace.lookup(nameInSource, this) ?: throw UndefinedSymbolError(this) @@ -774,11 +770,11 @@ data class IdentifierReference(val nameInSource: List, override val posi } } - fun firstStructVarName(namespace: INameScope): String? { + fun firstStructVarName(program: Program): String? { // take the name of the first struct member of the structvariable instead // if it's just a regular variable, return null. - val struct = memberOfStruct(namespace) ?: return null - val decl = targetVarDecl(namespace)!! + val struct = memberOfStruct(program) ?: return null + val decl = targetVarDecl(program)!! if(decl.datatype!=DataType.STRUCT) return null @@ -816,34 +812,16 @@ class FunctionCall(override var target: IdentifierReference, private fun constValue(program: Program, withDatatypeCheck: Boolean): NumericLiteralValue? { // if the function is a built-in function and the args are consts, should try to const-evaluate! // lenghts of arrays and strings are constants that are determined at compile time! - if(target.nameInSource.size>1) return null - try { - var resultValue: NumericLiteralValue? = null - val func = BuiltinFunctions[target.nameInSource[0]] - if(func!=null) { - val exprfunc = func.constExpressionFunc - if(exprfunc!=null) - resultValue = exprfunc(args, position, program) - else if(func.known_returntype==null) - throw ExpressionError("builtin function ${target.nameInSource[0]} can't be used here because it doesn't return a value", position) - } - - if(withDatatypeCheck) { - val resultDt = this.inferType(program) - if(resultValue==null || resultDt istype resultValue.type) - return resultValue - throw FatalAstException("evaluated const expression result value doesn't match expected datatype $resultDt, pos=$position") - } else { + if(target.nameInSource.size>1) + return null + val resultValue: NumericLiteralValue? = program.builtinFunctions.constValue(target.nameInSource[0], args, position) + if(withDatatypeCheck) { + val resultDt = this.inferType(program) + if(resultValue==null || resultDt istype resultValue.type) return resultValue - } - } - catch(x: NotConstArgumentException) { - // const-evaluating the builtin function call failed. - return null - } - catch(x: CannotEvaluateException) { - // const-evaluating the builtin function call failed. - return null + throw FatalAstException("evaluated const expression result value doesn't match expected datatype $resultDt, pos=$position") + } else { + return resultValue } } @@ -860,14 +838,14 @@ class FunctionCall(override var target: IdentifierReference, val constVal = constValue(program ,false) if(constVal!=null) return InferredTypes.knownFor(constVal.type) - val stmt = target.targetStatement(program.namespace) ?: return InferredTypes.unknown() + val stmt = target.targetStatement(program) ?: return InferredTypes.unknown() when (stmt) { is BuiltinFunctionStatementPlaceholder -> { if(target.nameInSource[0] == "set_carry" || target.nameInSource[0]=="set_irqd" || target.nameInSource[0] == "clear_carry" || target.nameInSource[0]=="clear_irqd") { return InferredTypes.void() // these have no return value } - return builtinFunctionReturnType(target.nameInSource[0], this.args, program) + return program.builtinFunctions.returnType(target.nameInSource[0], this.args) } is Subroutine -> { if(stmt.returntypes.isEmpty()) diff --git a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt index 80ee88988..e26645579 100644 --- a/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt +++ b/compiler/src/prog8/compiler/BeforeAsmGenerationAstChanger.kt @@ -38,7 +38,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E // But it can only be done if the target variable IS NOT OCCURRING AS AN OPERAND ITSELF. if(!assignment.isAugmentable && assignment.target.identifier != null - && CompilationTarget.instance.isInRegularRAM(assignment.target, program.namespace)) { + && CompilationTarget.instance.isInRegularRAM(assignment.target, program)) { val binExpr = assignment.value as? BinaryExpression if (binExpr != null && binExpr.operator !in comparisonOperators) { if (binExpr.left !is BinaryExpression) { @@ -157,7 +157,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E if(typecast.type in WordDatatypes) { val fcall = typecast.parent as? IFunctionCall if (fcall != null) { - val sub = fcall.target.targetStatement(program.namespace) as? Subroutine + val sub = fcall.target.targetStatement(program) as? Subroutine if (sub != null && sub.isAsmSubroutine) { return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent)) } diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index c94ff7413..e559bf698 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -1,8 +1,12 @@ package prog8.compiler import prog8.ast.AstToSourceCode +import prog8.ast.IBuiltinFunctions import prog8.ast.Program import prog8.ast.base.* +import prog8.ast.expressions.Expression +import prog8.ast.expressions.InferredTypes +import prog8.ast.expressions.NumericLiteralValue import prog8.ast.statements.Directive import prog8.compiler.astprocessing.* import prog8.compiler.astprocessing.addTypecasts @@ -12,7 +16,7 @@ import prog8.compiler.astprocessing.reorderStatements import prog8.compiler.target.C64Target import prog8.compiler.target.CompilationTarget import prog8.compiler.target.Cx16Target -import prog8.functions.BuiltinFunctions +import prog8.functions.* import prog8.optimizer.* import prog8.optimizer.UnusedCodeRemover import prog8.optimizer.constantFold @@ -97,13 +101,44 @@ fun compileProgram(filepath: Path, throw x } - return CompilationResult(false, Program("failed", mutableListOf(), setOf()), programName, emptyList()) + val failedProgram = Program("failed", mutableListOf(), BuiltinFunctionsFacade(BuiltinFunctions)) + return CompilationResult(false, failedProgram, programName, emptyList()) +} + +private class BuiltinFunctionsFacade(functions: Map): IBuiltinFunctions { + lateinit var program: Program + + override val names = functions.keys + override fun constValue(name: String, args: List, position: Position): NumericLiteralValue? { + val func = BuiltinFunctions[name] + if(func!=null) { + val exprfunc = func.constExpressionFunc + if(exprfunc!=null) { + return try { + exprfunc(args, position, program) + } catch(x: NotConstArgumentException) { + // const-evaluating the builtin function call failed. + null + } catch(x: CannotEvaluateException) { + // const-evaluating the builtin function call failed. + null + } + } + else if(func.known_returntype==null) + throw IllegalArgumentException("builtin function $name can't be used here because it doesn't return a value") + } + return null + } + override fun returnType(name: String, args: MutableList) = + builtinFunctionReturnType(name, args, program) } private fun parseImports(filepath: Path, errors: ErrorReporter): Triple> { println("Compiler target: ${CompilationTarget.instance.name}. Parsing...") val importer = ModuleImporter() - val programAst = Program(moduleName(filepath.fileName), mutableListOf(), BuiltinFunctions.keys) + val bf = BuiltinFunctionsFacade(BuiltinFunctions) + val programAst = Program(moduleName(filepath.fileName), mutableListOf(), bf) + bf.program = programAst importer.importModule(programAst, filepath) errors.handle() diff --git a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt index 78aac2ba5..ec2f4dd35 100644 --- a/compiler/src/prog8/compiler/astprocessing/AstChecker.kt +++ b/compiler/src/prog8/compiler/astprocessing/AstChecker.kt @@ -100,7 +100,7 @@ internal class AstChecker(private val program: Program, if(iterableDt !in IterableDatatypes && forLoop.iterable !is RangeExpr) { errors.err("can only loop over an iterable type", forLoop.position) } else { - val loopvar = forLoop.loopVar.targetVarDecl(program.namespace) + val loopvar = forLoop.loopVar.targetVarDecl(program) if(loopvar==null || loopvar.type== VarDeclType.CONST) { errors.err("for loop requires a variable to loop with", forLoop.position) } else { @@ -377,7 +377,7 @@ internal class AstChecker(private val program: Program, override fun visit(assignment: Assignment) { if(assignment.value is FunctionCall) { - val stmt = (assignment.value as FunctionCall).target.targetStatement(program.namespace) + val stmt = (assignment.value as FunctionCall).target.targetStatement(program) if (stmt is Subroutine) { val idt = assignment.target.inferType(program) if(!idt.isKnown) { @@ -391,7 +391,7 @@ internal class AstChecker(private val program: Program, val targetIdent = assignment.target.identifier if(targetIdent!=null) { - val targetVar = targetIdent.targetVarDecl(program.namespace) + val targetVar = targetIdent.targetVarDecl(program) if(targetVar?.struct != null) { val sourceStructLv = assignment.value as? ArrayLiteralValue if (sourceStructLv != null) { @@ -400,7 +400,7 @@ internal class AstChecker(private val program: Program, } else { val sourceIdent = assignment.value as? IdentifierReference if (sourceIdent != null) { - val sourceVar = sourceIdent.targetVarDecl(program.namespace) + val sourceVar = sourceIdent.targetVarDecl(program) if (sourceVar?.struct != null) { if (sourceVar.struct !== targetVar.struct) errors.err("assignment of different struct types", assignment.position) @@ -488,7 +488,7 @@ internal class AstChecker(private val program: Program, } override fun visit(addressOf: AddressOf) { - val variable=addressOf.identifier.targetVarDecl(program.namespace) + val variable=addressOf.identifier.targetVarDecl(program) if(variable!=null && variable.datatype !in ArrayDatatypes && variable.type!=VarDeclType.MEMORY @@ -783,7 +783,7 @@ internal class AstChecker(private val program: Program, fun isPassByReferenceElement(e: Expression): Boolean { if(e is IdentifierReference) { - val decl = e.targetVarDecl(program.namespace)!! + val decl = e.targetVarDecl(program)!! return decl.datatype in PassByReferenceDatatypes } return e is StringLiteralValue @@ -936,12 +936,12 @@ internal class AstChecker(private val program: Program, errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCall.args.first().position) } - val error = VerifyFunctionArgTypes.checkTypes(functionCall, functionCall.definingScope(), program) + val error = VerifyFunctionArgTypes.checkTypes(functionCall, program) if(error!=null) errors.err(error, functionCall.position) // check the functions that return multiple returnvalues. - val stmt = functionCall.target.targetStatement(program.namespace) + val stmt = functionCall.target.targetStatement(program) if (stmt is Subroutine) { if (stmt.returntypes.size > 1) { // Currently, it's only possible to handle ONE (or zero) return values from a subroutine. @@ -1000,7 +1000,7 @@ internal class AstChecker(private val program: Program, } val error = - VerifyFunctionArgTypes.checkTypes(functionCallStatement, functionCallStatement.definingScope(), program) + VerifyFunctionArgTypes.checkTypes(functionCallStatement, program) if(error!=null) { errors.err(error, functionCallStatement.args.firstOrNull()?.position ?: functionCallStatement.position) } @@ -1027,7 +1027,7 @@ internal class AstChecker(private val program: Program, errors.err("swap requires args of numerical type", position) } else if(target.name=="all" || target.name=="any") { - if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program.namespace)?.datatype == DataType.STR) { + if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR) { errors.err("any/all on a string is useless (is always true unless the string is empty)", position) } if(args[0].inferType(program).typeOrElse(DataType.STR) == DataType.STR) { @@ -1082,7 +1082,7 @@ internal class AstChecker(private val program: Program, } } } else if(postIncrDecr.target.arrayindexed != null) { - val target = postIncrDecr.target.arrayindexed?.arrayvar?.targetStatement(program.namespace) + val target = postIncrDecr.target.arrayindexed?.arrayvar?.targetStatement(program) if(target==null) { errors.err("undefined symbol", postIncrDecr.position) } @@ -1097,7 +1097,7 @@ internal class AstChecker(private val program: Program, } override fun visit(arrayIndexedExpression: ArrayIndexedExpression) { - val target = arrayIndexedExpression.arrayvar.targetStatement(program.namespace) + val target = arrayIndexedExpression.arrayvar.targetStatement(program) if(target is VarDecl) { if(target.datatype !in IterableDatatypes) errors.err("indexing requires an iterable variable", arrayIndexedExpression.position) @@ -1189,7 +1189,7 @@ internal class AstChecker(private val program: Program, } private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? { - val targetStatement = target.targetStatement(program.namespace) + val targetStatement = target.targetStatement(program) if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder) return targetStatement else if(targetStatement==null) @@ -1407,7 +1407,7 @@ internal class AstChecker(private val program: Program, if(sourceDatatype==DataType.STRUCT) { val structLv = sourceValue as ArrayLiteralValue val numValues = structLv.value.size - val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!! + val targetstruct = target.identifier!!.targetVarDecl(program)!!.struct!! return targetstruct.numberOfElements == numValues } false diff --git a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt index af66d4149..e8605bd62 100644 --- a/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt +++ b/compiler/src/prog8/compiler/astprocessing/StatementReorderer.kt @@ -84,7 +84,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable { - val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program.namespace) + val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program) if(arrayVar!=null && arrayVar.datatype == DataType.UWORD) { // rewrite pointervar[index] into @(pointervar+index) val indexer = arrayIndexedExpression.indexer @@ -142,7 +142,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte } is IFunctionCall -> { val argnum = parent.args.indexOf(expr) - when (val callee = parent.target.targetStatement(program.namespace)) { + when (val callee = parent.target.targetStatement(program)) { is Subroutine -> { val paramType = callee.parameters[argnum].type if(leftDt isAssignableTo paramType) { @@ -315,16 +315,16 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte private fun flattenArrayAssignmentFromArrayLiteral(assign: Assignment): List { val identifier = assign.target.identifier!! - val targetVar = identifier.targetVarDecl(program.namespace)!! + val targetVar = identifier.targetVarDecl(program)!! val alv = assign.value as? ArrayLiteralValue return flattenArrayAssign(targetVar, alv, identifier, assign.position) } private fun flattenArrayAssignmentFromIdentifier(assign: Assignment): List { val identifier = assign.target.identifier!! - val targetVar = identifier.targetVarDecl(program.namespace)!! + val targetVar = identifier.targetVarDecl(program)!! val sourceIdent = assign.value as IdentifierReference - val sourceVar = sourceIdent.targetVarDecl(program.namespace)!! + val sourceVar = sourceIdent.targetVarDecl(program)!! if(!sourceVar.isArray) { errors.err("value must be an array", sourceIdent.position) return emptyList() @@ -354,7 +354,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte private fun flattenStructAssignmentFromStructLiteral(structAssignment: Assignment): List { val identifier = structAssignment.target.identifier!! val identifierName = identifier.nameInSource.single() - val targetVar = identifier.targetVarDecl(program.namespace)!! + val targetVar = identifier.targetVarDecl(program)!! val struct = targetVar.struct!! val slv = structAssignment.value as? ArrayLiteralValue @@ -378,11 +378,11 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte // TODO use memcopy beyond a certain number of elements val identifier = structAssignment.target.identifier!! val identifierName = identifier.nameInSource.single() - val targetVar = identifier.targetVarDecl(program.namespace)!! + val targetVar = identifier.targetVarDecl(program)!! val struct = targetVar.struct!! when (structAssignment.value) { is IdentifierReference -> { - val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program.namespace)!! + val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program)!! when { sourceVar.struct!=null -> { // struct memberwise copy diff --git a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt index b8b54ccb4..3cc062860 100644 --- a/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt +++ b/compiler/src/prog8/compiler/astprocessing/TypecastsAdder.kt @@ -1,7 +1,6 @@ package prog8.compiler.astprocessing import prog8.ast.IFunctionCall -import prog8.ast.INameScope import prog8.ast.Node import prog8.ast.Program import prog8.ast.base.* @@ -108,18 +107,18 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke } override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { - return afterFunctionCallArgs(functionCallStatement, functionCallStatement.definingScope()) + return afterFunctionCallArgs(functionCallStatement) } override fun after(functionCall: FunctionCall, parent: Node): Iterable { - return afterFunctionCallArgs(functionCall, functionCall.definingScope()) + return afterFunctionCallArgs(functionCall) } - private fun afterFunctionCallArgs(call: IFunctionCall, scope: INameScope): Iterable { + private fun afterFunctionCallArgs(call: IFunctionCall): Iterable { // see if a typecast is needed to convert the arguments into the required parameter's type val modifications = mutableListOf() - when(val sub = call.target.targetStatement(scope)) { + when(val sub = call.target.targetStatement(program)) { is Subroutine -> { sub.parameters.zip(call.args).forEachIndexed { index, pair -> val argItype = pair.second.inferType(program) diff --git a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt index 7e313ebfe..fecbcd2e3 100644 --- a/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt +++ b/compiler/src/prog8/compiler/astprocessing/VerifyFunctionArgTypes.kt @@ -1,7 +1,6 @@ package prog8.compiler.astprocessing import prog8.ast.IFunctionCall -import prog8.ast.INameScope import prog8.ast.Program import prog8.ast.base.DataType import prog8.ast.expressions.Expression @@ -15,13 +14,13 @@ import prog8.functions.BuiltinFunctions class VerifyFunctionArgTypes(val program: Program) : IAstVisitor { override fun visit(functionCall: FunctionCall) { - val error = checkTypes(functionCall as IFunctionCall, functionCall.definingScope(), program) + val error = checkTypes(functionCall as IFunctionCall, program) if(error!=null) throw CompilerException(error) } override fun visit(functionCallStatement: FunctionCallStatement) { - val error = checkTypes(functionCallStatement as IFunctionCall, functionCallStatement.definingScope(), program) + val error = checkTypes(functionCallStatement as IFunctionCall, program) if (error!=null) throw CompilerException(error) } @@ -40,13 +39,13 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor { return false } - fun checkTypes(call: IFunctionCall, scope: INameScope, program: Program): String? { + fun checkTypes(call: IFunctionCall, program: Program): String? { val argITypes = call.args.map { it.inferType(program) } val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown } if(firstUnknownDt>=0) return "argument ${firstUnknownDt+1} invalid argument type" val argtypes = argITypes.map { it.typeOrElse(DataType.STRUCT) } - val target = call.target.targetStatement(scope) + val target = call.target.targetStatement(program) if (target is Subroutine) { if(call.args.size != target.parameters.size) return "invalid number of arguments" diff --git a/compiler/src/prog8/compiler/target/CompilationTarget.kt b/compiler/src/prog8/compiler/target/CompilationTarget.kt index 71c96c852..a1d09f386 100644 --- a/compiler/src/prog8/compiler/target/CompilationTarget.kt +++ b/compiler/src/prog8/compiler/target/CompilationTarget.kt @@ -1,6 +1,5 @@ package prog8.compiler.target -import prog8.ast.INameScope import prog8.ast.IStringEncoding import prog8.ast.Program import prog8.ast.base.* @@ -28,7 +27,7 @@ internal interface CompilationTarget: IStringEncoding { lateinit var instance: CompilationTarget } - fun isInRegularRAM(target: AssignTarget, namespace: INameScope): Boolean { + fun isInRegularRAM(target: AssignTarget, program: Program): Boolean { when { target.memoryAddress != null -> { return when (target.memoryAddress.addressExpression) { @@ -36,7 +35,7 @@ internal interface CompilationTarget: IStringEncoding { machine.isRegularRAMaddress((target.memoryAddress.addressExpression as NumericLiteralValue).number.toInt()) } is IdentifierReference -> { - val decl = (target.memoryAddress.addressExpression as IdentifierReference).targetVarDecl(namespace) + val decl = (target.memoryAddress.addressExpression as IdentifierReference).targetVarDecl(program) if ((decl?.type == VarDeclType.VAR || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteralValue) machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt()) else @@ -46,7 +45,7 @@ internal interface CompilationTarget: IStringEncoding { } } target.arrayindexed != null -> { - val targetStmt = target.arrayindexed!!.arrayvar.targetVarDecl(namespace) + val targetStmt = target.arrayindexed!!.arrayvar.targetVarDecl(program) return if (targetStmt?.type == VarDeclType.MEMORY) { val addr = targetStmt.value as? NumericLiteralValue if (addr != null) @@ -56,7 +55,7 @@ internal interface CompilationTarget: IStringEncoding { } else true } target.identifier != null -> { - val decl = target.identifier!!.targetVarDecl(namespace)!! + val decl = target.identifier!!.targetVarDecl(program)!! return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue) machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt()) else diff --git a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt index 95c5e2da0..82fc1d7bc 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/AsmGen.kt @@ -430,10 +430,10 @@ internal class AsmGen(private val program: Program, "$" + it.number.toInt().toString(16).padStart(4, '0') } is AddressOf -> { - it.identifier.firstStructVarName(program.namespace) ?: asmSymbolName(it.identifier) + it.identifier.firstStructVarName(program) ?: asmSymbolName(it.identifier) } is IdentifierReference -> { - it.firstStructVarName(program.namespace) ?: asmSymbolName(it) + it.firstStructVarName(program) ?: asmSymbolName(it) } else -> throw AssemblyError("weird array elt dt") } @@ -495,8 +495,8 @@ internal class AsmGen(private val program: Program, } internal fun asmSymbolName(identifier: IdentifierReference): String { - return if(identifier.memberOfStruct(program.namespace)!=null) { - val name = identifier.targetVarDecl(program.namespace)!!.name + return if(identifier.memberOfStruct(program)!=null) { + val name = identifier.targetVarDecl(program)!!.name fixNameSymbols(name) } else { fixNameSymbols(identifier.nameInSource.joinToString(".")) @@ -510,8 +510,8 @@ internal class AsmGen(private val program: Program, throw AssemblyError("no symbol name for register $regs") internal fun asmVariableName(identifier: IdentifierReference): String { - return if(identifier.memberOfStruct(program.namespace)!=null) { - val name = identifier.targetVarDecl(program.namespace)!!.name + return if(identifier.memberOfStruct(program)!=null) { + val name = identifier.targetVarDecl(program)!!.name fixNameSymbols(name) } else { fixNameSymbols(identifier.nameInSource.joinToString(".")) @@ -527,7 +527,7 @@ internal class AsmGen(private val program: Program, internal fun loadByteFromPointerIntoA(pointervar: IdentifierReference): Pair { // returns if the pointer is already on the ZP itself or not (in the latter case SCRATCH_W1 is used as intermediary) val sourceName = asmVariableName(pointervar) - val vardecl = pointervar.targetVarDecl(program.namespace)!! + val vardecl = pointervar.targetVarDecl(program)!! val scopedName = vardecl.makeScopedName(vardecl.name) if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { return if (isZpVar(scopedName)) { @@ -965,7 +965,7 @@ internal class AsmGen(private val program: Program, } } is IdentifierReference -> { - val vardecl = (stmt.iterations as IdentifierReference).targetStatement(program.namespace) as VarDecl + val vardecl = (stmt.iterations as IdentifierReference).targetStatement(program) as VarDecl val name = asmVariableName(stmt.iterations as IdentifierReference) when(vardecl.datatype) { DataType.UBYTE, DataType.BYTE -> { @@ -1275,7 +1275,7 @@ $label nop""") private fun getJumpTarget(jmp: Jump): String { return when { jmp.identifier!=null -> { - val target = jmp.identifier.targetStatement(program.namespace) + val target = jmp.identifier.targetStatement(program) val asmName = asmSymbolName(jmp.identifier) if(target is Label) "_$asmName" // prefix with underscore to jump to local label @@ -1362,7 +1362,7 @@ $label nop""") internal fun isZpVar(scopedName: String): Boolean = scopedName in allocatedZeropageVariables internal fun isZpVar(variable: IdentifierReference): Boolean { - val vardecl = variable.targetVarDecl(program.namespace)!! + val vardecl = variable.targetVarDecl(program)!! return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables } diff --git a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt index 5c716eb57..b58482785 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/BuiltinFunctionsAsmGen.kt @@ -71,7 +71,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val throw AssemblyError("should not discard result of memory allocation at $fcall") val scope = fcall.definingScope() val nameRef = fcall.args[0] as IdentifierReference - val name = (nameRef.targetVarDecl(program.namespace)!!.value as StringLiteralValue).value + val name = (nameRef.targetVarDecl(program)!!.value as StringLiteralValue).value val size = (fcall.args[1] as NumericLiteralValue).number.toInt() val existingSize = asmgen.slabs[name] @@ -125,7 +125,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val private fun funcReverse(fcall: IFunctionCall) { val variable = fcall.args.single() if (variable is IdentifierReference) { - val decl = variable.targetVarDecl(program.namespace)!! + val decl = variable.targetVarDecl(program)!! val varName = asmgen.asmVariableName(variable) val numElements = decl.arraysize!!.constIndex() when (decl.datatype) { @@ -164,7 +164,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val private fun funcSort(fcall: IFunctionCall) { val variable = fcall.args.single() if (variable is IdentifierReference) { - val decl = variable.targetVarDecl(program.namespace)!! + val decl = variable.targetVarDecl(program)!! val varName = asmgen.asmVariableName(variable) val numElements = decl.arraysize!!.constIndex() when (decl.datatype) { @@ -1108,7 +1108,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val // address in P8ZP_SCRATCH_W1, number of elements in A arg as IdentifierReference val identifierName = asmgen.asmVariableName(arg) - val size = arg.targetVarDecl(program.namespace)!!.arraysize!!.constIndex()!! + val size = arg.targetVarDecl(program)!!.arraysize!!.constIndex()!! asmgen.out(""" lda #<$identifierName ldy #>$identifierName diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt index aeeb03659..6ebb975f4 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ExpressionsAsmGen.kt @@ -1327,7 +1327,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge private fun translateFunctionCallResultOntoStack(call: FunctionCall) { // only for use in nested expression evaluation - val sub = call.target.targetStatement(program.namespace) + val sub = call.target.targetStatement(program) if(sub is BuiltinFunctionStatementPlaceholder) { val builtinFunc = BuiltinFunctions.getValue(sub.name) asmgen.translateBuiltinFunctionCallExpression(call, builtinFunc, true, null) diff --git a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt index 9c7aa8c37..f32429a04 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/ForLoopsAsmGen.kt @@ -239,7 +239,7 @@ $endLabel""") val endLabel = asmgen.makeLabel("for_end") asmgen.loopEndLabels.push(endLabel) val iterableName = asmgen.asmVariableName(ident) - val decl = ident.targetVarDecl(program.namespace)!! + val decl = ident.targetVarDecl(program)!! when(iterableDt) { DataType.STR -> { asmgen.out(""" diff --git a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt index cfcae2607..f7fac1948 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/FunctionCallAsmGen.kt @@ -22,7 +22,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } internal fun saveXbeforeCall(stmt: IFunctionCall) { - val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") + val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}") if(sub.shouldSaveX()) { val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA() @@ -34,7 +34,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg } internal fun restoreXafterCall(stmt: IFunctionCall) { - val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") + val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}") if(sub.shouldSaveX()) { val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA() @@ -52,7 +52,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg // NOTE: does NOT output code to save/restore the X register for this call! Every caller should deal with this in their own way!! // (you can use subroutine.shouldSaveX() and saveX()/restoreX() routines as a help for this) - val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}") + val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}") val subName = asmgen.asmSymbolName(stmt.target) if(stmt.args.isNotEmpty()) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt index b4e550e00..e2bfafb0d 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AsmAssignment.kt @@ -157,7 +157,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind, AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value) } is FunctionCall -> { - when (val sub = value.target.targetStatement(program.namespace)) { + when (val sub = value.target.targetStatement(program)) { is Subroutine -> { val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first ?: throw AssemblyError("can't translate zero return values in assignment") diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt index 3a151c5ab..f7083fa90 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AssignmentAsmGen.kt @@ -143,7 +143,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen SourceStorageKind.EXPRESSION -> { when(val value = assign.source.expression!!) { is AddressOf -> { - val sourceName = value.identifier.firstStructVarName(program.namespace) ?: asmgen.asmVariableName(value.identifier) + val sourceName = value.identifier.firstStructVarName(program) ?: asmgen.asmVariableName(value.identifier) assignAddressOf(assign.target, sourceName) } is NumericLiteralValue -> throw AssemblyError("source kind should have been literalnumber") @@ -152,7 +152,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen is DirectMemoryRead -> throw AssemblyError("source kind should have been memory") is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value) is FunctionCall -> { - when (val sub = value.target.targetStatement(program.namespace)) { + when (val sub = value.target.targetStatement(program)) { is Subroutine -> { asmgen.saveXbeforeCall(value) asmgen.translateFunctionCall(value) @@ -2061,7 +2061,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen fun storeAIntoPointerVar(pointervar: IdentifierReference) { val sourceName = asmgen.asmVariableName(pointervar) - val vardecl = pointervar.targetVarDecl(program.namespace)!! + val vardecl = pointervar.targetVarDecl(program)!! val scopedName = vardecl.makeScopedName(vardecl.name) if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) { if (asmgen.isZpVar(scopedName)) { diff --git a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt index bf1702a47..87b544382 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen/assignment/AugmentableAssignmentAsmGen.kt @@ -986,7 +986,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) { val otherName = asmgen.asmVariableName(ident) - val valueDt = ident.targetVarDecl(program.namespace)!!.datatype + val valueDt = ident.targetVarDecl(program)!!.datatype when (valueDt) { in ByteDatatypes -> { // the other variable is a BYTE type so optimize for that @@ -1467,7 +1467,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program, } private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine) { - val valueDt = ident.targetVarDecl(program.namespace)!!.datatype + val valueDt = ident.targetVarDecl(program)!!.datatype if(valueDt != DataType.FLOAT) throw AssemblyError("float variable expected") diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 83e9b91fe..6bb15f26d 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -287,7 +287,7 @@ private fun builtinOffsetof(args: List, position: Position, program: val idref = args[0] as? IdentifierReference ?: throw SyntaxError("offsetof argument should be an identifier", position) - val vardecl = idref.targetVarDecl(program.namespace)!! + val vardecl = idref.targetVarDecl(program)!! val struct = vardecl.struct if (struct == null || vardecl.datatype == DataType.STRUCT) throw SyntaxError("offsetof can only be used on struct members", position) @@ -311,7 +311,7 @@ private fun builtinSizeof(args: List, position: Position, program: P val dt = args[0].inferType(program) if(dt.isKnown) { - val target = (args[0] as IdentifierReference).targetStatement(program.namespace) + val target = (args[0] as IdentifierReference).targetStatement(program) ?: throw CannotEvaluateException("sizeof", "no target") fun structSize(target: StructDecl) = @@ -343,7 +343,7 @@ private fun builtinLen(args: List, position: Position, program: Prog if(args.size!=1) throw SyntaxError("len requires one argument", position) - val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(program.namespace) + val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(program) var arraySize = directMemVar?.arraysize?.constIndex() if(arraySize != null) return NumericLiteralValue.optimalInteger(arraySize, position) @@ -351,7 +351,7 @@ private fun builtinLen(args: List, position: Position, program: Prog return NumericLiteralValue.optimalInteger((args[0] as ArrayLiteralValue).value.size, position) if(args[0] !is IdentifierReference) throw SyntaxError("len argument should be an identifier", position) - val target = (args[0] as IdentifierReference).targetVarDecl(program.namespace) + val target = (args[0] as IdentifierReference).targetVarDecl(program) ?: throw CannotEvaluateException("len", "no target vardecl") return when(target.datatype) { diff --git a/compiler/src/prog8/optimizer/BinExprSplitter.kt b/compiler/src/prog8/optimizer/BinExprSplitter.kt index 0abc316ed..f624ae7cf 100644 --- a/compiler/src/prog8/optimizer/BinExprSplitter.kt +++ b/compiler/src/prog8/optimizer/BinExprSplitter.kt @@ -1,6 +1,5 @@ package prog8.optimizer -import prog8.ast.INameScope import prog8.ast.Node import prog8.ast.Program import prog8.ast.expressions.* @@ -54,7 +53,7 @@ X = BinExpr X = LeftExpr */ - if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program.namespace)) { + if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program)) { if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right) return noModifications @@ -79,9 +78,9 @@ X = BinExpr X = LeftExpr private fun isSimpleExpression(expr: Expression) = expr is IdentifierReference || expr is NumericLiteralValue || expr is AddressOf || expr is DirectMemoryRead || expr is StringLiteralValue || expr is ArrayLiteralValue || expr is RangeExpr - private fun isSimpleTarget(target: AssignTarget, namespace: INameScope) = + private fun isSimpleTarget(target: AssignTarget, program: Program) = if (target.identifier!=null || target.memoryAddress!=null) - CompilationTarget.instance.isInRegularRAM(target, namespace) + CompilationTarget.instance.isInRegularRAM(target, program) else false diff --git a/compiler/src/prog8/optimizer/CallGraph.kt b/compiler/src/prog8/optimizer/CallGraph.kt index 4977ebd49..489fd6e43 100644 --- a/compiler/src/prog8/optimizer/CallGraph.kt +++ b/compiler/src/prog8/optimizer/CallGraph.kt @@ -89,7 +89,7 @@ class CallGraph(private val program: Program) : IAstVisitor { override fun visit(identifier: IdentifierReference) { // track symbol usage - val target = identifier.targetStatement(this.program.namespace) + val target = identifier.targetStatement(program) if (target != null) { addNodeAndParentScopes(target) } @@ -126,7 +126,7 @@ class CallGraph(private val program: Program) : IAstVisitor { } override fun visit(functionCall: FunctionCall) { - val otherSub = functionCall.target.targetSubroutine(program.namespace) + val otherSub = functionCall.target.targetSubroutine(program) if (otherSub != null) { functionCall.definingSubroutine()?.let { thisSub -> calls[thisSub] = calls.getValue(thisSub).plus(otherSub) @@ -137,7 +137,7 @@ class CallGraph(private val program: Program) : IAstVisitor { } override fun visit(functionCallStatement: FunctionCallStatement) { - val otherSub = functionCallStatement.target.targetSubroutine(program.namespace) + val otherSub = functionCallStatement.target.targetSubroutine(program) if (otherSub != null) { functionCallStatement.definingSubroutine()?.let { thisSub -> calls[thisSub] = calls.getValue(thisSub).plus(otherSub) @@ -148,7 +148,7 @@ class CallGraph(private val program: Program) : IAstVisitor { } override fun visit(jump: Jump) { - val otherSub = jump.identifier?.targetSubroutine(program.namespace) + val otherSub = jump.identifier?.targetSubroutine(program) if (otherSub != null) { jump.definingSubroutine()?.let { thisSub -> calls[thisSub] = calls.getValue(thisSub).plus(otherSub) diff --git a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt index 288eb7f9a..70528f050 100644 --- a/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt +++ b/compiler/src/prog8/optimizer/ConstantFoldingOptimizer.kt @@ -231,7 +231,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke val rangeTo = iterableRange.to as? NumericLiteralValue if(rangeFrom==null || rangeTo==null) return noModifications - val loopvar = forLoop.loopVar.targetVarDecl(program.namespace) ?: throw UndefinedSymbolError(forLoop.loopVar) + val loopvar = forLoop.loopVar.targetVarDecl(program) ?: throw UndefinedSymbolError(forLoop.loopVar) val stepLiteral = iterableRange.step as? NumericLiteralValue when(loopvar.datatype) { diff --git a/compiler/src/prog8/optimizer/StatementOptimizer.kt b/compiler/src/prog8/optimizer/StatementOptimizer.kt index 25c0846ed..e6dd9ee34 100644 --- a/compiler/src/prog8/optimizer/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizer/StatementOptimizer.kt @@ -89,7 +89,7 @@ internal class StatementOptimizer(private val program: Program, arg as? IdentifierReference } if(stringVar!=null) { - val vardecl = stringVar.targetVarDecl(program.namespace)!! + val vardecl = stringVar.targetVarDecl(program)!! val string = vardecl.value as? StringLiteralValue if(string!=null) { val pos = functionCallStatement.position @@ -123,7 +123,7 @@ internal class StatementOptimizer(private val program: Program, } // if the first instruction in the called subroutine is a return statement, remove the jump altogeter - val subroutine = functionCallStatement.target.targetSubroutine(program.namespace) + val subroutine = functionCallStatement.target.targetSubroutine(program) if(subroutine!=null) { val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull() if(first is Return) @@ -135,7 +135,7 @@ internal class StatementOptimizer(private val program: Program, override fun before(functionCall: FunctionCall, parent: Node): Iterable { // if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value - val subroutine = functionCall.target.targetSubroutine(program.namespace) + val subroutine = functionCall.target.targetSubroutine(program) if(subroutine!=null) { val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull() if(first is Return && first.value!=null) { @@ -203,7 +203,7 @@ internal class StatementOptimizer(private val program: Program, return listOf(IAstModification.ReplaceNode(forLoop, scope, parent)) } } - val iterable = (forLoop.iterable as? IdentifierReference)?.targetVarDecl(program.namespace) + val iterable = (forLoop.iterable as? IdentifierReference)?.targetVarDecl(program) if(iterable!=null) { if(iterable.datatype==DataType.STR) { val sv = iterable.value as StringLiteralValue @@ -306,7 +306,7 @@ internal class StatementOptimizer(private val program: Program, override fun after(jump: Jump, parent: Node): Iterable { // if the jump is to the next statement, remove the jump val scope = jump.definingScope() - val label = jump.identifier?.targetStatement(scope) + val label = jump.identifier?.targetStatement(program) if(label!=null && scope.statements.indexOf(label) == scope.statements.indexOf(jump)+1) return listOf(IAstModification.Remove(jump, jump.definingScope())) @@ -390,7 +390,7 @@ internal class StatementOptimizer(private val program: Program, // assignments of the form: X = X // remove assignments that have no effect (such as X=X+0) // optimize/rewrite some other expressions - val vardeclDt = (assignment.target.identifier?.targetVarDecl(program.namespace))?.type + val vardeclDt = (assignment.target.identifier?.targetVarDecl(program))?.type when (bexpr.operator) { "+" -> { if (rightCv == 0.0) { diff --git a/compiler/src/prog8/optimizer/UnusedCodeRemover.kt b/compiler/src/prog8/optimizer/UnusedCodeRemover.kt index 3d07d1dfb..aa616b5dd 100644 --- a/compiler/src/prog8/optimizer/UnusedCodeRemover.kt +++ b/compiler/src/prog8/optimizer/UnusedCodeRemover.kt @@ -93,7 +93,7 @@ internal class UnusedCodeRemover(private val program: Program, private val error val assign1 = stmtPairs[0] as? Assignment val assign2 = stmtPairs[1] as? Assignment if (assign1 != null && assign2 != null && !assign2.isAugmentable) { - if (assign1.target.isSameAs(assign2.target, program) && CompilationTarget.instance.isInRegularRAM(assign1.target, program.namespace)) { + if (assign1.target.isSameAs(assign2.target, program) && CompilationTarget.instance.isInRegularRAM(assign1.target, program)) { if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(*(assign2.target.identifier!!.nameInSource.toTypedArray()))) // only remove the second assignment if its value is a simple expression! when(assign2.value) { diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index 0b14c0619..c4841d740 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -5,6 +5,9 @@ import org.hamcrest.Matchers.closeTo import org.hamcrest.Matchers.equalTo import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance +import prog8.ast.IBuiltinFunctions +import prog8.ast.Program +import prog8.ast.Module import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* @@ -19,6 +22,7 @@ import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5 import prog8.compiler.target.c64.Petscii import prog8.compiler.target.cx16.CX16MachineDefinition import java.io.CharConversionException +import java.nio.file.Path import kotlin.test.* @TestInstance(TestInstance.Lifecycle.PER_CLASS) @@ -402,34 +406,36 @@ class TestPetscii { class TestMemory { + private class DummyFunctions: IBuiltinFunctions { + override val names: Set = emptySet() + override fun constValue(name: String, args: List, position: Position): NumericLiteralValue? = null + override fun returnType(name: String, args: MutableList) = InferredTypes.InferredType.unknown() + } + @Test fun testInValidRamC64_memory_addresses() { CompilationTarget.instance = C64Target var memexpr = NumericLiteralValue.optimalInteger(0x0000, Position.DUMMY) var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - var scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope)) + val program = Program("test", mutableListOf(), DummyFunctions()) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0x9fff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0xc000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0xcfff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -438,38 +444,37 @@ class TestMemory { var memexpr = NumericLiteralValue.optimalInteger(0xa000, Position.DUMMY) var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - var scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope)) + val program = Program("test", mutableListOf(), DummyFunctions()) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0xafff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0xd000, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) memexpr = NumericLiteralValue.optimalInteger(0xffff, Position.DUMMY) target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope)) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test fun testInValidRamC64_memory_identifiers() { CompilationTarget.instance = C64Target var target = createTestProgramForMemoryRefViaVar(0x1000, VarDeclType.VAR) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val program = Program("test", mutableListOf(), DummyFunctions()) + + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) target = createTestProgramForMemoryRefViaVar(0xd020, VarDeclType.VAR) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) target = createTestProgramForMemoryRefViaVar(0x1000, VarDeclType.CONST) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) target = createTestProgramForMemoryRefViaVar(0xd020, VarDeclType.CONST) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) target = createTestProgramForMemoryRefViaVar(0x1000, VarDeclType.MEMORY) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -479,7 +484,8 @@ class TestMemory { val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + module.linkParents(ParentSentinel) return target } @@ -488,8 +494,8 @@ class TestMemory { CompilationTarget.instance = C64Target val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY) val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY) - val scope = AnonymousScope(mutableListOf(), Position.DUMMY) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope)) + val program = Program("test", mutableListOf(), DummyFunctions()) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -499,8 +505,10 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + val program = Program("test", mutableListOf(module), DummyFunctions()) + module.linkParents(ParentSentinel) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -511,8 +519,10 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + val program = Program("test", mutableListOf(module), DummyFunctions()) + module.linkParents(ParentSentinel) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -523,8 +533,10 @@ class TestMemory { val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + val program = Program("test", mutableListOf(module), DummyFunctions()) + module.linkParents(ParentSentinel) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -535,8 +547,10 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + val program = Program("test", mutableListOf(module), DummyFunctions()) + module.linkParents(ParentSentinel) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -548,8 +562,10 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) - assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + val program = Program("test", mutableListOf(module), DummyFunctions()) + module.linkParents(ParentSentinel) + assertTrue(CompilationTarget.instance.isInRegularRAM(target, program)) } @Test @@ -561,7 +577,9 @@ class TestMemory { val target = AssignTarget(null, arrayindexed, null, Position.DUMMY) val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY) val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY) - subroutine.linkParents(ParentSentinel) - assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope())) + val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of("")) + val program = Program("test", mutableListOf(module), DummyFunctions()) + module.linkParents(ParentSentinel) + assertFalse(CompilationTarget.instance.isInRegularRAM(target, program)) } }