diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index e27d32721..5f4e9944f 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -35,7 +35,7 @@ fun main(args: Array) { compileMain(args) } -fun printSoftwareHeader(what: String) { +internal fun printSoftwareHeader(what: String) { val buildVersion = object {}.javaClass.getResource("/version.txt").readText().trim() println("\nProg8 $what v$buildVersion by Irmen de Jong (irmen@razorvine.net)") println("This software is licensed under the GNU GPL 3.0, see https://www.gnu.org/licenses/gpl.html\n") @@ -190,7 +190,7 @@ private fun compileMain(args: Array) { } -fun determineCompilationOptions(program: Program): CompilationOptions { +private fun determineCompilationOptions(program: Program): CompilationOptions { val mainModule = program.modules.first() val outputType = (mainModule.statements.singleOrNull { it is Directive && it.directive == "%output" } as? Directive)?.args?.single()?.name?.toUpperCase() diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 61eedd084..a8b491e61 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -848,6 +848,60 @@ data class AssignTarget(val register: Register?, fun isMemoryMapped(namespace: INameScope): Boolean = memoryAddress!=null || (identifier?.targetVarDecl(namespace)?.type==VarDeclType.MEMORY) + + fun isSameAs(value: IExpression): Boolean { + return when { + this.memoryAddress!=null -> false + this.register!=null -> value is RegisterExpr && value.register==this.register + this.identifier!=null -> value is IdentifierReference && value.nameInSource==this.identifier.nameInSource + this.arrayindexed!=null -> value is ArrayIndexedExpression && + value.identifier.nameInSource==this.arrayindexed.identifier.nameInSource && + value.arrayspec.size()!=null && + this.arrayindexed.arrayspec.size()!=null && + value.arrayspec.size()==this.arrayindexed.arrayspec.size() + else -> false + } + } + + fun isSameAs(other: AssignTarget, program: Program): Boolean { + if(this===other) + return true + if(this.register!=null && other.register!=null) + return this.register==other.register + if(this.identifier!=null && other.identifier!=null) + return this.identifier.nameInSource==other.identifier.nameInSource + if(this.memoryAddress!=null && other.memoryAddress!=null) { + val addr1 = this.memoryAddress!!.addressExpression.constValue(program) + val addr2 = other.memoryAddress!!.addressExpression.constValue(program) + return addr1!=null && addr2!=null && addr1==addr2 + } + if(this.arrayindexed!=null && other.arrayindexed!=null) { + if(this.arrayindexed.identifier.nameInSource == other.arrayindexed.identifier.nameInSource) { + val x1 = this.arrayindexed.arrayspec.index.constValue(program) + val x2 = other.arrayindexed.arrayspec.index.constValue(program) + return x1!=null && x2!=null && x1==x2 + } + } + return false + } + + fun isNotMemory(namespace: INameScope): Boolean { + if(this.register!=null) + return true + if(this.memoryAddress!=null) + return false + if(this.arrayindexed!=null) { + val targetStmt = this.arrayindexed.identifier.targetVarDecl(namespace) + if(targetStmt!=null) + return targetStmt.type!=VarDeclType.MEMORY + } + if(this.identifier!=null) { + val targetStmt = this.identifier.targetVarDecl(namespace) + if(targetStmt!=null) + return targetStmt.type!=VarDeclType.MEMORY + } + return false + } } @@ -857,6 +911,29 @@ interface IExpression: Node { fun process(processor: IAstProcessor): IExpression fun referencesIdentifier(name: String): Boolean fun resultingDatatype(program: Program): DataType? + + fun same(other: IExpression): Boolean { + if(this===other) + return true + when(this) { + is RegisterExpr -> + return (other is RegisterExpr && other.register==this.register) + is IdentifierReference -> + return (other is IdentifierReference && other.nameInSource==this.nameInSource) + is PrefixExpression -> + return (other is PrefixExpression && other.operator==this.operator && other.expression.same(this.expression)) + is BinaryExpression -> + return (other is BinaryExpression && other.operator==this.operator + && other.left.same(this.left) + && other.right.same(this.right)) + is ArrayIndexedExpression -> { + return (other is ArrayIndexedExpression && other.identifier.nameInSource == this.identifier.nameInSource + && other.arrayspec.index.same(this.arrayspec.index)) + } + is LiteralValue -> return (other is LiteralValue && other==this) + } + return false + } } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 16d7c2b05..e14e853f3 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -5,7 +5,6 @@ import prog8.compiler.HeapValues import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE import prog8.functions.BuiltinFunctions -import prog8.optimizing.same import prog8.parser.ParsingFailedError import java.io.File @@ -13,7 +12,7 @@ import java.io.File * General checks on the Ast */ -fun Program.checkValid(compilerOptions: CompilationOptions) { +internal fun Program.checkValid(compilerOptions: CompilationOptions) { val checker = AstChecker(this, compilerOptions) checker.process(this) printErrors(checker.result(), name) @@ -269,9 +268,9 @@ private class AstChecker(private val program: Program, if(subroutine.isAsmSubroutine) { if(subroutine.asmParameterRegisters.size != subroutine.parameters.size) - err("number of asm parameter registers is not the same as number of parameters") + err("number of asm parameter registers is not the isSameAs as number of parameters") if(subroutine.asmReturnvaluesRegisters.size != subroutine.returntypes.size) - err("number of return registers is not the same as number of return values") + err("number of return registers is not the isSameAs as number of return values") for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) { if(param.second.registerOrPair in setOf(RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y)) { if (param.first.type != DataType.UBYTE && param.first.type != DataType.BYTE) @@ -845,7 +844,7 @@ private class AstChecker(private val program: Program, checkResult.add(ExpressionError("swap requires 2 args of identical type", position)) else if (args[0].constValue(program) != null || args[1].constValue(program) != null) checkResult.add(ExpressionError("swap requires 2 variables, not constant value(s)", position)) - else if(same(args[0], args[1])) + else if(args[0].same(args[1])) checkResult.add(ExpressionError("swap should have 2 different args", position)) else if(dt1 !in NumericDatatypes) checkResult.add(ExpressionError("swap requires args of numerical type", position)) diff --git a/compiler/src/prog8/ast/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/AstIdentifiersChecker.kt index 0be53576c..cbdd0cab3 100644 --- a/compiler/src/prog8/ast/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/AstIdentifiersChecker.kt @@ -8,7 +8,7 @@ import prog8.functions.BuiltinFunctions * Finally, it also makes sure the datatype of all Var decls and sub Return values is set correctly. */ -fun Program.checkIdentifiers() { +internal fun Program.checkIdentifiers() { val checker = AstIdentifiersChecker(namespace) checker.process(this) @@ -53,7 +53,7 @@ private class AstIdentifiersChecker(private val namespace: INameScope) : IAstPro private var blocks: MutableMap = mutableMapOf() - fun result(): List { + internal fun result(): List { return checkResult } diff --git a/compiler/src/prog8/ast/AstRecursionChecker.kt b/compiler/src/prog8/ast/AstRecursionChecker.kt index e6f210883..a27616568 100644 --- a/compiler/src/prog8/ast/AstRecursionChecker.kt +++ b/compiler/src/prog8/ast/AstRecursionChecker.kt @@ -4,7 +4,7 @@ package prog8.ast * Checks for the occurrence of recursive subroutine calls */ -fun Program.checkRecursion() { +internal fun Program.checkRecursion() { val checker = AstRecursionChecker(namespace) checker.process(this) printErrors(checker.result(), name) @@ -84,7 +84,7 @@ private class DirectedGraph { private class AstRecursionChecker(private val namespace: INameScope) : IAstProcessor { private val callGraph = DirectedGraph() - fun result(): List { + internal fun result(): List { val cycle = callGraph.checkForCycle() if(cycle.isEmpty()) return emptyList() diff --git a/compiler/src/prog8/ast/ImportedAstChecker.kt b/compiler/src/prog8/ast/ImportedAstChecker.kt index cf196667d..0d8f10099 100644 --- a/compiler/src/prog8/ast/ImportedAstChecker.kt +++ b/compiler/src/prog8/ast/ImportedAstChecker.kt @@ -5,7 +5,7 @@ package prog8.ast * Checks that are specific for imported modules. */ -fun Module.checkImportedValid() { +internal fun Module.checkImportedValid() { this.linkParents() val checker = ImportedAstChecker() checker.process(this) @@ -16,7 +16,7 @@ fun Module.checkImportedValid() { private class ImportedAstChecker : IAstProcessor { private val checkResult: MutableList = mutableListOf() - fun result(): List { + internal fun result(): List { return checkResult } diff --git a/compiler/src/prog8/ast/StmtReorderer.kt b/compiler/src/prog8/ast/StmtReorderer.kt index 73541344c..4471c21a9 100644 --- a/compiler/src/prog8/ast/StmtReorderer.kt +++ b/compiler/src/prog8/ast/StmtReorderer.kt @@ -1,6 +1,6 @@ package prog8.ast -fun Program.reorderStatements() { +internal fun Program.reorderStatements() { val initvalueCreator = VarInitValueAndAddressOfCreator(namespace) initvalueCreator.process(this) @@ -8,7 +8,7 @@ fun Program.reorderStatements() { checker.process(this) } -const val initvarsSubName="prog8_init_vars" // the name of the subroutine that should be called for every block to initialize its variables +internal const val initvarsSubName="prog8_init_vars" // the name of the subroutine that should be called for every block to initialize its variables private class StatementReorderer(private val program: Program): IAstProcessor { @@ -167,7 +167,7 @@ private class StatementReorderer(private val program: Program): IAstProcessor { } private fun sortConstantAssignments(statements: MutableList) { - // sort assignments by datatype and value, so multiple initializations with the same value can be optimized (to load the value just once) + // sort assignments by datatype and value, so multiple initializations with the isSameAs value can be optimized (to load the value just once) val result = mutableListOf() val stmtIter = statements.iterator() for(stmt in stmtIter) { diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 2d30dc37f..556465f3d 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -7,7 +7,6 @@ import prog8.compiler.intermediate.Opcode import prog8.compiler.intermediate.Value import prog8.compiler.intermediate.branchOpcodes import prog8.functions.BuiltinFunctions -import prog8.optimizing.same import prog8.parser.tryGetEmbeddedResource import prog8.stackvm.Syscall import java.io.File @@ -68,7 +67,7 @@ class HeapValues { if (str.length > 255) throw IllegalArgumentException("string length must be 0-255") - // strings are 'interned' and shared if they're the same + // strings are 'interned' and shared if they're the isSameAs val value = HeapValue(type, str, null, null) val existing = heap.filter { it.value==value }.map { it.key }.firstOrNull() @@ -147,10 +146,7 @@ data class CompilationOptions(val output: OutputType, internal class Compiler(private val program: Program): IAstProcessor { - val prog: IntermediateProgram = IntermediateProgram(program.name, program.loadAddress, program.heap, program.modules.first().source) - val namespace = program.namespace - val heap = program.heap - + private val prog: IntermediateProgram = IntermediateProgram(program.name, program.loadAddress, program.heap, program.modules.first().source) private var generatedLabelSequenceNumber = 0 private val breakStmtLabelStack : Stack = Stack() private val continueStmtLabelStack : Stack = Stack() @@ -644,7 +640,7 @@ internal class Compiler(private val program: Program): IAstProcessor { translateBinaryOperator(expr.operator, commonDt) } is FunctionCall -> { - val target = expr.target.targetStatement(namespace) + val target = expr.target.targetStatement(program.namespace) if(target is BuiltinFunctionStatementPlaceholder) { // call to a builtin function (some will just be an opcode!) val funcname = expr.target.nameInSource[0] @@ -731,7 +727,7 @@ internal class Compiler(private val program: Program): IAstProcessor { } private fun translate(identifierRef: IdentifierReference) { - val target = identifierRef.targetStatement(namespace) + val target = identifierRef.targetStatement(program.namespace) when (target) { is VarDecl -> { when (target.type) { @@ -760,7 +756,7 @@ internal class Compiler(private val program: Program): IAstProcessor { private fun translate(stmt: FunctionCallStatement) { prog.line(stmt.position) - val targetStmt = stmt.target.targetStatement(namespace)!! + val targetStmt = stmt.target.targetStatement(program.namespace)!! if(targetStmt is BuiltinFunctionStatementPlaceholder) { val funcname = stmt.target.nameInSource[0] translateBuiltinFunctionCall(funcname, stmt.arglist) @@ -819,7 +815,7 @@ internal class Compiler(private val program: Program): IAstProcessor { "any", "all" -> { // 1 array argument, type determines the exact syscall to use val arg=args.single() as IdentifierReference - val target=arg.targetVarDecl(namespace)!! + val target=arg.targetVarDecl(program.namespace)!! val length=Value(DataType.UBYTE, target.arraysize!!.size()!!) prog.instr(Opcode.PUSH_BYTE, length) when (arg.resultingDatatype(program)) { @@ -832,7 +828,7 @@ internal class Compiler(private val program: Program): IAstProcessor { "avg" -> { // 1 array argument, type determines the exact syscall to use val arg=args.single() as IdentifierReference - val target=arg.targetVarDecl(namespace)!! + val target=arg.targetVarDecl(program.namespace)!! val length=Value(DataType.UBYTE, target.arraysize!!.size()!!) val arrayDt=arg.resultingDatatype(program) prog.instr(Opcode.PUSH_BYTE, length) @@ -863,7 +859,7 @@ internal class Compiler(private val program: Program): IAstProcessor { "min", "max", "sum" -> { // 1 array argument, type determines the exact syscall to use val arg=args.single() as IdentifierReference - val target=arg.targetVarDecl(namespace)!! + val target=arg.targetVarDecl(program.namespace)!! val length=Value(DataType.UBYTE, target.arraysize!!.size()!!) prog.instr(Opcode.PUSH_BYTE, length) when (arg.resultingDatatype(program)) { @@ -976,7 +972,7 @@ internal class Compiler(private val program: Program): IAstProcessor { throw AstException("swap requires 2 args of identical type") if (args[0].constValue(program) != null || args[1].constValue(program) != null) throw AstException("swap requires 2 variables, not constant value(s)") - if(same(args[0], args[1])) + if(args[0].same(args[1])) throw AstException("swap should have 2 different args") if(dt1 !in NumericDatatypes) throw AstException("swap requires args of numerical type") @@ -1384,7 +1380,7 @@ internal class Compiler(private val program: Program): IAstProcessor { } private fun translate(arrayindexed: ArrayIndexedExpression, write: Boolean) { - val variable = arrayindexed.identifier.targetVarDecl(namespace)!! + val variable = arrayindexed.identifier.targetVarDecl(program.namespace)!! translate(arrayindexed.arrayspec.index) if (write) prog.instr(opcodeWriteindexedvar(variable.datatype), callLabel = variable.scopedname) @@ -1415,7 +1411,7 @@ internal class Compiler(private val program: Program): IAstProcessor { jumpAddress = Value(DataType.UWORD, stmt.address) } else -> { - val target = stmt.identifier!!.targetStatement(namespace)!! + val target = stmt.identifier!!.targetStatement(program.namespace)!! jumpLabel = when(target) { is Label -> target.scopedname is Subroutine -> target.scopedname @@ -1435,14 +1431,14 @@ internal class Compiler(private val program: Program): IAstProcessor { "--" -> prog.instr(Opcode.DEC_VAR_UB, callLabel = stmt.target.register!!.name) } stmt.target.identifier != null -> { - val targetStatement = stmt.target.identifier!!.targetVarDecl(namespace)!! + val targetStatement = stmt.target.identifier!!.targetVarDecl(program.namespace)!! when(stmt.operator) { "++" -> prog.instr(opcodeIncvar(targetStatement.datatype), callLabel = targetStatement.scopedname) "--" -> prog.instr(opcodeDecvar(targetStatement.datatype), callLabel = targetStatement.scopedname) } } stmt.target.arrayindexed != null -> { - val variable = stmt.target.arrayindexed!!.identifier.targetVarDecl(namespace)!! + val variable = stmt.target.arrayindexed!!.identifier.targetVarDecl(program.namespace)!! translate(stmt.target.arrayindexed!!.arrayspec.index) when(stmt.operator) { "++" -> prog.instr(opcodeIncArrayindexedVar(variable.datatype), callLabel = variable.scopedname) @@ -1502,7 +1498,7 @@ internal class Compiler(private val program: Program): IAstProcessor { DataType.STR, DataType.STR_S -> pushHeapVarAddress(stmt.value, true) DataType.ARRAY_B, DataType.ARRAY_UB, DataType.ARRAY_W, DataType.ARRAY_UW, DataType.ARRAY_F -> { if (stmt.value is IdentifierReference) { - val vardecl = (stmt.value as IdentifierReference).targetVarDecl(namespace)!! + val vardecl = (stmt.value as IdentifierReference).targetVarDecl(program.namespace)!! prog.removeLastInstruction() prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname) } @@ -1539,7 +1535,7 @@ internal class Compiler(private val program: Program): IAstProcessor { when (value) { is LiteralValue -> throw CompilerException("can only push address of string or array (value on the heap)") is IdentifierReference -> { - val vardecl = value.targetVarDecl(namespace)!! + val vardecl = value.targetVarDecl(program.namespace)!! if(removeLastOpcode) prog.removeLastInstruction() prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname) } @@ -1551,7 +1547,7 @@ internal class Compiler(private val program: Program): IAstProcessor { when (value) { is LiteralValue -> throw CompilerException("can only push address of float that is a variable on the heap") is IdentifierReference -> { - val vardecl = value.targetVarDecl(namespace)!! + val vardecl = value.targetVarDecl(program.namespace)!! prog.instr(Opcode.PUSH_ADDR_HEAPVAR, callLabel = vardecl.scopedname) } else -> throw CompilerException("can only take address of a the float as constant literal or variable") @@ -1559,7 +1555,7 @@ internal class Compiler(private val program: Program): IAstProcessor { } private fun translateMultiReturnAssignment(stmt: Assignment) { - val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(namespace) + val targetStmt = (stmt.value as? FunctionCall)?.target?.targetStatement(program.namespace) if(targetStmt is Subroutine && targetStmt.isAsmSubroutine) { // this is the only case where multiple assignment targets are allowed: a call to an asmsub with multiple return values // the return values are already on the stack (the subroutine call puts them there) @@ -1575,7 +1571,7 @@ internal class Compiler(private val program: Program): IAstProcessor { private fun popValueIntoTarget(assignTarget: AssignTarget, datatype: DataType) { when { assignTarget.identifier != null -> { - val target = assignTarget.identifier.targetStatement(namespace)!! + val target = assignTarget.identifier.targetStatement(program.namespace)!! if (target is VarDecl) { when (target.type) { VarDeclType.VAR -> { @@ -1630,13 +1626,13 @@ internal class Compiler(private val program: Program): IAstProcessor { loopVarName = reg.name loopVarDt = DataType.UBYTE } else { - val loopvar = loop.loopVar!!.targetVarDecl(namespace)!! + val loopvar = loop.loopVar!!.targetVarDecl(program.namespace)!! loopVarName = loopvar.scopedname loopVarDt = loopvar.datatype } if(loop.iterable is RangeExpr) { - val range = (loop.iterable as RangeExpr).toConstantIntegerRange(heap) + val range = (loop.iterable as RangeExpr).toConstantIntegerRange(program.heap) if(range!=null) { // loop over a range with constant start, last and step values if (range.isEmpty()) @@ -1679,7 +1675,7 @@ internal class Compiler(private val program: Program): IAstProcessor { when { loop.iterable is IdentifierReference -> { val idRef = loop.iterable as IdentifierReference - val vardecl = idRef.targetVarDecl(namespace)!! + val vardecl = idRef.targetVarDecl(program.namespace)!! val iterableValue = vardecl.value as LiteralValue if(!iterableValue.isIterable(program)) throw CompilerException("loop over something that isn't iterable ${loop.iterable}") @@ -1703,16 +1699,16 @@ internal class Compiler(private val program: Program): IAstProcessor { when(iterableValue.type) { !in IterableDatatypes -> throw CompilerException("non-iterableValue type") DataType.STR, DataType.STR_S -> { - numElements = iterableValue.strvalue(heap).length + numElements = iterableValue.strvalue(program.heap).length if(numElements>255) throw CompilerException("string length > 255") } DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_W -> { - numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize + numElements = iterableValue.arrayvalue?.size ?: program.heap.get(iterableValue.heapId!!).arraysize if(numElements>255) throw CompilerException("string length > 255") } DataType.ARRAY_F -> { - numElements = iterableValue.arrayvalue?.size ?: heap.get(iterableValue.heapId!!).arraysize + numElements = iterableValue.arrayvalue?.size ?: program.heap.get(iterableValue.heapId!!).arraysize if(numElements>255) throw CompilerException("string length > 255") } else -> throw CompilerException("weird datatype") @@ -1943,7 +1939,7 @@ internal class Compiler(private val program: Program): IAstProcessor { lvTarget.linkParents(body) val targetStatement: VarDecl? = if(lvTarget.identifier!=null) { - lvTarget.identifier.targetVarDecl(namespace) + lvTarget.identifier.targetVarDecl(program.namespace) } else { null } @@ -2139,7 +2135,7 @@ internal class Compiler(private val program: Program): IAstProcessor { } private fun translate(addrof: AddressOf) { - val target = addrof.identifier.targetVarDecl(namespace)!! + val target = addrof.identifier.targetVarDecl(program.namespace)!! if(target.datatype in ArrayDatatypes || target.datatype in StringDatatypes|| target.datatype==DataType.FLOAT) { pushHeapVarAddress(addrof.identifier, false) } @@ -2176,7 +2172,7 @@ fun loadAsmIncludeFile(filename: String, source: Path): String { ?: throw IllegalArgumentException("library file '$filename' not found") resource.bufferedReader().use { it.readText() } } else { - // first try in the same folder as where the containing file was imported from + // first try in the isSameAs folder as where the containing file was imported from val sib = source.resolveSibling(filename) if (sib.toFile().isFile) sib.toFile().readText() diff --git a/compiler/src/prog8/compiler/Zeropage.kt b/compiler/src/prog8/compiler/Zeropage.kt index 2d8829f79..e247d2f7b 100644 --- a/compiler/src/prog8/compiler/Zeropage.kt +++ b/compiler/src/prog8/compiler/Zeropage.kt @@ -16,7 +16,7 @@ abstract class Zeropage(protected val options: CompilationOptions) { fun available() = free.size fun allocate(scopedname: String, datatype: DataType, position: Position?): Int { - assert(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"same scopedname can't be allocated twice"} + assert(scopedname.isEmpty() || !allocations.values.any { it.first==scopedname } ) {"isSameAs scopedname can't be allocated twice"} val size = when (datatype) { diff --git a/compiler/src/prog8/compiler/intermediate/Value.kt b/compiler/src/prog8/compiler/intermediate/Value.kt index 311b1d39a..e7dd76149 100644 --- a/compiler/src/prog8/compiler/intermediate/Value.kt +++ b/compiler/src/prog8/compiler/intermediate/Value.kt @@ -118,7 +118,7 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) { private fun arithResult(leftDt: DataType, result: Number, rightDt: DataType, op: String): Value { if(leftDt!=rightDt) - throw ValueException("left and right datatypes are not the same") + throw ValueException("left and right datatypes are not the isSameAs") if(result.toDouble() < 0 ) { return when(leftDt) { DataType.UBYTE, DataType.UWORD -> { diff --git a/compiler/src/prog8/compiler/target/c64/AsmGen.kt b/compiler/src/prog8/compiler/target/c64/AsmGen.kt index 4050eae9f..64433fac0 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmGen.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmGen.kt @@ -16,7 +16,8 @@ import kotlin.math.abs class AssemblyError(msg: String) : RuntimeException(msg) -class AsmGen(val options: CompilationOptions, val program: IntermediateProgram, val heap: HeapValues, val zeropage: Zeropage) { +class AsmGen(private val options: CompilationOptions, private val program: IntermediateProgram, + private val heap: HeapValues, private val zeropage: Zeropage) { private val globalFloatConsts = mutableMapOf() private val assemblyLines = mutableListOf() private lateinit var block: IntermediateProgram.ProgramBlock diff --git a/compiler/src/prog8/compiler/target/c64/AsmOptimizer.kt b/compiler/src/prog8/compiler/target/c64/AsmOptimizer.kt index b66c0a01c..2e9e199b2 100644 --- a/compiler/src/prog8/compiler/target/c64/AsmOptimizer.kt +++ b/compiler/src/prog8/compiler/target/c64/AsmOptimizer.kt @@ -64,7 +64,7 @@ fun optimizeUselessStackByteWrites(linesByFour: List>> fun optimizeSameAssignments(linesByFourteen: List>>): List { - // optimize sequential assignments of the same value to various targets (bytes, words, floats) + // optimize sequential assignments of the isSameAs value to various targets (bytes, words, floats) // the float one is the one that requires 2*7=14 lines of code to check... // @todo a better place to do this is in the Compiler instead and work on opcodes, and never even create the inefficient asm... @@ -86,7 +86,7 @@ fun optimizeSameAssignments(linesByFourteen: List>>): val thirdvalue = fifth.substring(4) val fourthvalue = sixth.substring(4) if(firstvalue==thirdvalue && secondvalue==fourthvalue) { - // lda/ldy sta/sty twice the same word --> remove second lda/ldy pair (fifth and sixth lines) + // lda/ldy sta/sty twice the isSameAs word --> remove second lda/ldy pair (fifth and sixth lines) removeLines.add(pair[4].index) removeLines.add(pair[5].index) } @@ -96,7 +96,7 @@ fun optimizeSameAssignments(linesByFourteen: List>>): val firstvalue = first.substring(4) val secondvalue = third.substring(4) if(firstvalue==secondvalue) { - // lda value / sta ? / lda same-value / sta ? -> remove second lda (third line) + // lda value / sta ? / lda isSameAs-value / sta ? -> remove second lda (third line) removeLines.add(pair[2].index) } } diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index 29f098ffb..9fac6e136 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -277,7 +277,7 @@ private fun collectionArgOutputBoolean(args: List, position: Positi } private fun builtinAbs(args: List, position: Position, program: Program): LiteralValue { - // 1 arg, type = float or int, result type= same as argument type + // 1 arg, type = float or int, result type= isSameAs as argument type if(args.size!=1) throw SyntaxError("abs requires one numeric argument", position) diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index 15c7157bf..4ebf88bb8 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -16,7 +16,7 @@ class ConstantFolding(private val program: Program) : IAstProcessor { private val reportedErrorMessages = mutableSetOf() fun addError(x: AstException) { - // check that we don't add the same error more than once + // check that we don't add the isSameAs error more than once if(x.toString() !in reportedErrorMessages) { reportedErrorMessages.add(x.toString()) errors.add(x) @@ -330,7 +330,7 @@ class ConstantFolding(private val program: Program) : IAstProcessor { { // @todo this implements only a small set of possible reorderings for now if(expr.operator==subExpr.operator) { - // both operators are the same. + // both operators are the isSameAs. // If + or *, we can simply swap the const of expr and Var in subexpr. if(expr.operator=="+" || expr.operator=="*") { if(leftIsConst) { diff --git a/compiler/src/prog8/optimizing/Extensions.kt b/compiler/src/prog8/optimizing/Extensions.kt index abc841d95..edbd9895d 100644 --- a/compiler/src/prog8/optimizing/Extensions.kt +++ b/compiler/src/prog8/optimizing/Extensions.kt @@ -4,7 +4,7 @@ import prog8.ast.* import prog8.parser.ParsingFailedError -fun Program.constantFold() { +internal fun Program.constantFold() { val optimizer = ConstantFolding(this) try { optimizer.process(this) @@ -26,7 +26,7 @@ fun Program.constantFold() { } -fun Program.optimizeStatements(optimizeInlining: Boolean): Int { +internal fun Program.optimizeStatements(optimizeInlining: Boolean): Int { val optimizer = StatementOptimizer(this, optimizeInlining) optimizer.process(this) for(scope in optimizer.scopesToFlatten.reversed()) { @@ -42,7 +42,7 @@ fun Program.optimizeStatements(optimizeInlining: Boolean): Int { return optimizer.optimizationsDone } -fun Program.simplifyExpressions() : Int { +internal fun Program.simplifyExpressions() : Int { val optimizer = SimplifyExpressions(this) optimizer.process(this) return optimizer.optimizationsDone diff --git a/compiler/src/prog8/optimizing/SimplifyExpressions.kt b/compiler/src/prog8/optimizing/SimplifyExpressions.kt index 819015677..171a6fb98 100644 --- a/compiler/src/prog8/optimizing/SimplifyExpressions.kt +++ b/compiler/src/prog8/optimizing/SimplifyExpressions.kt @@ -8,7 +8,7 @@ import kotlin.math.log2 todo advanced expression optimization: common (sub) expression elimination (turn common expressions into single subroutine call + introduce variable to hold it) */ -class SimplifyExpressions(private val program: Program) : IAstProcessor { +internal class SimplifyExpressions(private val program: Program) : IAstProcessor { var optimizationsDone: Int = 0 override fun process(assignment: Assignment): IStatement { @@ -295,8 +295,8 @@ class SimplifyExpressions(private val program: Program) : IAstProcessor { private fun determineY(x: IExpression, subBinExpr: BinaryExpression): IExpression? { return when { - same(subBinExpr.left, x) -> subBinExpr.right - same(subBinExpr.right, x) -> subBinExpr.left + subBinExpr.left.same(x) -> subBinExpr.right + subBinExpr.right.same(x) -> subBinExpr.left else -> null } } diff --git a/compiler/src/prog8/optimizing/StatementOptimizer.kt b/compiler/src/prog8/optimizing/StatementOptimizer.kt index 206b03772..f44bf1363 100644 --- a/compiler/src/prog8/optimizing/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizing/StatementOptimizer.kt @@ -12,7 +12,7 @@ import kotlin.math.floor todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to) + print warning about this */ -class StatementOptimizer(private val program: Program, private val optimizeInlining: Boolean) : IAstProcessor { +internal class StatementOptimizer(private val program: Program, private val optimizeInlining: Boolean) : IAstProcessor { var optimizationsDone: Int = 0 private set var scopesToFlatten = mutableListOf() @@ -50,7 +50,7 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin } private fun inlineSubroutine(sub: Subroutine, caller: Node) { - // if the sub is called multiple times from the same scope, we can't inline (would result in duplicate definitions) + // if the sub is called multiple times from the isSameAs scope, we can't inline (would result in duplicate definitions) // (unless we add a sequence number to all vars/labels and references to them in the inlined code, but I skip that for now) val scope = caller.definingScope() if(sub.calledBy.count { it.definingScope()===scope } > 1) @@ -171,7 +171,7 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin } private fun deduplicateAssignments(statements: List): MutableList { - // removes 'duplicate' assignments that assign the same target + // removes 'duplicate' assignments that assign the isSameAs target val linesToRemove = mutableListOf() var previousAssignmentLine: Int? = null for (i in 0 until statements.size) { @@ -182,9 +182,9 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin continue } else { val prev = statements[previousAssignmentLine] as Assignment - if (prev.targets.size == 1 && stmt.targets.size == 1 && same(prev.targets[0], stmt.targets[0])) { + if (prev.targets.size == 1 && stmt.targets.size == 1 && prev.targets[0].isSameAs(stmt.targets[0], program)) { // get rid of the previous assignment, if the target is not MEMORY - if (isNotMemory(prev.targets[0])) + if (prev.targets[0].isNotMemory(program.namespace)) linesToRemove.add(previousAssignmentLine) } previousAssignmentLine = i @@ -195,25 +195,6 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin return linesToRemove } - private fun isNotMemory(target: AssignTarget): Boolean { - if(target.register!=null) - return true - if(target.memoryAddress!=null) - return false - if(target.arrayindexed!=null) { - val targetStmt = target.arrayindexed.identifier.targetVarDecl(program.namespace) - if(targetStmt!=null) - return targetStmt.type!=VarDeclType.MEMORY - } - if(target.identifier!=null) { - val targetStmt = target.identifier.targetVarDecl(program.namespace) - if(targetStmt!=null) - return targetStmt.type!=VarDeclType.MEMORY - } - return false - } - - override fun process(functionCallStatement: FunctionCallStatement): IStatement { if(functionCallStatement.target.nameInSource.size==1 && functionCallStatement.target.nameInSource[0] in BuiltinFunctions) { val functionName = functionCallStatement.target.nameInSource[0] @@ -467,7 +448,7 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin if(assignment.targets.size==1) { val target=assignment.targets[0] - if(same(target, assignment.value)) { + if(target.isSameAs(assignment.value)) { optimizationsDone++ return NopStatement(assignment.position) } @@ -477,7 +458,7 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin val cv = bexpr.right.constValue(program)?.asNumericValue?.toDouble() if(cv==null) { if(bexpr.operator=="+" && targetDt!=DataType.FLOAT) { - if (same(bexpr.left, bexpr.right) && same(target, bexpr.left)) { + if (bexpr.left.same(bexpr.right) && target.isSameAs(bexpr.left)) { bexpr.operator = "*" bexpr.right = LiteralValue.optimalInteger(2, assignment.value.position) optimizationsDone++ @@ -485,7 +466,7 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin } } } else { - if (same(target, bexpr.left)) { + if (target.isSameAs(bexpr.left)) { // remove assignments that have no effect X=X , X+=0, X-=0, X*=1, X/=1, X//=1, A |= 0, A ^= 0, A<<=0, etc etc // A = A B val vardeclDt = (target.identifier?.targetVarDecl(program.namespace))?.type @@ -616,64 +597,7 @@ class StatementOptimizer(private val program: Program, private val optimizeInlin return super.process(label) } - - private fun same(target: AssignTarget, value: IExpression): Boolean { - return when { - target.memoryAddress!=null -> false - target.register!=null -> value is RegisterExpr && value.register==target.register - target.identifier!=null -> value is IdentifierReference && value.nameInSource==target.identifier.nameInSource - target.arrayindexed!=null -> value is ArrayIndexedExpression && - value.identifier.nameInSource==target.arrayindexed.identifier.nameInSource && - value.arrayspec.size()!=null && - target.arrayindexed.arrayspec.size()!=null && - value.arrayspec.size()==target.arrayindexed.arrayspec.size() - else -> false - } - } - - private fun same(target1: AssignTarget, target2: AssignTarget): Boolean { - if(target1===target2) - return true - if(target1.register!=null && target2.register!=null) - return target1.register==target2.register - if(target1.identifier!=null && target2.identifier!=null) - return target1.identifier.nameInSource==target2.identifier.nameInSource - if(target1.memoryAddress!=null && target2.memoryAddress!=null) { - val addr1 = target1.memoryAddress!!.addressExpression.constValue(program) - val addr2 = target2.memoryAddress!!.addressExpression.constValue(program) - return addr1!=null && addr2!=null && addr1==addr2 - } - if(target1.arrayindexed!=null && target2.arrayindexed!=null) { - if(target1.arrayindexed.identifier.nameInSource == target2.arrayindexed.identifier.nameInSource) { - val x1 = target1.arrayindexed.arrayspec.index.constValue(program) - val x2 = target2.arrayindexed.arrayspec.index.constValue(program) - return x1!=null && x2!=null && x1==x2 - } - } - return false - } } -fun same(left: IExpression, right: IExpression): Boolean { - if(left===right) - return true - when(left) { - is RegisterExpr -> - return (right is RegisterExpr && right.register==left.register) - is IdentifierReference -> - return (right is IdentifierReference && right.nameInSource==left.nameInSource) - is PrefixExpression -> - return (right is PrefixExpression && right.operator==left.operator && same(right.expression, left.expression)) - is BinaryExpression -> - return (right is BinaryExpression && right.operator==left.operator - && same(right.left, left.left) - && same(right.right, left.right)) - is ArrayIndexedExpression -> { - return (right is ArrayIndexedExpression && right.identifier.nameInSource == left.identifier.nameInSource - && same(right.arrayspec.index, left.arrayspec.index)) - } - is LiteralValue -> return (right is LiteralValue && right==left) - } - return false -} + diff --git a/compiler/src/prog8/parser/CommentHandlingTokenStream.kt b/compiler/src/prog8/parser/CommentHandlingTokenStream.kt index c3963761d..714b59dd8 100644 --- a/compiler/src/prog8/parser/CommentHandlingTokenStream.kt +++ b/compiler/src/prog8/parser/CommentHandlingTokenStream.kt @@ -4,7 +4,7 @@ import org.antlr.v4.runtime.CommonTokenStream import org.antlr.v4.runtime.Lexer -class CommentHandlingTokenStream(lexer: Lexer) : CommonTokenStream(lexer) { +internal class CommentHandlingTokenStream(lexer: Lexer) : CommonTokenStream(lexer) { data class Comment(val type: String, val line: Int, val comment: String) diff --git a/compiler/src/prog8/parser/ModuleParsing.kt b/compiler/src/prog8/parser/ModuleParsing.kt index 02112c256..bc5491bb9 100644 --- a/compiler/src/prog8/parser/ModuleParsing.kt +++ b/compiler/src/prog8/parser/ModuleParsing.kt @@ -8,7 +8,7 @@ import java.nio.file.Path import java.nio.file.Paths -class ParsingFailedError(override var message: String) : Exception(message) +internal class ParsingFailedError(override var message: String) : Exception(message) private class LexerErrorListener: BaseErrorListener() { @@ -25,7 +25,7 @@ internal class CustomLexer(val modulePath: Path, input: CharStream?) : prog8Lexe internal fun moduleName(fileName: Path) = fileName.toString().substringBeforeLast('.') -fun importModule(program: Program, filePath: Path): Module { +internal fun importModule(program: Program, filePath: Path): Module { print("importing '${moduleName(filePath.fileName)}'") if(filePath.parent!=null) { var importloc = filePath.toString() @@ -43,14 +43,14 @@ fun importModule(program: Program, filePath: Path): Module { return importModule(program, input, filePath, filePath.parent==null) } -fun importLibraryModule(program: Program, name: String): Module? { +internal fun importLibraryModule(program: Program, name: String): Module? { val import = Directive("%import", listOf( DirectiveArg("", name, 42, position = Position("<<>>", 0, 0 ,0)) ), Position("<<>>", 0, 0 ,0)) return executeImportDirective(program, import, Paths.get("")) } -private fun importModule(program: Program, stream: CharStream, modulePath: Path, isLibrary: Boolean): Module { +internal fun importModule(program: Program, stream: CharStream, modulePath: Path, isLibrary: Boolean): Module { val moduleName = moduleName(modulePath.fileName) val lexer = CustomLexer(modulePath, stream) val lexerErrors = LexerErrorListener() @@ -133,6 +133,6 @@ private fun executeImportDirective(program: Program, import: Directive, source: return importedModule } -fun tryGetEmbeddedResource(name: String): InputStream? { +internal fun tryGetEmbeddedResource(name: String): InputStream? { return object{}.javaClass.getResourceAsStream("/prog8lib/$name") } diff --git a/compiler/src/prog8/stackvm/Program.kt b/compiler/src/prog8/stackvm/Program.kt index 0c4a4bb8f..3ca535a98 100644 --- a/compiler/src/prog8/stackvm/Program.kt +++ b/compiler/src/prog8/stackvm/Program.kt @@ -122,7 +122,7 @@ class Program (val name: String, val instructions = mutableListOf() val labels = mutableMapOf() val splitpattern = Pattern.compile("\\s+") - val nextInstructionLabels = Stack() // more than one label can occur on the same line + val nextInstructionLabels = Stack() // more than one label can occur on the isSameAs line while(true) { val (lineNr, line) = lines.next() diff --git a/compiler/test/StackVMOpcodeTests.kt b/compiler/test/StackVMOpcodeTests.kt index 689067b6f..1eac5a8bc 100644 --- a/compiler/test/StackVMOpcodeTests.kt +++ b/compiler/test/StackVMOpcodeTests.kt @@ -636,7 +636,7 @@ class TestStackVmOpcodes { assertEquals(DataType.UBYTE, rndb2.type) assertEquals(DataType.UWORD, rndw.type) assertEquals(DataType.FLOAT, rndf.type) - assertNotEquals(rndb1.integerValue(), rndb2.integerValue()) // this *sometimes* fails when the two random numbers are the same by pure chance + assertNotEquals(rndb1.integerValue(), rndb2.integerValue()) // this *sometimes* fails when the two random numbers are the isSameAs by pure chance assertTrue(rndf.numericValue().toDouble() > 0.0 && rndf.numericValue().toDouble() < 1.0) vm.step(2)