mirror of
https://github.com/irmen/prog8.git
synced 2025-08-05 06:28:20 +00:00
syntactic sugar: turned some functions into read only properties
This commit is contained in:
@@ -22,7 +22,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
// This allows you to restart the program and have the same starting values of the variables
|
||||
if(decl.allowInitializeWithZero)
|
||||
{
|
||||
val nextAssign = decl.definingScope().nextSibling(decl) as? Assignment
|
||||
val nextAssign = decl.definingScope.nextSibling(decl) as? Assignment
|
||||
if (nextAssign != null && nextAssign.target isSameAs IdentifierReference(listOf(decl.name), Position.DUMMY))
|
||||
decl.value = null
|
||||
else {
|
||||
@@ -51,14 +51,14 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
// use the other part of the expression to split.
|
||||
val assignRight = Assignment(assignment.target, binExpr.right, assignment.position)
|
||||
return listOf(
|
||||
IAstModification.InsertBefore(assignment, assignRight, assignment.definingScope()),
|
||||
IAstModification.InsertBefore(assignment, assignRight, assignment.definingScope),
|
||||
IAstModification.ReplaceNode(binExpr.right, binExpr.left, binExpr),
|
||||
IAstModification.ReplaceNode(binExpr.left, assignment.target.toExpression(), binExpr))
|
||||
}
|
||||
} else {
|
||||
val assignLeft = Assignment(assignment.target, binExpr.left, assignment.position)
|
||||
return listOf(
|
||||
IAstModification.InsertBefore(assignment, assignLeft, assignment.definingScope()),
|
||||
IAstModification.InsertBefore(assignment, assignLeft, assignment.definingScope),
|
||||
IAstModification.ReplaceNode(binExpr.left, assignment.target.toExpression(), binExpr))
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
val decls = scope.statements.filterIsInstance<VarDecl>().filter { it.type == VarDeclType.VAR }
|
||||
subroutineVariables.addAll(decls.map { it.name to it })
|
||||
|
||||
val sub = scope.definingSubroutine()
|
||||
val sub = scope.definingSubroutine
|
||||
if (sub != null) {
|
||||
// move any remaining vardecls of the scope into the upper scope. Make sure the position remains the same!
|
||||
val replacements = mutableListOf<IAstModification>()
|
||||
@@ -129,7 +129,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
}
|
||||
|
||||
// precede a subroutine with a return to avoid falling through into the subroutine from code above it
|
||||
val outerScope = subroutine.definingScope()
|
||||
val outerScope = subroutine.definingScope
|
||||
val outerStatements = outerScope.statements
|
||||
val subroutineStmtIdx = outerStatements.indexOf(subroutine)
|
||||
if (subroutineStmtIdx > 0
|
||||
@@ -339,14 +339,14 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: I
|
||||
|
||||
private fun getAutoIndexerVarFor(expr: ArrayIndexedExpression): MutableList<IAstModification> {
|
||||
val modifications = mutableListOf<IAstModification>()
|
||||
val statement = expr.containingStatement()
|
||||
val statement = expr.containingStatement
|
||||
val dt = expr.indexer.indexExpr.inferType(program)
|
||||
val register = if(dt.istype(DataType.UBYTE) || dt.istype(DataType.BYTE)) "r9L" else "r9"
|
||||
// replace the indexer with just the variable (simply use a cx16 virtual register r9, that we HOPE is not used for other things in the expression...)
|
||||
// assign the indexing expression to the helper variable, but only if that hasn't been done already
|
||||
val target = AssignTarget(IdentifierReference(listOf("cx16", register), expr.indexer.position), null, null, expr.indexer.position)
|
||||
val assign = Assignment(target, expr.indexer.indexExpr, expr.indexer.position)
|
||||
modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope()))
|
||||
modifications.add(IAstModification.InsertBefore(statement, assign, statement.definingScope))
|
||||
modifications.add(IAstModification.ReplaceNode(expr.indexer.indexExpr, target.identifier!!.copy(), expr.indexer))
|
||||
return modifications
|
||||
}
|
||||
|
@@ -63,7 +63,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(returnStmt: Return) {
|
||||
val expectedReturnValues = returnStmt.definingSubroutine()?.returntypes ?: emptyList()
|
||||
val expectedReturnValues = returnStmt.definingSubroutine?.returntypes ?: emptyList()
|
||||
if(expectedReturnValues.size>1) {
|
||||
throw FatalAstException("cannot use a return with one value in a subroutine that has multiple return values: $returnStmt")
|
||||
}
|
||||
@@ -87,7 +87,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(ifStatement: IfStatement) {
|
||||
if(!ifStatement.condition.inferType(program).isInteger())
|
||||
if(!ifStatement.condition.inferType(program).isInteger)
|
||||
errors.err("condition value should be an integer type", ifStatement.condition.position)
|
||||
super.visit(ifStatement)
|
||||
}
|
||||
@@ -388,13 +388,13 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(untilLoop: UntilLoop) {
|
||||
if(!untilLoop.condition.inferType(program).isInteger())
|
||||
if(!untilLoop.condition.inferType(program).isInteger)
|
||||
errors.err("condition value should be an integer type", untilLoop.condition.position)
|
||||
super.visit(untilLoop)
|
||||
}
|
||||
|
||||
override fun visit(whileLoop: WhileLoop) {
|
||||
if(!whileLoop.condition.inferType(program).isInteger())
|
||||
if(!whileLoop.condition.inferType(program).isInteger)
|
||||
errors.err("condition value should be an integer type", whileLoop.condition.position)
|
||||
super.visit(whileLoop)
|
||||
}
|
||||
@@ -423,7 +423,7 @@ internal class AstChecker(private val program: Program,
|
||||
val targetDt = assignment.target.inferType(program)
|
||||
val valueDt = assignment.value.inferType(program)
|
||||
if(valueDt.isKnown && !(valueDt isAssignableTo targetDt)) {
|
||||
if(targetDt.isIterable())
|
||||
if(targetDt.isIterable)
|
||||
errors.err("cannot assign value to string or array", assignment.value.position)
|
||||
else if(!(valueDt.istype(DataType.STR) && targetDt.istype(DataType.UWORD)))
|
||||
errors.err("type of value doesn't match target", assignment.value.position)
|
||||
@@ -726,7 +726,7 @@ internal class AstChecker(private val program: Program,
|
||||
var definingModule = directive.parent // TODO: why not just use directive.definingModule() here?
|
||||
while (definingModule !is Module)
|
||||
definingModule = definingModule.parent
|
||||
if (definingModule.isLibrary())
|
||||
if (definingModule.isLibrary)
|
||||
return
|
||||
|
||||
val s = definingModule.source?.pathString()
|
||||
@@ -1021,7 +1021,7 @@ internal class AstChecker(private val program: Program,
|
||||
errors.err("swap requires 2 variables, not constant value(s)", position)
|
||||
else if(args[0] isSameAs args[1])
|
||||
errors.err("swap should have 2 different args", position)
|
||||
else if(!dt1.isNumeric())
|
||||
else if(!dt1.isNumeric)
|
||||
errors.err("swap requires args of numerical type", position)
|
||||
}
|
||||
else if(target.name=="all" || target.name=="any") {
|
||||
@@ -1126,7 +1126,7 @@ internal class AstChecker(private val program: Program,
|
||||
}
|
||||
|
||||
override fun visit(whenStatement: WhenStatement) {
|
||||
if(!whenStatement.condition.inferType(program).isInteger())
|
||||
if(!whenStatement.condition.inferType(program).isInteger)
|
||||
errors.err("when condition must be an integer value", whenStatement.position)
|
||||
val tally = mutableSetOf<Int>()
|
||||
for((choices, choiceNode) in whenStatement.choiceValues(program)) {
|
||||
|
@@ -160,9 +160,9 @@ internal fun Program.moveMainAndStartToFirst() {
|
||||
// and finally the entrypoint subroutine "start" itself is moved to the top in that block.
|
||||
|
||||
val directives = modules[0].statements.filterIsInstance<Directive>()
|
||||
val start = this.entrypoint()
|
||||
val mod = start.definingModule()
|
||||
val block = start.definingBlock()
|
||||
val start = this.entrypoint
|
||||
val mod = start.definingModule
|
||||
val block = start.definingBlock
|
||||
moveModuleToFront(mod)
|
||||
mod.remove(block)
|
||||
var afterDirective = mod.statements.indexOfFirst { it !is Directive }
|
||||
|
@@ -46,10 +46,10 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
if (existing != null && existing !== decl)
|
||||
nameError(decl.name, decl.position, existing)
|
||||
|
||||
if(decl.definingBlock().name==decl.name)
|
||||
nameError(decl.name, decl.position, decl.definingBlock())
|
||||
if(decl.definingSubroutine()?.name==decl.name)
|
||||
nameError(decl.name, decl.position, decl.definingSubroutine()!!)
|
||||
if(decl.definingBlock.name==decl.name)
|
||||
nameError(decl.name, decl.position, decl.definingBlock)
|
||||
if(decl.definingSubroutine?.name==decl.name)
|
||||
nameError(decl.name, decl.position, decl.definingSubroutine!!)
|
||||
|
||||
super.visit(decl)
|
||||
}
|
||||
@@ -70,7 +70,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
nameError(subroutine.name, subroutine.position, existing)
|
||||
|
||||
// check that there are no local variables, labels, or other subs that redefine the subroutine's parameters. Blocks are okay.
|
||||
val symbolsInSub = subroutine.allDefinedSymbols()
|
||||
val symbolsInSub = subroutine.allDefinedSymbols
|
||||
val namesInSub = symbolsInSub.map{ it.first }.toSet()
|
||||
val paramNames = subroutine.parameters.map { it.name }.toSet()
|
||||
val paramsToCheck = paramNames.intersect(namesInSub)
|
||||
@@ -87,10 +87,10 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
errors.err("asmsub can only contain inline assembly (%asm)", subroutine.position)
|
||||
}
|
||||
|
||||
if(subroutine.name == subroutine.definingBlock().name) {
|
||||
if(subroutine.name == subroutine.definingBlock.name) {
|
||||
// subroutines cannot have the same name as their enclosing block,
|
||||
// because this causes symbol scoping issues in the resulting assembly source
|
||||
nameError(subroutine.name, subroutine.position, subroutine.definingBlock())
|
||||
nameError(subroutine.name, subroutine.position, subroutine.definingBlock)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
||||
// the builtin functions can't be redefined
|
||||
errors.err("builtin function cannot be redefined", label.position)
|
||||
} else {
|
||||
val existing = label.definingSubroutine()?.getAllLabels(label.name) ?: emptyList()
|
||||
val existing = label.definingSubroutine?.getAllLabels(label.name) ?: emptyList()
|
||||
for(el in existing) {
|
||||
if(el === label || el.name != label.name)
|
||||
continue
|
||||
|
@@ -17,7 +17,7 @@ internal class AstVariousTransforms(private val program: Program) : AstWalker()
|
||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||
// For non-kernal subroutines and non-asm parameters:
|
||||
// inject subroutine params as local variables (if they're not there yet).
|
||||
val symbolsInSub = subroutine.allDefinedSymbols()
|
||||
val symbolsInSub = subroutine.allDefinedSymbols
|
||||
val namesInSub = symbolsInSub.map{ it.first }.toSet()
|
||||
if(subroutine.asmAddress==null) {
|
||||
if(subroutine.asmParameterRegisters.isEmpty() && subroutine.parameters.isNotEmpty()) {
|
||||
|
@@ -44,7 +44,7 @@ internal class LiteralsToAutoVars(private val program: Program) : AstWalker() {
|
||||
val identifier = IdentifierReference(listOf(vardecl2.name), vardecl2.position)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(array, identifier, parent),
|
||||
IAstModification.InsertFirst(vardecl2, array.definingScope())
|
||||
IAstModification.InsertFirst(vardecl2, array.definingScope)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -190,7 +190,7 @@ internal class StatementReorderer(val program: Program, val errors: IErrorReport
|
||||
val valueType = assignment.value.inferType(program)
|
||||
val targetType = assignment.target.inferType(program)
|
||||
|
||||
if(targetType.isArray() && valueType.isArray() ) {
|
||||
if(targetType.isArray && valueType.isArray) {
|
||||
if (assignment.value is ArrayLiteralValue) {
|
||||
errors.err("cannot assign array literal here, use separate assignment per element", assignment.position)
|
||||
} else {
|
||||
|
@@ -25,7 +25,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
|
||||
if(!valueDt.istype(decl.datatype)) {
|
||||
|
||||
// don't add a typecast on an array initializer value
|
||||
if(valueDt.isInteger() && decl.datatype in ArrayDatatypes)
|
||||
if(valueDt.isInteger && decl.datatype in ArrayDatatypes)
|
||||
return noModifications
|
||||
|
||||
// don't add a typecast if the initializer value is inherently not assignable
|
||||
@@ -214,7 +214,7 @@ class TypecastsAdder(val program: Program, val errors: IErrorReporter) : AstWalk
|
||||
// add a typecast to the return type if it doesn't match the subroutine's signature
|
||||
val returnValue = returnStmt.value
|
||||
if(returnValue!=null) {
|
||||
val subroutine = returnStmt.definingSubroutine()!!
|
||||
val subroutine = returnStmt.definingSubroutine!!
|
||||
if(subroutine.returntypes.size==1) {
|
||||
val subReturnType = subroutine.returntypes.first()
|
||||
if (returnValue.inferType(program).istype(subReturnType))
|
||||
|
@@ -195,7 +195,7 @@ fun builtinFunctionReturnType(function: String, args: List<Expression>, program:
|
||||
return when (function) {
|
||||
"abs" -> {
|
||||
val dt = args.single().inferType(program)
|
||||
return if(dt.isNumeric())
|
||||
return if(dt.isNumeric)
|
||||
dt
|
||||
else
|
||||
InferredTypes.InferredType.unknown()
|
||||
@@ -300,7 +300,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
|
||||
?: throw CannotEvaluateException("sizeof", "no target")
|
||||
|
||||
return when {
|
||||
dt.isArray() -> {
|
||||
dt.isArray -> {
|
||||
val length = (target as VarDecl).arraysize!!.constIndex() ?: throw CannotEvaluateException("sizeof", "unknown array size")
|
||||
val elementDt = ArrayToElementTypes.getValue(dt.typeOrElse(DataType.UNDEFINED))
|
||||
numericLiteral(memsizer.memorySize(elementDt) * length, position)
|
||||
|
@@ -55,10 +55,10 @@ internal class AsmGen(private val program: Program,
|
||||
println("Generating assembly code... ")
|
||||
|
||||
header()
|
||||
val allBlocks = program.allBlocks()
|
||||
val allBlocks = program.allBlocks
|
||||
if(allBlocks.first().name != "main")
|
||||
throw AssemblyError("first block should be 'main'")
|
||||
for(b in program.allBlocks())
|
||||
for(b in program.allBlocks)
|
||||
block2asm(b)
|
||||
|
||||
for(removal in removals.toList()) {
|
||||
@@ -229,7 +229,7 @@ internal class AsmGen(private val program: Program,
|
||||
|
||||
private fun assignInitialValueToVar(decl: VarDecl, variableName: List<String>) {
|
||||
val asmName = asmVariableName(variableName)
|
||||
assignmentAsmGen.assignExpressionToVariable(decl.value!!, asmName, decl.datatype, decl.definingSubroutine())
|
||||
assignmentAsmGen.assignExpressionToVariable(decl.value!!, asmName, decl.datatype, decl.definingSubroutine)
|
||||
}
|
||||
|
||||
private var generatedLabelSequenceNumber: Int = 0
|
||||
@@ -502,8 +502,8 @@ internal class AsmGen(private val program: Program,
|
||||
return identifier.nameInSource.joinToString(".")
|
||||
|
||||
val target = identifier.targetStatement(program)!!
|
||||
val targetScope = target.definingSubroutine()
|
||||
val identScope = identifier.definingSubroutine()
|
||||
val targetScope = target.definingSubroutine
|
||||
val identScope = identifier.definingSubroutine
|
||||
return if(targetScope !== identScope) {
|
||||
val scopedName = getScopedSymbolNameForTarget(identifier.nameInSource.last(), target)
|
||||
if(target is Label) {
|
||||
@@ -896,10 +896,10 @@ internal class AsmGen(private val program: Program,
|
||||
memdefs2asm(sub.statements)
|
||||
|
||||
// the main.start subroutine is the program's entrypoint and should perform some initialization logic
|
||||
if(sub.name=="start" && sub.definingBlock().name=="main") {
|
||||
if(sub.name=="start" && sub.definingBlock.name=="main") {
|
||||
out("; program startup initialization")
|
||||
out(" cld")
|
||||
program.allBlocks().forEach {
|
||||
program.allBlocks.forEach {
|
||||
if(it.statements.filterIsInstance<VarDecl>().any { vd->vd.value!=null && vd.type==VarDeclType.VAR && vd.datatype in NumericDatatypes})
|
||||
out(" jsr ${it.name}.prog8_init_vars")
|
||||
}
|
||||
@@ -981,7 +981,7 @@ internal class AsmGen(private val program: Program,
|
||||
// if(!booleanCondition.left.isSimple || !booleanCondition.right.isSimple)
|
||||
// throw AssemblyError("both operands for if comparison expression should have been simplified")
|
||||
|
||||
if (stmt.elsepart.containsNoCodeNorVars()) {
|
||||
if (stmt.elsepart.containsNoCodeNorVars) {
|
||||
// empty else
|
||||
val endLabel = makeLabel("if_end")
|
||||
expressionsAsmGen.translateComparisonExpressionWithJumpIfFalse(booleanCondition, endLabel)
|
||||
@@ -1112,7 +1112,7 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
private fun createRepeatCounterVar(dt: DataType, constIterations: Int?, stmt: RepeatLoop): String {
|
||||
val asmInfo = stmt.definingSubroutine()!!.asmGenInfo
|
||||
val asmInfo = stmt.definingSubroutine!!.asmGenInfo
|
||||
var parent = stmt.parent
|
||||
while(parent !is ParentSentinel) {
|
||||
if(parent is RepeatLoop)
|
||||
@@ -1234,7 +1234,7 @@ $repeatLabel lda $counterVar
|
||||
}
|
||||
|
||||
private fun translate(stmt: BranchStatement) {
|
||||
if(stmt.truepart.containsNoCodeNorVars() && stmt.elsepart.containsCodeOrVars())
|
||||
if(stmt.truepart.containsNoCodeNorVars && stmt.elsepart.containsCodeOrVars)
|
||||
throw AssemblyError("only else part contains code, shoud have been switched already")
|
||||
|
||||
val jump = stmt.truepart.statements.first() as? Jump
|
||||
@@ -1246,7 +1246,7 @@ $repeatLabel lda $counterVar
|
||||
} else {
|
||||
val truePartIsJustBreak = stmt.truepart.statements.firstOrNull() is Break
|
||||
val elsePartIsJustBreak = stmt.elsepart.statements.firstOrNull() is Break
|
||||
if(stmt.elsepart.containsNoCodeNorVars()) {
|
||||
if(stmt.elsepart.containsNoCodeNorVars) {
|
||||
if(truePartIsJustBreak) {
|
||||
// branch with just a break (jump out of loop)
|
||||
val instruction = branchInstruction(stmt.condition, false)
|
||||
@@ -1290,8 +1290,8 @@ $repeatLabel lda $counterVar
|
||||
if(stmt.value!=null && stmt.type==VarDeclType.VAR && stmt.datatype in NumericDatatypes) {
|
||||
// generate an assignment statement to (re)initialize the variable's value.
|
||||
// if the vardecl is not in a subroutine however, we have to initialize it globally.
|
||||
if(stmt.definingSubroutine()==null) {
|
||||
val block = stmt.definingBlock()
|
||||
if(stmt.definingSubroutine ==null) {
|
||||
val block = stmt.definingBlock
|
||||
var inits = blockLevelVarInits[block]
|
||||
if(inits==null) {
|
||||
inits = mutableSetOf()
|
||||
@@ -1315,7 +1315,7 @@ $repeatLabel lda $counterVar
|
||||
"%asminclude" -> {
|
||||
// TODO: handle %asminclude with SourceCode
|
||||
val includedName = stmt.args[0].str!!
|
||||
val sourcePath = Path(stmt.definingModule().source!!.pathString()) // FIXME: %asminclude inside non-library, non-filesystem module
|
||||
val sourcePath = Path(stmt.definingModule.source!!.pathString()) // FIXME: %asminclude inside non-library, non-filesystem module
|
||||
val sourcecode = loadAsmIncludeFile(includedName, sourcePath)
|
||||
assemblyLines.add(sourcecode.trimEnd().trimStart('\n'))
|
||||
}
|
||||
@@ -1323,7 +1323,7 @@ $repeatLabel lda $counterVar
|
||||
val includedName = stmt.args[0].str!!
|
||||
val offset = if(stmt.args.size>1) ", ${stmt.args[1].int}" else ""
|
||||
val length = if(stmt.args.size>2) ", ${stmt.args[2].int}" else ""
|
||||
val sourcePath = Path(stmt.definingModule().source!!.pathString()) // FIXME: %asmbinary inside non-library, non-filesystem module
|
||||
val sourcePath = Path(stmt.definingModule.source!!.pathString()) // FIXME: %asmbinary inside non-library, non-filesystem module
|
||||
val includedPath = sourcePath.resolveSibling(includedName)
|
||||
val pathForAssembler = outputDir // #54: 64tass needs the path *relative to the .asm file*
|
||||
.absolute() // avoid IllegalArgumentExc due to non-absolute path .relativize(absolute path)
|
||||
@@ -1358,7 +1358,7 @@ $label nop""")
|
||||
|
||||
internal fun translate(ret: Return, withRts: Boolean=true) {
|
||||
ret.value?.let { returnvalue ->
|
||||
val sub = ret.definingSubroutine()!!
|
||||
val sub = ret.definingSubroutine!!
|
||||
val returnType = sub.returntypes.single()
|
||||
val returnReg = sub.asmReturnvaluesRegisters.single()
|
||||
if(returnReg.registerOrPair==null)
|
||||
|
@@ -34,7 +34,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
if(discardResult && resultToStack)
|
||||
throw AssemblyError("cannot both discard the result AND put it onto stack")
|
||||
|
||||
val sscope = (fcall as Node).definingSubroutine()
|
||||
val sscope = (fcall as Node).definingSubroutine
|
||||
|
||||
when (func.name) {
|
||||
"msb" -> funcMsb(fcall, resultToStack, resultRegister)
|
||||
@@ -195,13 +195,13 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
|
||||
asmgen.out(" cmp ${arg2.addressExpression.constValue(program)!!.number.toHex()}")
|
||||
} else {
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine)
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
|
||||
asmgen.out(" cmp P8ZP_SCRATCH_B1")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_B1", DataType.UBYTE, (fcall as Node).definingSubroutine)
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.A)
|
||||
asmgen.out(" cmp P8ZP_SCRATCH_B1")
|
||||
}
|
||||
@@ -229,7 +229,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
+""")
|
||||
}
|
||||
else -> {
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, (fcall as Node).definingSubroutine())
|
||||
asmgen.assignExpressionToVariable(arg2, "P8ZP_SCRATCH_W1", DataType.UWORD, (fcall as Node).definingSubroutine)
|
||||
asmgen.assignExpressionToRegister(arg1, RegisterOrPair.AY)
|
||||
asmgen.out("""
|
||||
cpy P8ZP_SCRATCH_W1+1
|
||||
@@ -426,7 +426,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression)
|
||||
if(ptrAndIndex!=null) {
|
||||
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as FunctionCallStatement).definingSubroutine()!!)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as FunctionCallStatement).definingSubroutine!!)
|
||||
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
asmgen.out("""
|
||||
@@ -527,7 +527,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
val ptrAndIndex = asmgen.pointerViaIndexRegisterPossible(what.addressExpression)
|
||||
if(ptrAndIndex!=null) {
|
||||
asmgen.assignExpressionToRegister(ptrAndIndex.second, RegisterOrPair.X)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as FunctionCallStatement).definingSubroutine()!!)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as FunctionCallStatement).definingSubroutine!!)
|
||||
asmgen.assignExpressionToRegister(ptrAndIndex.first, RegisterOrPair.AY)
|
||||
asmgen.restoreRegisterLocal(CpuRegister.X)
|
||||
asmgen.out("""
|
||||
@@ -851,9 +851,9 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
|
||||
fun targetFromExpr(expr: Expression, datatype: DataType): AsmAssignTarget {
|
||||
return when (expr) {
|
||||
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine(), variableAsmName = asmgen.asmVariableName(expr))
|
||||
is ArrayIndexedExpression -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, datatype, expr.definingSubroutine(), array = expr)
|
||||
is DirectMemoryRead -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, datatype, expr.definingSubroutine(), memory = DirectMemoryWrite(expr.addressExpression, expr.position))
|
||||
is IdentifierReference -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, datatype, expr.definingSubroutine, variableAsmName = asmgen.asmVariableName(expr))
|
||||
is ArrayIndexedExpression -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, datatype, expr.definingSubroutine, array = expr)
|
||||
is DirectMemoryRead -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, datatype, expr.definingSubroutine, memory = DirectMemoryWrite(expr.addressExpression, expr.position))
|
||||
else -> throw AssemblyError("invalid expression object $expr")
|
||||
}
|
||||
}
|
||||
@@ -1189,7 +1189,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
val varname = asmgen.asmVariableName(addrExpr)
|
||||
if(asmgen.isZpVar(addrExpr)) {
|
||||
// pointervar is already in the zero page, no need to copy
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine()!!)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
||||
if (asmgen.isTargetCpu(CpuType.CPU65c02)) {
|
||||
asmgen.out("""
|
||||
@@ -1214,7 +1214,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
val varname = asmgen.asmVariableName(addrExpr.left as IdentifierReference)
|
||||
if(asmgen.isZpVar(addrExpr.left as IdentifierReference)) {
|
||||
// pointervar is already in the zero page, no need to copy
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine()!!)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (fcall as Node).definingSubroutine!!)
|
||||
asmgen.assignExpressionToRegister(fcall.args[1], RegisterOrPair.AX)
|
||||
val index = (addrExpr.right as NumericLiteralValue).number.toHex()
|
||||
asmgen.out("""
|
||||
@@ -1366,7 +1366,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
|
||||
private fun funcMsb(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
val arg = fcall.args.single()
|
||||
if (!arg.inferType(program).isWords())
|
||||
if (!arg.inferType(program).isWords)
|
||||
throw AssemblyError("msb required word argument")
|
||||
if (arg is NumericLiteralValue)
|
||||
throw AssemblyError("msb(const) should have been const-folded away")
|
||||
@@ -1410,7 +1410,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
|
||||
|
||||
private fun funcLsb(fcall: IFunctionCall, resultToStack: Boolean, resultRegister: RegisterOrPair?) {
|
||||
val arg = fcall.args.single()
|
||||
if (!arg.inferType(program).isWords())
|
||||
if (!arg.inferType(program).isWords)
|
||||
throw AssemblyError("lsb required word argument")
|
||||
if (arg is NumericLiteralValue)
|
||||
throw AssemblyError("lsb(const) should have been const-folded away")
|
||||
|
@@ -197,7 +197,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
jsr floats.vars_less_f
|
||||
beq $jumpIfFalseLabel""")
|
||||
} else {
|
||||
val subroutine = left.definingSubroutine()!!
|
||||
val subroutine = left.definingSubroutine!!
|
||||
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
@@ -242,7 +242,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
jsr floats.vars_lesseq_f
|
||||
beq $jumpIfFalseLabel""")
|
||||
} else {
|
||||
val subroutine = left.definingSubroutine()!!
|
||||
val subroutine = left.definingSubroutine!!
|
||||
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
@@ -287,7 +287,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
jsr floats.vars_less_f
|
||||
beq $jumpIfFalseLabel""")
|
||||
} else {
|
||||
val subroutine = left.definingSubroutine()!!
|
||||
val subroutine = left.definingSubroutine!!
|
||||
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
@@ -332,7 +332,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
jsr floats.vars_lesseq_f
|
||||
beq $jumpIfFalseLabel""")
|
||||
} else {
|
||||
val subroutine = left.definingSubroutine()!!
|
||||
val subroutine = left.definingSubroutine!!
|
||||
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
@@ -1339,7 +1339,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
jsr floats.vars_equal_f
|
||||
beq $jumpIfFalseLabel""")
|
||||
} else {
|
||||
val subroutine = left.definingSubroutine()!!
|
||||
val subroutine = left.definingSubroutine!!
|
||||
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
@@ -1424,7 +1424,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
||||
jsr floats.vars_equal_f
|
||||
bne $jumpIfFalseLabel""")
|
||||
} else {
|
||||
val subroutine = left.definingSubroutine()!!
|
||||
val subroutine = left.definingSubroutine!!
|
||||
subroutine.asmGenInfo.usedFloatEvalResultVar1 = true
|
||||
asmgen.assignExpressionToVariable(right, subroutineFloatEvalResultVar1, DataType.FLOAT, subroutine)
|
||||
asmgen.assignExpressionToRegister(left, RegisterOrPair.FAC1)
|
||||
|
@@ -589,5 +589,5 @@ $loopLabel""")
|
||||
}
|
||||
|
||||
private fun assignLoopvar(stmt: ForLoop, range: RangeExpr) =
|
||||
asmgen.assignExpressionToVariable(range.from, asmgen.asmVariableName(stmt.loopVar), stmt.loopVarDt(program).typeOrElse(DataType.UNDEFINED), stmt.definingSubroutine())
|
||||
asmgen.assignExpressionToVariable(range.from, asmgen.asmVariableName(stmt.loopVar), stmt.loopVarDt(program).typeOrElse(DataType.UNDEFINED), stmt.definingSubroutine)
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
||||
if(regSaveOnStack)
|
||||
asmgen.saveRegisterStack(CpuRegister.X, keepAonEntry)
|
||||
else
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (stmt as Node).definingSubroutine()!!)
|
||||
asmgen.saveRegisterLocal(CpuRegister.X, (stmt as Node).definingSubroutine!!)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@ internal class PostIncrDecrAsmGen(private val program: Program, private val asmg
|
||||
val targetIdent = stmt.target.identifier
|
||||
val targetMemory = stmt.target.memoryAddress
|
||||
val targetArrayIdx = stmt.target.arrayindexed
|
||||
val scope = stmt.definingSubroutine()
|
||||
val scope = stmt.definingSubroutine
|
||||
when {
|
||||
targetIdent!=null -> {
|
||||
val what = asmgen.asmVariableName(targetIdent)
|
||||
|
@@ -61,9 +61,9 @@ internal class AsmAssignTarget(val kind: TargetStorageKind,
|
||||
throw AssemblyError("unknown dt")
|
||||
val dt = idt.typeOrElse(DataType.UNDEFINED)
|
||||
when {
|
||||
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine(), variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
|
||||
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine(), array = arrayindexed, origAstTarget = this)
|
||||
memoryAddress != null -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine(), memory = memoryAddress, origAstTarget = this)
|
||||
identifier != null -> AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, dt, assign.definingSubroutine, variableAsmName = asmgen.asmVariableName(identifier!!), origAstTarget = this)
|
||||
arrayindexed != null -> AsmAssignTarget(TargetStorageKind.ARRAY, program, asmgen, dt, assign.definingSubroutine, array = arrayindexed, origAstTarget = this)
|
||||
memoryAddress != null -> AsmAssignTarget(TargetStorageKind.MEMORY, program, asmgen, dt, assign.definingSubroutine, memory = memoryAddress, origAstTarget = this)
|
||||
else -> throw AssemblyError("weird target")
|
||||
}
|
||||
}
|
||||
|
@@ -27,30 +27,30 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
}
|
||||
|
||||
private val usedSubroutines: Set<Subroutine> by lazy {
|
||||
calledBy.keys + program.entrypoint()
|
||||
calledBy.keys + program.entrypoint
|
||||
}
|
||||
|
||||
private val usedBlocks: Set<Block> by lazy {
|
||||
val blocksFromSubroutines = usedSubroutines.map { it.definingBlock() }
|
||||
val blocksFromLibraries = program.allBlocks().filter { it.isInLibrary }
|
||||
val blocksFromSubroutines = usedSubroutines.map { it.definingBlock }
|
||||
val blocksFromLibraries = program.allBlocks.filter { it.isInLibrary }
|
||||
val used = mutableSetOf<Block>()
|
||||
|
||||
allIdentifiersAndTargets.forEach {
|
||||
if(it.key.first.definingBlock() in blocksFromSubroutines) {
|
||||
val target = it.value.definingBlock()
|
||||
if(it.key.first.definingBlock in blocksFromSubroutines) {
|
||||
val target = it.value.definingBlock
|
||||
used.add(target)
|
||||
}
|
||||
}
|
||||
|
||||
used + blocksFromLibraries + program.entrypoint().definingBlock()
|
||||
used + blocksFromLibraries + program.entrypoint.definingBlock
|
||||
}
|
||||
|
||||
private val usedModules: Set<Module> by lazy {
|
||||
usedBlocks.map { it.definingModule() }.toSet()
|
||||
usedBlocks.map { it.definingModule }.toSet()
|
||||
}
|
||||
|
||||
override fun visit(directive: Directive) {
|
||||
val thisModule = directive.definingModule()
|
||||
val thisModule = directive.definingModule
|
||||
if (directive.directive == "%import") {
|
||||
val importedModule: Module = program.modules.single { it.name == directive.args[0].name }
|
||||
imports[thisModule] = imports.getValue(thisModule) + importedModule
|
||||
@@ -63,7 +63,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
override fun visit(functionCall: FunctionCall) {
|
||||
val otherSub = functionCall.target.targetSubroutine(program)
|
||||
if (otherSub != null) {
|
||||
functionCall.definingSubroutine()?.let { thisSub ->
|
||||
functionCall.definingSubroutine?.let { thisSub ->
|
||||
calls[thisSub] = calls.getValue(thisSub) + otherSub
|
||||
calledBy[otherSub] = calledBy.getValue(otherSub) + functionCall
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
override fun visit(functionCallStatement: FunctionCallStatement) {
|
||||
val otherSub = functionCallStatement.target.targetSubroutine(program)
|
||||
if (otherSub != null) {
|
||||
functionCallStatement.definingSubroutine()?.let { thisSub ->
|
||||
functionCallStatement.definingSubroutine?.let { thisSub ->
|
||||
calls[thisSub] = calls.getValue(thisSub) + otherSub
|
||||
calledBy[otherSub] = calledBy.getValue(otherSub) + functionCallStatement
|
||||
}
|
||||
@@ -85,7 +85,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
override fun visit(addressOf: AddressOf) {
|
||||
val otherSub = addressOf.identifier.targetSubroutine(program)
|
||||
if(otherSub!=null) {
|
||||
addressOf.definingSubroutine()?.let { thisSub ->
|
||||
addressOf.definingSubroutine?.let { thisSub ->
|
||||
calls[thisSub] = calls.getValue(thisSub) + otherSub
|
||||
calledBy[otherSub] = calledBy.getValue(otherSub) + thisSub
|
||||
}
|
||||
@@ -96,7 +96,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
override fun visit(jump: Jump) {
|
||||
val otherSub = jump.identifier?.targetSubroutine(program)
|
||||
if (otherSub != null) {
|
||||
jump.definingSubroutine()?.let { thisSub ->
|
||||
jump.definingSubroutine?.let { thisSub ->
|
||||
calls[thisSub] = calls.getValue(thisSub) + otherSub
|
||||
calledBy[otherSub] = calledBy.getValue(otherSub) + jump
|
||||
}
|
||||
@@ -177,7 +177,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
|
||||
if(decl.type!=VarDeclType.VAR || decl.autogeneratedDontRemove || decl.sharedWithAsm)
|
||||
return false
|
||||
|
||||
if(decl.definingBlock() !in usedBlocks)
|
||||
if(decl.definingBlock !in usedBlocks)
|
||||
return false
|
||||
|
||||
val allReferencedVardecls = allIdentifiersAndTargets.filter { it.value is VarDecl }.map { it.value }.toSet()
|
||||
|
@@ -33,7 +33,7 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat
|
||||
|
||||
// move vardecl to the containing subroutine and add initialization assignment in its place if needed
|
||||
if(decl.type == VarDeclType.VAR && decl.datatype in NumericDatatypes) {
|
||||
val subroutine = decl.definingSubroutine() as? INameScope
|
||||
val subroutine = decl.definingSubroutine as? INameScope
|
||||
if(subroutine!=null && subroutine!==parent) {
|
||||
val declValue = decl.value
|
||||
decl.value = null
|
||||
@@ -62,21 +62,21 @@ internal class VarConstantValueTypeAdjuster(private val program: Program, privat
|
||||
val step = range.step.constValue(program)?.number?.toDouble()
|
||||
|
||||
if(from==null) {
|
||||
if(!range.from.inferType(program).isInteger())
|
||||
if(!range.from.inferType(program).isInteger)
|
||||
errors.err("range expression from value must be integer", range.from.position)
|
||||
} else if(from-from.toInt()>0) {
|
||||
errors.err("range expression from value must be integer", range.from.position)
|
||||
}
|
||||
|
||||
if(to==null) {
|
||||
if(!range.to.inferType(program).isInteger())
|
||||
if(!range.to.inferType(program).isInteger)
|
||||
errors.err("range expression to value must be integer", range.to.position)
|
||||
} else if(to-to.toInt()>0) {
|
||||
errors.err("range expression to value must be integer", range.to.position)
|
||||
}
|
||||
|
||||
if(step==null) {
|
||||
if(!range.step.inferType(program).isInteger())
|
||||
if(!range.step.inferType(program).isInteger)
|
||||
errors.err("range expression step value must be integer", range.step.position)
|
||||
} else if(step-step.toInt()>0) {
|
||||
errors.err("range expression step value must be integer", range.step.position)
|
||||
|
@@ -590,14 +590,14 @@ internal class ExpressionSimplifier(private val program: Program) : AstWalker()
|
||||
return expr2.left
|
||||
}
|
||||
in powersOfTwo -> {
|
||||
if (leftValue.inferType(program).isInteger()) {
|
||||
if (leftValue.inferType(program).isInteger) {
|
||||
// times a power of two => shift left
|
||||
val numshifts = log2(cv).toInt()
|
||||
return BinaryExpression(expr2.left, "<<", NumericLiteralValue.optimalInteger(numshifts, expr.position), expr.position)
|
||||
}
|
||||
}
|
||||
in negativePowersOfTwo -> {
|
||||
if (leftValue.inferType(program).isInteger()) {
|
||||
if (leftValue.inferType(program).isInteger) {
|
||||
// times a negative power of two => negate, then shift left
|
||||
val numshifts = log2(-cv).toInt()
|
||||
return BinaryExpression(PrefixExpression("-", expr2.left, expr.position), "<<", NumericLiteralValue.optimalInteger(numshifts, expr.position), expr.position)
|
||||
|
@@ -79,7 +79,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
val functionName = functionCallStatement.target.nameInSource[0]
|
||||
if (functionName in functions.purefunctionNames) {
|
||||
errors.warn("statement has no effect (function return value is discarded)", functionCallStatement.position)
|
||||
return listOf(IAstModification.Remove(functionCallStatement, functionCallStatement.definingScope()))
|
||||
return listOf(IAstModification.Remove(functionCallStatement, functionCallStatement.definingScope))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
if(subroutine!=null) {
|
||||
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
|
||||
if(first is Return)
|
||||
return listOf(IAstModification.Remove(functionCallStatement, functionCallStatement.definingScope()))
|
||||
return listOf(IAstModification.Remove(functionCallStatement, functionCallStatement.definingScope))
|
||||
}
|
||||
|
||||
return noModifications
|
||||
@@ -152,11 +152,11 @@ internal class StatementOptimizer(private val program: Program,
|
||||
|
||||
override fun after(ifStatement: IfStatement, parent: Node): Iterable<IAstModification> {
|
||||
// remove empty if statements
|
||||
if(ifStatement.truepart.containsNoCodeNorVars() && ifStatement.elsepart.containsNoCodeNorVars())
|
||||
return listOf(IAstModification.Remove(ifStatement, ifStatement.definingScope()))
|
||||
if(ifStatement.truepart.containsNoCodeNorVars && ifStatement.elsepart.containsNoCodeNorVars)
|
||||
return listOf(IAstModification.Remove(ifStatement, ifStatement.definingScope))
|
||||
|
||||
// empty true part? switch with the else part
|
||||
if(ifStatement.truepart.containsNoCodeNorVars() && ifStatement.elsepart.containsCodeOrVars()) {
|
||||
if(ifStatement.truepart.containsNoCodeNorVars && ifStatement.elsepart.containsCodeOrVars) {
|
||||
val invertedCondition = PrefixExpression("not", ifStatement.condition, ifStatement.condition.position)
|
||||
val emptyscope = AnonymousScope(mutableListOf(), ifStatement.elsepart.position)
|
||||
val truepart = AnonymousScope(ifStatement.elsepart.statements, ifStatement.truepart.position)
|
||||
@@ -184,14 +184,14 @@ internal class StatementOptimizer(private val program: Program,
|
||||
}
|
||||
|
||||
override fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> {
|
||||
if(forLoop.body.containsNoCodeNorVars()) {
|
||||
if(forLoop.body.containsNoCodeNorVars) {
|
||||
errors.warn("removing empty for loop", forLoop.position)
|
||||
return listOf(IAstModification.Remove(forLoop, forLoop.definingScope()))
|
||||
return listOf(IAstModification.Remove(forLoop, forLoop.definingScope))
|
||||
} else if(forLoop.body.statements.size==1) {
|
||||
val loopvar = forLoop.body.statements[0] as? VarDecl
|
||||
if(loopvar!=null && loopvar.name==forLoop.loopVar.nameInSource.singleOrNull()) {
|
||||
// remove empty for loop (only loopvar decl in it)
|
||||
return listOf(IAstModification.Remove(forLoop, forLoop.definingScope()))
|
||||
return listOf(IAstModification.Remove(forLoop, forLoop.definingScope))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
} else {
|
||||
// always false -> remove the while statement altogether
|
||||
errors.warn("condition is always false", whileLoop.condition.position)
|
||||
listOf(IAstModification.Remove(whileLoop, whileLoop.definingScope()))
|
||||
listOf(IAstModification.Remove(whileLoop, whileLoop.definingScope))
|
||||
}
|
||||
}
|
||||
return noModifications
|
||||
@@ -277,14 +277,14 @@ internal class StatementOptimizer(private val program: Program,
|
||||
override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
|
||||
val iter = repeatLoop.iterations
|
||||
if(iter!=null) {
|
||||
if(repeatLoop.body.containsNoCodeNorVars()) {
|
||||
if(repeatLoop.body.containsNoCodeNorVars) {
|
||||
errors.warn("empty loop removed", repeatLoop.position)
|
||||
return listOf(IAstModification.Remove(repeatLoop, repeatLoop.definingScope()))
|
||||
return listOf(IAstModification.Remove(repeatLoop, repeatLoop.definingScope))
|
||||
}
|
||||
val iterations = iter.constValue(program)?.number?.toInt()
|
||||
if (iterations == 0) {
|
||||
errors.warn("iterations is always 0, removed loop", iter.position)
|
||||
return listOf(IAstModification.Remove(repeatLoop, repeatLoop.definingScope()))
|
||||
return listOf(IAstModification.Remove(repeatLoop, repeatLoop.definingScope))
|
||||
}
|
||||
if (iterations == 1) {
|
||||
errors.warn("iterations is always 1", iter.position)
|
||||
@@ -296,10 +296,10 @@ internal class StatementOptimizer(private val program: Program,
|
||||
|
||||
override fun after(jump: Jump, parent: Node): Iterable<IAstModification> {
|
||||
// if the jump is to the next statement, remove the jump
|
||||
val scope = jump.definingScope()
|
||||
val scope = jump.definingScope
|
||||
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()))
|
||||
return listOf(IAstModification.Remove(jump, jump.definingScope))
|
||||
|
||||
return noModifications
|
||||
}
|
||||
@@ -332,7 +332,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(binExpr, expr2, binExpr.parent),
|
||||
IAstModification.InsertAfter(assignment, addConstant, assignment.definingScope()))
|
||||
IAstModification.InsertAfter(assignment, addConstant, assignment.definingScope))
|
||||
} else if (op2 == "-") {
|
||||
// A = A +/- B - N
|
||||
val expr2 = BinaryExpression(binExpr.left, binExpr.operator, rExpr.left, binExpr.position)
|
||||
@@ -343,7 +343,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
)
|
||||
return listOf(
|
||||
IAstModification.ReplaceNode(binExpr, expr2, binExpr.parent),
|
||||
IAstModification.InsertAfter(assignment, subConstant, assignment.definingScope()))
|
||||
IAstModification.InsertAfter(assignment, subConstant, assignment.definingScope))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
override fun after(assignment: Assignment, parent: Node): Iterable<IAstModification> {
|
||||
if(assignment.target isSameAs assignment.value) {
|
||||
// remove assignment to self
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
}
|
||||
|
||||
val targetIDt = assignment.target.inferType(program)
|
||||
@@ -385,7 +385,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
when (bexpr.operator) {
|
||||
"+" -> {
|
||||
if (rightCv == 0.0) {
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
} else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) {
|
||||
if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) {
|
||||
// replace by several INCs if it's not a memory address (inc on a memory mapped register doesn't work very well)
|
||||
@@ -399,7 +399,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
}
|
||||
"-" -> {
|
||||
if (rightCv == 0.0) {
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
} else if (targetDt in IntegerDatatypes && floor(rightCv) == rightCv) {
|
||||
if (vardeclDt != VarDeclType.MEMORY && rightCv in 1.0..4.0) {
|
||||
// replace by several DECs if it's not a memory address (dec on a memory mapped register doesn't work very well)
|
||||
@@ -411,18 +411,18 @@ internal class StatementOptimizer(private val program: Program,
|
||||
}
|
||||
}
|
||||
}
|
||||
"*" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
"/" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
"**" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
"|" -> if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
"^" -> if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
"*" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
"/" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
"**" -> if (rightCv == 1.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
"|" -> if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
"^" -> if (rightCv == 0.0) return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
"<<" -> {
|
||||
if (rightCv == 0.0)
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
}
|
||||
">>" -> {
|
||||
if (rightCv == 0.0)
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope()))
|
||||
return listOf(IAstModification.Remove(assignment, assignment.definingScope))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,7 +434,7 @@ internal class StatementOptimizer(private val program: Program,
|
||||
|
||||
override fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> {
|
||||
fun returnViaIntermediaryVar(value: Expression): Iterable<IAstModification>? {
|
||||
val subr = returnStmt.definingSubroutine()!!
|
||||
val subr = returnStmt.definingSubroutine!!
|
||||
val returnDt = subr.returntypes.single()
|
||||
if (returnDt in IntegerDatatypes) {
|
||||
// first assign to intermediary variable, then return that
|
||||
|
@@ -20,8 +20,8 @@ internal class UnusedCodeRemover(private val program: Program,
|
||||
private val callgraph = CallGraph(program)
|
||||
|
||||
override fun before(module: Module, parent: Node): Iterable<IAstModification> {
|
||||
return if (!module.isLibrary() && (module.containsNoCodeNorVars() || callgraph.unused(module)))
|
||||
listOf(IAstModification.Remove(module, module.definingScope()))
|
||||
return if (!module.isLibrary && (module.containsNoCodeNorVars || callgraph.unused(module)))
|
||||
listOf(IAstModification.Remove(module, module.definingScope))
|
||||
else
|
||||
noModifications
|
||||
}
|
||||
@@ -61,7 +61,7 @@ internal class UnusedCodeRemover(private val program: Program,
|
||||
|
||||
override fun after(block: Block, parent: Node): Iterable<IAstModification> {
|
||||
if("force_output" !in block.options()) {
|
||||
if (block.containsNoCodeNorVars()) {
|
||||
if (block.containsNoCodeNorVars) {
|
||||
if(block.name != internedStringsModuleName)
|
||||
errors.warn("removing unused block '${block.name}'", block.position)
|
||||
return listOf(IAstModification.Remove(block, parent as INameScope))
|
||||
@@ -77,20 +77,20 @@ internal class UnusedCodeRemover(private val program: Program,
|
||||
}
|
||||
|
||||
override fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> {
|
||||
val forceOutput = "force_output" in subroutine.definingBlock().options()
|
||||
if (subroutine !== program.entrypoint() && !forceOutput && !subroutine.inline && !subroutine.isAsmSubroutine) {
|
||||
val forceOutput = "force_output" in subroutine.definingBlock.options()
|
||||
if (subroutine !== program.entrypoint && !forceOutput && !subroutine.inline && !subroutine.isAsmSubroutine) {
|
||||
if(callgraph.unused(subroutine)) {
|
||||
if(!subroutine.definingModule().isLibrary())
|
||||
if(!subroutine.definingModule.isLibrary)
|
||||
errors.warn("removing unused subroutine '${subroutine.name}'", subroutine.position)
|
||||
return listOf(IAstModification.Remove(subroutine, subroutine.definingScope()))
|
||||
return listOf(IAstModification.Remove(subroutine, subroutine.definingScope))
|
||||
}
|
||||
if(subroutine.containsNoCodeNorVars()) {
|
||||
if(!subroutine.definingModule().isLibrary())
|
||||
if(subroutine.containsNoCodeNorVars) {
|
||||
if(!subroutine.definingModule.isLibrary)
|
||||
errors.warn("removing empty subroutine '${subroutine.name}'", subroutine.position)
|
||||
val removals = mutableListOf(IAstModification.Remove(subroutine, subroutine.definingScope()))
|
||||
val removals = mutableListOf(IAstModification.Remove(subroutine, subroutine.definingScope))
|
||||
callgraph.calledBy[subroutine]?.let {
|
||||
for(node in it)
|
||||
removals.add(IAstModification.Remove(node, node.definingScope()))
|
||||
removals.add(IAstModification.Remove(node, node.definingScope))
|
||||
}
|
||||
return removals
|
||||
}
|
||||
@@ -102,11 +102,11 @@ internal class UnusedCodeRemover(private val program: Program,
|
||||
|
||||
override fun after(decl: VarDecl, parent: Node): Iterable<IAstModification> {
|
||||
if(decl.type==VarDeclType.VAR) {
|
||||
val forceOutput = "force_output" in decl.definingBlock().options()
|
||||
if (!forceOutput && !decl.autogeneratedDontRemove && !decl.sharedWithAsm && !decl.definingBlock().isInLibrary) {
|
||||
val forceOutput = "force_output" in decl.definingBlock.options()
|
||||
if (!forceOutput && !decl.autogeneratedDontRemove && !decl.sharedWithAsm && !decl.definingBlock.isInLibrary) {
|
||||
if (callgraph.unused(decl)) {
|
||||
errors.warn("removing unused variable '${decl.name}'", decl.position)
|
||||
return listOf(IAstModification.Remove(decl, decl.definingScope()))
|
||||
return listOf(IAstModification.Remove(decl, decl.definingScope))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -98,7 +98,7 @@ locallabel:
|
||||
fun testSymbolNameFromVarIdentifier() {
|
||||
val program = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program)
|
||||
val sub = program.entrypoint()
|
||||
val sub = program.entrypoint
|
||||
|
||||
// local variable
|
||||
val localvarIdent = sub.statements.filterIsInstance<Assignment>().first { it.value is IdentifierReference }.value as IdentifierReference
|
||||
@@ -122,7 +122,7 @@ locallabel:
|
||||
fun testSymbolNameFromLabelIdentifier() {
|
||||
val program = createTestProgram()
|
||||
val asmgen = createTestAsmGen(program)
|
||||
val sub = program.entrypoint()
|
||||
val sub = program.entrypoint
|
||||
|
||||
// local label
|
||||
val localLabelIdent = (sub.statements.filterIsInstance<Assignment>().first { (it.value as? AddressOf)?.identifier?.nameInSource==listOf("locallabel") }.value as AddressOf).identifier
|
||||
|
@@ -37,7 +37,7 @@ class TestCompilerOnCharLit {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val funCall = startSub.statements.filterIsInstance<IFunctionCall>()[0]
|
||||
|
||||
assertIs<NumericLiteralValue>(funCall.args[0],
|
||||
@@ -61,7 +61,7 @@ class TestCompilerOnCharLit {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val funCall = startSub.statements.filterIsInstance<IFunctionCall>()[0]
|
||||
|
||||
assertIs<IdentifierReference>(funCall.args[0])
|
||||
@@ -96,7 +96,7 @@ class TestCompilerOnCharLit {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val funCall = startSub.statements.filterIsInstance<IFunctionCall>()[0]
|
||||
|
||||
// Now, both is ok for the arg: a) still the IdRef or b) replaced by numeric literal
|
||||
|
@@ -40,7 +40,7 @@ class TestCompilerOnImportsAndIncludes {
|
||||
.assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val strLits = startSub.statements
|
||||
.filterIsInstance<FunctionCallStatement>()
|
||||
.map { it.args[0] as IdentifierReference }
|
||||
@@ -48,8 +48,8 @@ class TestCompilerOnImportsAndIncludes {
|
||||
|
||||
assertEquals("main.bar", strLits[0].value)
|
||||
assertEquals("foo.bar", strLits[1].value)
|
||||
assertEquals("main", strLits[0].definingScope().name)
|
||||
assertEquals("foo", strLits[1].definingScope().name)
|
||||
assertEquals("main", strLits[0].definingScope.name)
|
||||
assertEquals("foo", strLits[1].definingScope.name)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -63,7 +63,7 @@ class TestCompilerOnImportsAndIncludes {
|
||||
.assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val strLits = startSub.statements
|
||||
.filterIsInstance<FunctionCallStatement>()
|
||||
.map { it.args[0] as IdentifierReference }
|
||||
@@ -71,8 +71,8 @@ class TestCompilerOnImportsAndIncludes {
|
||||
|
||||
assertEquals("main.bar", strLits[0].value)
|
||||
assertEquals("foo.bar", strLits[1].value)
|
||||
assertEquals("main", strLits[0].definingScope().name)
|
||||
assertEquals("foo", strLits[1].definingScope().name)
|
||||
assertEquals("main", strLits[0].definingScope.name)
|
||||
assertEquals("foo", strLits[1].definingScope.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,19 +88,19 @@ class TestCompilerOnImportsAndIncludes {
|
||||
.assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val args = startSub.statements
|
||||
.filterIsInstance<FunctionCallStatement>()
|
||||
.map { it.args[0] }
|
||||
|
||||
val str0 = (args[0] as IdentifierReference).targetVarDecl(program)!!.value as StringLiteralValue
|
||||
assertEquals("main.bar", str0.value)
|
||||
assertEquals("main", str0.definingScope().name)
|
||||
assertEquals("main", str0.definingScope.name)
|
||||
|
||||
val id1 = (args[1] as AddressOf).identifier
|
||||
val lbl1 = id1.targetStatement(program) as Label
|
||||
assertEquals("foo_bar", lbl1.name)
|
||||
assertEquals("start", lbl1.definingScope().name)
|
||||
assertEquals("start", lbl1.definingScope.name)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@ class TestCompilerOnRanges {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val decl = startSub
|
||||
.statements.filterIsInstance<VarDecl>()[0]
|
||||
val rhsValues = (decl.value as ArrayLiteralValue)
|
||||
@@ -69,7 +69,7 @@ class TestCompilerOnRanges {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val decl = startSub
|
||||
.statements.filterIsInstance<VarDecl>()[0]
|
||||
val rhsValues = (decl.value as ArrayLiteralValue)
|
||||
@@ -151,7 +151,7 @@ class TestCompilerOnRanges {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val iterable = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }[0]
|
||||
@@ -182,7 +182,7 @@ class TestCompilerOnRanges {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val rangeExpr = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
@@ -209,7 +209,7 @@ class TestCompilerOnRanges {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val rangeExpr = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
@@ -250,7 +250,7 @@ class TestCompilerOnRanges {
|
||||
""").assertSuccess()
|
||||
|
||||
val program = result.programAst
|
||||
val startSub = program.entrypoint()
|
||||
val startSub = program.entrypoint
|
||||
val iterable = startSub
|
||||
.statements.filterIsInstance<ForLoop>()
|
||||
.map { it.iterable }
|
||||
|
@@ -29,7 +29,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
||||
}
|
||||
|
||||
override fun visit(module: Module) {
|
||||
if(!module.isLibrary()) {
|
||||
if(!module.isLibrary) {
|
||||
outputln("; ----------- module: ${module.name} -----------")
|
||||
super.visit(module)
|
||||
}
|
||||
@@ -98,7 +98,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
||||
override fun visit(decl: VarDecl) {
|
||||
|
||||
// if the vardecl is a parameter of a subroutine, don't output it again
|
||||
val paramNames = (decl.definingScope() as? Subroutine)?.parameters?.map { it.name }
|
||||
val paramNames = (decl.definingScope as? Subroutine)?.parameters?.map { it.name }
|
||||
if(paramNames!=null && decl.name in paramNames)
|
||||
return
|
||||
|
||||
|
@@ -36,11 +36,11 @@ interface INameScope {
|
||||
is WhileLoop -> if(stmt.body.name==name) return stmt.body
|
||||
is BranchStatement -> {
|
||||
if(stmt.truepart.name==name) return stmt.truepart
|
||||
if(stmt.elsepart.containsCodeOrVars() && stmt.elsepart.name==name) return stmt.elsepart
|
||||
if(stmt.elsepart.containsCodeOrVars && stmt.elsepart.name==name) return stmt.elsepart
|
||||
}
|
||||
is IfStatement -> {
|
||||
if(stmt.truepart.name==name) return stmt.truepart
|
||||
if(stmt.elsepart.containsCodeOrVars() && stmt.elsepart.name==name) return stmt.elsepart
|
||||
if(stmt.elsepart.containsCodeOrVars && stmt.elsepart.name==name) return stmt.elsepart
|
||||
}
|
||||
is WhenStatement -> {
|
||||
val scope = stmt.choices.firstOrNull { it.statements.name==name }
|
||||
@@ -69,23 +69,24 @@ interface INameScope {
|
||||
return null
|
||||
}
|
||||
|
||||
fun allDefinedSymbols(): List<Pair<String, Statement>> {
|
||||
return statements.mapNotNull {
|
||||
when (it) {
|
||||
is Label -> it.name to it
|
||||
is VarDecl -> it.name to it
|
||||
is Subroutine -> it.name to it
|
||||
is Block -> it.name to it
|
||||
else -> null
|
||||
val allDefinedSymbols: List<Pair<String, Statement>>
|
||||
get() {
|
||||
return statements.mapNotNull {
|
||||
when (it) {
|
||||
is Label -> it.name to it
|
||||
is VarDecl -> it.name to it
|
||||
is Subroutine -> it.name to it
|
||||
is Block -> it.name to it
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun lookup(scopedName: List<String>, localContext: Node) : Statement? {
|
||||
if(scopedName.size>1) {
|
||||
// a scoped name refers to a name in another module.
|
||||
// it's a qualified name, look it up from the root of the module's namespace (consider all modules in the program)
|
||||
for(module in localContext.definingModule().program.modules) {
|
||||
for(module in localContext.definingModule.program.modules) {
|
||||
var scope: INameScope? = module
|
||||
for(name in scopedName.dropLast(1)) {
|
||||
scope = scope?.subScope(name)
|
||||
@@ -112,7 +113,7 @@ interface INameScope {
|
||||
// find the scope the localContext is in, look in that first
|
||||
var statementScope = localContext
|
||||
while(statementScope !is ParentSentinel) {
|
||||
val localScope = statementScope.definingScope()
|
||||
val localScope = statementScope.definingScope
|
||||
val result = localScope.getLabelOrVariable(scopedName[0])
|
||||
if (result != null)
|
||||
return result
|
||||
@@ -126,8 +127,8 @@ interface INameScope {
|
||||
}
|
||||
}
|
||||
|
||||
fun containsCodeOrVars() = statements.any { it !is Directive || it.directive == "%asminclude" || it.directive == "%asm"}
|
||||
fun containsNoCodeNorVars() = !containsCodeOrVars()
|
||||
val containsCodeOrVars get() = statements.any { it !is Directive || it.directive == "%asminclude" || it.directive == "%asm" }
|
||||
val containsNoCodeNorVars get() = !containsCodeOrVars
|
||||
|
||||
fun remove(stmt: Statement) {
|
||||
if(!statements.remove(stmt))
|
||||
@@ -190,38 +191,42 @@ interface Node {
|
||||
var parent: Node // will be linked correctly later (late init)
|
||||
fun linkParents(parent: Node)
|
||||
|
||||
fun definingModule(): Module {
|
||||
if(this is Module)
|
||||
return this
|
||||
return findParentNode<Module>(this)!!
|
||||
}
|
||||
|
||||
fun definingSubroutine(): Subroutine? = findParentNode<Subroutine>(this)
|
||||
|
||||
fun definingScope(): INameScope {
|
||||
val scope = findParentNode<INameScope>(this)
|
||||
if(scope!=null) {
|
||||
return scope
|
||||
val definingModule: Module
|
||||
get() {
|
||||
if (this is Module)
|
||||
return this
|
||||
return findParentNode<Module>(this)!!
|
||||
}
|
||||
if(this is Label && this.name.startsWith("builtin::")) {
|
||||
return BuiltinFunctionScopePlaceholder
|
||||
|
||||
val definingSubroutine: Subroutine? get() = findParentNode<Subroutine>(this)
|
||||
|
||||
val definingScope: INameScope
|
||||
get() {
|
||||
val scope = findParentNode<INameScope>(this)
|
||||
if (scope != null) {
|
||||
return scope
|
||||
}
|
||||
if (this is Label && this.name.startsWith("builtin::")) {
|
||||
return BuiltinFunctionScopePlaceholder
|
||||
}
|
||||
if (this is GlobalNamespace)
|
||||
return this
|
||||
throw FatalAstException("scope missing from $this")
|
||||
}
|
||||
if(this is GlobalNamespace)
|
||||
return this
|
||||
throw FatalAstException("scope missing from $this")
|
||||
}
|
||||
|
||||
fun definingBlock(): Block {
|
||||
if(this is Block)
|
||||
return this
|
||||
return findParentNode<Block>(this)!!
|
||||
}
|
||||
val definingBlock: Block
|
||||
get() {
|
||||
if (this is Block)
|
||||
return this
|
||||
return findParentNode<Block>(this)!!
|
||||
}
|
||||
|
||||
fun containingStatement(): Statement {
|
||||
if(this is Statement)
|
||||
return this
|
||||
return findParentNode<Statement>(this)!!
|
||||
}
|
||||
val containingStatement: Statement
|
||||
get() {
|
||||
if (this is Statement)
|
||||
return this
|
||||
return findParentNode<Statement>(this)!!
|
||||
}
|
||||
|
||||
fun replaceChildNode(node: Node, replacement: Node)
|
||||
}
|
||||
@@ -265,16 +270,18 @@ class Program(val name: String,
|
||||
return this
|
||||
}
|
||||
|
||||
fun allBlocks(): List<Block> = modules.flatMap { it.statements.filterIsInstance<Block>() }
|
||||
val allBlocks: List<Block>
|
||||
get() = modules.flatMap { it.statements.filterIsInstance<Block>() }
|
||||
|
||||
fun entrypoint(): Subroutine {
|
||||
val mainBlocks = allBlocks().filter { it.name=="main" }
|
||||
return when (mainBlocks.size) {
|
||||
0 -> throw FatalAstException("no 'main' block")
|
||||
1 -> mainBlocks[0].subScope("start") as Subroutine
|
||||
else -> throw FatalAstException("more than one 'main' block")
|
||||
val entrypoint: Subroutine
|
||||
get() {
|
||||
val mainBlocks = allBlocks.filter { it.name == "main" }
|
||||
return when (mainBlocks.size) {
|
||||
0 -> throw FatalAstException("no 'main' block")
|
||||
1 -> mainBlocks[0].subScope("start") as Subroutine
|
||||
else -> throw FatalAstException("more than one 'main' block")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val mainModule: Module // TODO: rename Program.mainModule - it's NOT necessarily the one containing the main *block*!
|
||||
get() = modules.first { it.name!=internedStringsModuleName }
|
||||
@@ -356,7 +363,8 @@ open class Module(override val name: String,
|
||||
statements.forEach {it.linkParents(this)}
|
||||
}
|
||||
|
||||
override fun definingScope(): INameScope = program.namespace
|
||||
override val definingScope: INameScope
|
||||
get() = program.namespace
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
require(node is Statement && replacement is Statement)
|
||||
val idx = statements.indexOfFirst { it===node }
|
||||
@@ -364,12 +372,12 @@ open class Module(override val name: String,
|
||||
replacement.parent = this
|
||||
}
|
||||
|
||||
override fun toString() = "Module(name=$name, pos=$position, lib=${isLibrary()})"
|
||||
override fun toString() = "Module(name=$name, pos=$position, lib=${isLibrary})"
|
||||
|
||||
fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||
fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||
|
||||
fun isLibrary() = (source == null) || source.isFromResources
|
||||
val isLibrary get() = (source == null) || source.isFromResources
|
||||
}
|
||||
|
||||
|
||||
@@ -403,7 +411,7 @@ class GlobalNamespace(val modules: Iterable<Module>, private val builtinFunction
|
||||
}
|
||||
|
||||
// lookup something from the module.
|
||||
return when (val stmt = localContext.definingModule().lookup(scopedName, localContext)) {
|
||||
return when (val stmt = localContext.definingModule.lookup(scopedName, localContext)) {
|
||||
is Label, is VarDecl, is Block, is Subroutine -> stmt
|
||||
null -> null
|
||||
else -> throw SyntaxError("invalid identifier target type", stmt.position)
|
||||
|
@@ -610,7 +610,7 @@ class ArrayLiteralValue(val type: InferredTypes.InferredType, // inferred be
|
||||
if(forloop != null) {
|
||||
val loopvarDt = forloop.loopVarDt(program)
|
||||
if(loopvarDt.isKnown) {
|
||||
return if(!loopvarDt.isArrayElement())
|
||||
return if(!loopvarDt.isArrayElement)
|
||||
InferredTypes.InferredType.unknown()
|
||||
else
|
||||
InferredTypes.InferredType.known(ElementToArrayTypes.getValue(loopvarDt.typeOrElse(DataType.UNDEFINED)))
|
||||
@@ -781,7 +781,7 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
|
||||
if(decl == null || !decl.autogeneratedDontRemove)
|
||||
return false
|
||||
|
||||
val scope=decl.definingModule()
|
||||
val scope=decl.definingModule
|
||||
return scope.name==internedStringsModuleName
|
||||
}
|
||||
}
|
||||
|
@@ -43,16 +43,16 @@ object InferredTypes {
|
||||
infix fun isNotAssignableTo(targetDt: InferredType): Boolean = !this.isAssignableTo(targetDt)
|
||||
infix fun isNotAssignableTo(targetDt: DataType): Boolean = !this.isAssignableTo(targetDt)
|
||||
|
||||
fun isBytes() = datatype in ByteDatatypes
|
||||
fun isWords() = datatype in WordDatatypes
|
||||
fun isInteger() = datatype in IntegerDatatypes
|
||||
fun isNumeric() = datatype in NumericDatatypes
|
||||
fun isArray() = datatype in ArrayDatatypes
|
||||
fun isString() = datatype in StringlyDatatypes
|
||||
fun isIterable() = datatype in IterableDatatypes
|
||||
fun isPassByReference() = datatype in PassByReferenceDatatypes
|
||||
fun isPassByValue() = datatype in PassByValueDatatypes
|
||||
fun isArrayElement() = datatype in ElementToArrayTypes
|
||||
val isBytes get() = datatype in ByteDatatypes
|
||||
val isWords get() = datatype in WordDatatypes
|
||||
val isInteger get() = datatype in IntegerDatatypes
|
||||
val isNumeric get() = datatype in NumericDatatypes
|
||||
val isArray get() = datatype in ArrayDatatypes
|
||||
val isString get() = datatype in StringlyDatatypes
|
||||
val isIterable get() = datatype in IterableDatatypes
|
||||
val isPassByReference get() = datatype in PassByReferenceDatatypes
|
||||
val isPassByValue get() = datatype in PassByValueDatatypes
|
||||
val isArrayElement get() = datatype in ElementToArrayTypes
|
||||
}
|
||||
|
||||
private val unknownInstance = InferredType.unknown()
|
||||
|
@@ -39,7 +39,8 @@ class BuiltinFunctionStatementPlaceholder(val name: String, override val positio
|
||||
override fun linkParents(parent: Node) {}
|
||||
override fun accept(visitor: IAstVisitor) = throw FatalAstException("should not iterate over this node")
|
||||
override fun accept(visitor: AstWalker, parent: Node) = throw FatalAstException("should not iterate over this node")
|
||||
override fun definingScope(): INameScope = BuiltinFunctionScopePlaceholder
|
||||
override val definingScope: INameScope
|
||||
get() = BuiltinFunctionScopePlaceholder
|
||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||
replacement.parent = this
|
||||
}
|
||||
|
@@ -37,7 +37,7 @@ object Prog8Parser {
|
||||
// .linkParents called in ParsedModule.add
|
||||
parseTree.directive().forEach { module.add(it.toAst()) }
|
||||
// TODO: remove Encoding
|
||||
parseTree.block().forEach { module.add(it.toAst(module.isLibrary())) }
|
||||
parseTree.block().forEach { module.add(it.toAst(module.isLibrary)) }
|
||||
|
||||
return module
|
||||
}
|
||||
|
Reference in New Issue
Block a user