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() {
|
internal fun Program.reorderStatements() {
|
||||||
val initvalueCreator = VarInitValueAndAddressOfCreator(this)
|
val initvalueCreator = VarInitValueCreator(this)
|
||||||
initvalueCreator.visit(this)
|
initvalueCreator.visit(this)
|
||||||
|
initvalueCreator.applyModifications()
|
||||||
|
|
||||||
val checker = StatementReorderer(this)
|
val checker = StatementReorderer(this)
|
||||||
checker.visit(this)
|
checker.visit(this)
|
||||||
|
@ -41,6 +41,18 @@ interface IAstModification {
|
|||||||
newExpr.linkParents(parent)
|
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
|
package prog8.ast.processing
|
||||||
|
|
||||||
import prog8.ast.INameScope
|
|
||||||
import prog8.ast.Module
|
|
||||||
import prog8.ast.Node
|
import prog8.ast.Node
|
||||||
import prog8.ast.Program
|
import prog8.ast.Program
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
@ -12,124 +10,109 @@ import prog8.functions.BuiltinFunctions
|
|||||||
import prog8.functions.FSignature
|
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:
|
// For VarDecls that declare an initialization value:
|
||||||
// Replace the vardecl with an assignment (to set the initial value),
|
// add an assignment to set this initial value explicitly.
|
||||||
// and add a new vardecl with the default constant value of that type (usually zero) to the scope.
|
|
||||||
// This makes sure the variables get reset to the intended value on a next run of the program.
|
// 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).
|
// 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 after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
if(decl.isArray && decl.value==null) {
|
if(decl.isArray && decl.value==null) {
|
||||||
// array datatype without initialization value, add list of zeros
|
// array datatype without initialization value, add list of zeros
|
||||||
val arraysize = decl.arraysize!!.size()!!
|
val arraysize = decl.arraysize!!.size()!!
|
||||||
val array = ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype),
|
val zero = decl.asDefaultValueDecl(decl).value!!
|
||||||
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
|
return listOf(IAstModification.ReplaceExpr(
|
||||||
decl.position)
|
{ newExpr -> decl.value = newExpr },
|
||||||
decl.value = array
|
ArrayLiteralValue(InferredTypes.InferredType.known(decl.datatype),
|
||||||
|
Array(arraysize) { zero },
|
||||||
|
decl.position),
|
||||||
|
decl
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
if(decl.type!= VarDeclType.VAR || decl.value==null)
|
if(decl.type == VarDeclType.VAR && decl.value != null && decl.datatype in NumericDatatypes) {
|
||||||
return decl
|
|
||||||
|
|
||||||
if(decl.datatype in NumericDatatypes) {
|
|
||||||
val scope = decl.definingScope()
|
|
||||||
addVarDecl(scope, decl.asDefaultValueDecl(null))
|
|
||||||
val declvalue = decl.value!!
|
val declvalue = decl.value!!
|
||||||
val value =
|
val value =
|
||||||
if(declvalue is NumericLiteralValue)
|
if(declvalue is NumericLiteralValue)
|
||||||
declvalue.cast(decl.datatype)
|
declvalue.cast(decl.datatype)
|
||||||
else
|
else
|
||||||
declvalue
|
declvalue
|
||||||
val identifierName = listOf(decl.name) // this was: (scoped name) decl.scopedname.split(".")
|
val identifierName = listOf(decl.name)
|
||||||
return VariableInitializationAssignment(
|
val initvalue = VariableInitializationAssignment(
|
||||||
AssignTarget(null, IdentifierReference(identifierName, decl.position), null, null, decl.position),
|
AssignTarget(null,
|
||||||
null,
|
IdentifierReference(identifierName, decl.position),
|
||||||
value,
|
null, null, decl.position),
|
||||||
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
|
var parentStatement: Node = functionCall
|
||||||
while(parentStatement !is Statement)
|
while(parentStatement !is Statement)
|
||||||
parentStatement = parentStatement.parent
|
parentStatement = parentStatement.parent
|
||||||
val targetStatement = functionCall.target.targetSubroutine(program.namespace)
|
val targetStatement = functionCall.target.targetSubroutine(program.namespace)
|
||||||
if(targetStatement!=null) {
|
if(targetStatement!=null) {
|
||||||
addAddressOfExprIfNeeded(targetStatement, functionCall.args, parentStatement)
|
return addAddressOfExprIfNeeded(targetStatement, functionCall.args, parentStatement)
|
||||||
} else {
|
} else {
|
||||||
val builtinFunc = BuiltinFunctions[functionCall.target.nameInSource.joinToString (".")]
|
val builtinFunc = BuiltinFunctions[functionCall.target.nameInSource.joinToString (".")]
|
||||||
if(builtinFunc!=null)
|
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)
|
val targetStatement = functionCallStatement.target.targetSubroutine(program.namespace)
|
||||||
if(targetStatement!=null) {
|
if(targetStatement!=null) {
|
||||||
addAddressOfExprIfNeeded(targetStatement, functionCallStatement.args, functionCallStatement)
|
return addAddressOfExprIfNeeded(targetStatement, functionCallStatement.args, functionCallStatement)
|
||||||
} else {
|
} else {
|
||||||
val builtinFunc = BuiltinFunctions[functionCallStatement.target.nameInSource.joinToString (".")]
|
val builtinFunc = BuiltinFunctions[functionCallStatement.target.nameInSource.joinToString (".")]
|
||||||
if(builtinFunc!=null)
|
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.
|
// 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)) {
|
for(argparam in subroutine.parameters.withIndex().zip(arglist)) {
|
||||||
if(argparam.first.value.type==DataType.UWORD || argparam.first.value.type == DataType.STR) {
|
if(argparam.first.value.type==DataType.UWORD || argparam.first.value.type == DataType.STR) {
|
||||||
if(argparam.second is AddressOf)
|
if(argparam.second is AddressOf)
|
||||||
continue
|
continue
|
||||||
val idref = argparam.second as? IdentifierReference
|
val idref = argparam.second as? IdentifierReference
|
||||||
val strvalue = argparam.second as? StringLiteralValue
|
|
||||||
if(idref!=null) {
|
if(idref!=null) {
|
||||||
val variable = idref.targetVarDecl(program.namespace)
|
val variable = idref.targetVarDecl(program.namespace)
|
||||||
if(variable!=null && variable.datatype in IterableDatatypes) {
|
if(variable!=null && variable.datatype in IterableDatatypes) {
|
||||||
val pointerExpr = AddressOf(idref, idref.position)
|
replacements += IAstModification.ReplaceExpr(
|
||||||
pointerExpr.linkParents(arglist[argparam.first.index].parent)
|
{ newExpr -> arglist[argparam.first.index] = newExpr },
|
||||||
arglist[argparam.first.index] = pointerExpr
|
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
|
// val paramTypesForAddressOf = PassByReferenceDatatypes + DataType.UWORD
|
||||||
for(arg in args.withIndex().zip(signature.parameters)) {
|
for(arg in args.withIndex().zip(signature.parameters)) {
|
||||||
val argvalue = arg.first.value
|
val argvalue = arg.first.value
|
||||||
@ -142,15 +125,6 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
|
|||||||
addrOf.linkParents(parent)
|
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,
|
// 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)
|
class VariableInitializationAssignment(target: AssignTarget, aug_op: String?, value: Expression, position: Position)
|
||||||
: Assignment(target, aug_op, value, position)
|
: Assignment(target, aug_op, value, position)
|
||||||
|
|
||||||
|
@ -81,6 +81,7 @@ fun compileProgram(filepath: Path,
|
|||||||
programAst.addTypecasts(errors)
|
programAst.addTypecasts(errors)
|
||||||
errors.handle()
|
errors.handle()
|
||||||
}
|
}
|
||||||
|
|
||||||
//println(" time3: $time3")
|
//println(" time3: $time3")
|
||||||
val time4 = measureTimeMillis {
|
val time4 = measureTimeMillis {
|
||||||
programAst.checkValid(compilerOptions, errors) // check if tree is valid
|
programAst.checkValid(compilerOptions, errors) // check if tree is valid
|
||||||
|
@ -5,29 +5,27 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
struct Color {
|
sub start() {
|
||||||
uword red
|
str meuk = "hello"
|
||||||
uword green
|
ubyte bb1 = 99
|
||||||
uword blue
|
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() {
|
sub func(uword addr1, uword addr2) {
|
||||||
Color c = {1,2,3}
|
c64scr.print_uwhex(addr1, 1)
|
||||||
Color c2 = {3,4,5}
|
|
||||||
c=c2
|
|
||||||
c64scr.print_uw(c.red)
|
|
||||||
c64.CHROUT('\n')
|
c64.CHROUT('\n')
|
||||||
c64scr.print_uw(c.green)
|
c64scr.print_uwhex(addr2, 1)
|
||||||
c64.CHROUT('\n')
|
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')
|
c64.CHROUT('\n')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user