From 824f06e17f3429ce8c31eb90d3dbe83369d7429d Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sat, 21 Mar 2020 13:22:04 +0100 Subject: [PATCH] new var init values --- compiler/src/prog8/ast/base/Extensions.kt | 3 +- .../src/prog8/ast/processing/AstWalker.kt | 12 ++ .../VarInitValueAndAddressOfCreator.kt | 126 +++++++----------- .../src/prog8/ast/statements/AstStatements.kt | 2 +- compiler/src/prog8/compiler/Main.kt | 1 + examples/test.p8 | 34 +++-- 6 files changed, 82 insertions(+), 96 deletions(-) diff --git a/compiler/src/prog8/ast/base/Extensions.kt b/compiler/src/prog8/ast/base/Extensions.kt index 1e09478a1..1d1e95dac 100644 --- a/compiler/src/prog8/ast/base/Extensions.kt +++ b/compiler/src/prog8/ast/base/Extensions.kt @@ -23,8 +23,9 @@ internal fun Program.moveAnonScopeVarsToSubroutine(errors: ErrorReporter) { } internal fun Program.reorderStatements() { - val initvalueCreator = VarInitValueAndAddressOfCreator(this) + val initvalueCreator = VarInitValueCreator(this) initvalueCreator.visit(this) + initvalueCreator.applyModifications() val checker = StatementReorderer(this) checker.visit(this) diff --git a/compiler/src/prog8/ast/processing/AstWalker.kt b/compiler/src/prog8/ast/processing/AstWalker.kt index 4eb127a54..475ea0185 100644 --- a/compiler/src/prog8/ast/processing/AstWalker.kt +++ b/compiler/src/prog8/ast/processing/AstWalker.kt @@ -41,6 +41,18 @@ interface IAstModification { newExpr.linkParents(parent) } } + + class Insert(val after: Statement?, val stmt: Statement, val parent: Node) : IAstModification { + override fun perform() { + if(parent is INameScope) { + val idx = if(after==null) 0 else parent.statements.indexOf(after) + parent.statements.add(idx, stmt) + stmt.linkParents(parent) + } else { + throw FatalAstException("parent of an insert modification is not an INameScope") + } + } + } } diff --git a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt index def02a8b7..7341d891e 100644 --- a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt +++ b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt @@ -1,7 +1,5 @@ package prog8.ast.processing -import prog8.ast.INameScope -import prog8.ast.Module import prog8.ast.Node import prog8.ast.Program import prog8.ast.base.* @@ -12,124 +10,109 @@ import prog8.functions.BuiltinFunctions import prog8.functions.FSignature -internal class VarInitValueAndAddressOfCreator(private val program: Program): IAstModifyingVisitor { +internal class VarInitValueCreator(val program: Program): AstWalker() { // For VarDecls that declare an initialization value: - // Replace the vardecl with an assignment (to set the initial value), - // and add a new vardecl with the default constant value of that type (usually zero) to the scope. + // add an assignment to set this initial value explicitly. // This makes sure the variables get reset to the intended value on a next run of the program. - // Variable decls without a value don't get this treatment, which means they retain the last - // value they had when restarting the program. - // This is done in a separate step because it interferes with the namespace lookup of symbols - // in other ast processors. - // Also takes care to insert AddressOf (&) expression where required (string params to a UWORD function param etc). + // TODO join this into the StatementReorderer? + // TODO actually I think the code generator should take care of this entirely, and this step should be removed from the ast modifications... - private val vardeclsToAdd = mutableMapOf>() - - override fun visit(module: Module) { - vardeclsToAdd.clear() - super.visit(module) - // add any new vardecls to the various scopes - for((where, decls) in vardeclsToAdd) { - where.statements.addAll(0, decls) - decls.forEach { it.linkParents(where as Node) } - } - } - - override fun visit(decl: VarDecl): Statement { - super.visit(decl) - + override fun after(decl: VarDecl, parent: Node): Iterable { if(decl.isArray && decl.value==null) { // array datatype without initialization value, add list of zeros val arraysize = decl.arraysize!!.size()!! - val array = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), - Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) }, - decl.position) - decl.value = array + val zero = decl.asDefaultValueDecl(decl).value!! + return listOf(IAstModification.ReplaceExpr( + { newExpr -> decl.value = newExpr }, + ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype), + Array(arraysize) { zero }, + decl.position), + decl + )) } - if(decl.type!= VarDeclType.VAR || decl.value==null) - return decl - - if(decl.datatype in NumericDatatypes) { - val scope = decl.definingScope() - addVarDecl(scope, decl.asDefaultValueDecl(null)) + if(decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes) { val declvalue = decl.value!! val value = if(declvalue is NumericLiteralValue) declvalue.cast(decl.datatype) else declvalue - val identifierName = listOf(decl.name) // this was: (scoped name) decl.scopedname.split(".") - return VariableInitializationAssignment( - AssignTarget(null, IdentifierReference(identifierName, decl.position), null, null, decl.position), - null, - value, - decl.position + val identifierName = listOf(decl.name) + val initvalue = VariableInitializationAssignment( + AssignTarget(null, + IdentifierReference(identifierName, decl.position), + null, null, decl.position), + null, value, decl.position + ) + val zero = decl.asDefaultValueDecl(decl).value!! + return listOf( + IAstModification.Insert(decl, initvalue, parent), + IAstModification.ReplaceExpr( + { newExpr -> decl.value = newExpr }, + zero, + decl + ) ) } - return decl + return emptyList() } - override fun visit(functionCall: FunctionCall): Expression { + override fun after(functionCall: FunctionCall, parent: Node): Iterable { + // insert AddressOf (&) expression where required (string params to a UWORD function param etc). var parentStatement: Node = functionCall while(parentStatement !is Statement) parentStatement = parentStatement.parent val targetStatement = functionCall.target.targetSubroutine(program.namespace) if(targetStatement!=null) { - addAddressOfExprIfNeeded(targetStatement, functionCall.args, parentStatement) + return addAddressOfExprIfNeeded(targetStatement, functionCall.args, parentStatement) } else { val builtinFunc = BuiltinFunctions[functionCall.target.nameInSource.joinToString (".")] if(builtinFunc!=null) - addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCall.args, parentStatement) + return addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCall.args, parentStatement) } - return functionCall + return emptyList() } - override fun visit(functionCallStatement: FunctionCallStatement): Statement { + override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable { + // insert AddressOf (&) expression where required (string params to a UWORD function param etc). val targetStatement = functionCallStatement.target.targetSubroutine(program.namespace) if(targetStatement!=null) { - addAddressOfExprIfNeeded(targetStatement, functionCallStatement.args, functionCallStatement) + return addAddressOfExprIfNeeded(targetStatement, functionCallStatement.args, functionCallStatement) } else { val builtinFunc = BuiltinFunctions[functionCallStatement.target.nameInSource.joinToString (".")] if(builtinFunc!=null) - addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCallStatement.args, functionCallStatement) + return addAddressOfExprIfNeededForBuiltinFuncs(builtinFunc, functionCallStatement.args, functionCallStatement) } - return functionCallStatement + return emptyList() } - private fun addAddressOfExprIfNeeded(subroutine: Subroutine, arglist: MutableList, parent: Statement) { + private fun addAddressOfExprIfNeeded(subroutine: Subroutine, arglist: MutableList, parent: Statement): Iterable { // functions that accept UWORD and are given an array type, or string, will receive the AddressOf (memory location) of that value instead. + val replacements = mutableListOf() for(argparam in subroutine.parameters.withIndex().zip(arglist)) { if(argparam.first.value.type==DataType.UWORD || argparam.first.value.type == DataType.STR) { if(argparam.second is AddressOf) continue val idref = argparam.second as? IdentifierReference - val strvalue = argparam.second as? StringLiteralValue if(idref!=null) { val variable = idref.targetVarDecl(program.namespace) if(variable!=null && variable.datatype in IterableDatatypes) { - val pointerExpr = AddressOf(idref, idref.position) - pointerExpr.linkParents(arglist[argparam.first.index].parent) - arglist[argparam.first.index] = pointerExpr + replacements += IAstModification.ReplaceExpr( + { newExpr -> arglist[argparam.first.index] = newExpr }, + AddressOf(idref, idref.position), + parent + ) } } - else if(strvalue!=null) { - // add a vardecl so that the autovar can be resolved in later lookups - val variable = VarDecl.createAuto(strvalue) - addVarDecl(strvalue.definingScope(), variable) - // replace the argument with &autovar - val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position) - val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position) - pointerExpr.linkParents(arglist[argparam.first.index].parent) - arglist[argparam.first.index] = pointerExpr - } } } + return replacements } - private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FSignature, args: MutableList, parent: Statement) { + private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FSignature, args: MutableList, parent: Statement): Iterable { // val paramTypesForAddressOf = PassByReferenceDatatypes + DataType.UWORD for(arg in args.withIndex().zip(signature.parameters)) { val argvalue = arg.first.value @@ -142,15 +125,6 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA addrOf.linkParents(parent) } } + return emptyList() } - - - private fun addVarDecl(scope: INameScope, variable: VarDecl) { - if(scope !in vardeclsToAdd) - vardeclsToAdd[scope] = mutableListOf() - val declList = vardeclsToAdd.getValue(scope) - if(declList.all{it.name!=variable.name}) - declList.add(variable) - } - } diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index cb768df7b..a893f850e 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -338,7 +338,7 @@ open class Assignment(var target: AssignTarget, val aug_op : String?, var value: } // This is a special class so the compiler can see if the assignments are for initializing the vars in the scope, -// or just a regular assignment. It may optimize the initialization step from this. +// or just a regular assignment. It could optimize the initialization step from this. class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, value: Expression, position: Position) : Assignment(target, aug_op, value, position) diff --git a/compiler/src/prog8/compiler/Main.kt b/compiler/src/prog8/compiler/Main.kt index ef8270855..cb193389b 100644 --- a/compiler/src/prog8/compiler/Main.kt +++ b/compiler/src/prog8/compiler/Main.kt @@ -81,6 +81,7 @@ fun compileProgram(filepath: Path, programAst.addTypecasts(errors) errors.handle() } + //println(" time3: $time3") val time4 = measureTimeMillis { programAst.checkValid(compilerOptions, errors) // check if tree is valid diff --git a/examples/test.p8 b/examples/test.p8 index d18d5a494..f98d35ff4 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -5,29 +5,27 @@ main { - struct Color { - uword red - uword green - uword blue + sub start() { + str meuk = "hello" + ubyte bb1 = 99 + ubyte key=c64.GETIN() + ubyte[] zzzz = [1,2,3] + + A = len(meuk) + A = msb(meuk) + ; A = strlen(meuk) + func(meuk, zzzz) + func(zzzz, "zzzz") + func("hello2", meuk) } - sub start() { - Color c = {1,2,3} - Color c2 = {3,4,5} - c=c2 - c64scr.print_uw(c.red) + sub func(uword addr1, uword addr2) { + c64scr.print_uwhex(addr1, 1) c64.CHROUT('\n') - c64scr.print_uw(c.green) + c64scr.print_uwhex(addr2, 1) c64.CHROUT('\n') - c64scr.print_uw(c.blue) - c64.CHROUT('\n') - c= {111,222,333} - c64scr.print_uw(c.red) - c64.CHROUT('\n') - c64scr.print_uw(c.green) - c64.CHROUT('\n') - c64scr.print_uw(c.blue) c64.CHROUT('\n') } + }