mirror of
https://github.com/irmen/prog8.git
synced 2024-10-19 07:23:56 +00:00
new var init values
This commit is contained in:
parent
21dbc6da97
commit
824f06e17f
@ -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)
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user