syntactic sugar: turned some functions into read only properties

This commit is contained in:
Irmen de Jong
2021-10-11 00:01:26 +02:00
parent 3557d38ce0
commit 5db0408b9f
31 changed files with 234 additions and 225 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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