new var init values

This commit is contained in:
Irmen de Jong 2020-03-21 13:22:04 +01:00
parent 21dbc6da97
commit 824f06e17f
6 changed files with 82 additions and 96 deletions

View File

@ -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)

View File

@ -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")
}
}
}
}

View File

@ -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<INameScope, MutableList<VarDecl>>()
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<IAstModification> {
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<IAstModification> {
// 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<IAstModification> {
// 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<Expression>, parent: Statement) {
private fun addAddressOfExprIfNeeded(subroutine: Subroutine, arglist: MutableList<Expression>, parent: Statement): Iterable<IAstModification> {
// 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<IAstModification>()
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<Expression>, parent: Statement) {
private fun addAddressOfExprIfNeededForBuiltinFuncs(signature: FSignature, args: MutableList<Expression>, parent: Statement): Iterable<IAstModification> {
// 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)
}
}

View File

@ -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)

View File

@ -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

View File

@ -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')
}
}