mirror of
https://github.com/irmen/prog8.git
synced 2024-11-16 22:09:56 +00:00
cleaned up some symbol visibilities
This commit is contained in:
parent
a6c3251668
commit
ebd38f27e6
@ -35,7 +35,7 @@ fun main(args: Array<String>) {
|
||||
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<String>) {
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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<String, Block> = mutableMapOf()
|
||||
|
||||
fun result(): List<AstException> {
|
||||
internal fun result(): List<AstException> {
|
||||
return checkResult
|
||||
}
|
||||
|
||||
|
@ -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<VT> {
|
||||
private class AstRecursionChecker(private val namespace: INameScope) : IAstProcessor {
|
||||
private val callGraph = DirectedGraph<INameScope>()
|
||||
|
||||
fun result(): List<AstException> {
|
||||
internal fun result(): List<AstException> {
|
||||
val cycle = callGraph.checkForCycle()
|
||||
if(cycle.isEmpty())
|
||||
return emptyList()
|
||||
|
@ -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<SyntaxError> = mutableListOf()
|
||||
|
||||
fun result(): List<SyntaxError> {
|
||||
internal fun result(): List<SyntaxError> {
|
||||
return checkResult
|
||||
}
|
||||
|
||||
|
@ -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<IStatement>) {
|
||||
// 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<IStatement>()
|
||||
val stmtIter = statements.iterator()
|
||||
for(stmt in stmtIter) {
|
||||
|
@ -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<String> = Stack()
|
||||
private val continueStmtLabelStack : Stack<String> = 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()
|
||||
|
@ -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) {
|
||||
|
@ -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 -> {
|
||||
|
@ -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<Double, String>()
|
||||
private val assemblyLines = mutableListOf<String>()
|
||||
private lateinit var block: IntermediateProgram.ProgramBlock
|
||||
|
@ -64,7 +64,7 @@ fun optimizeUselessStackByteWrites(linesByFour: List<List<IndexedValue<String>>>
|
||||
|
||||
fun optimizeSameAssignments(linesByFourteen: List<List<IndexedValue<String>>>): List<Int> {
|
||||
|
||||
// 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<List<IndexedValue<String>>>):
|
||||
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<List<IndexedValue<String>>>):
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ private fun collectionArgOutputBoolean(args: List<IExpression>, position: Positi
|
||||
}
|
||||
|
||||
private fun builtinAbs(args: List<IExpression>, 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)
|
||||
|
||||
|
@ -16,7 +16,7 @@ class ConstantFolding(private val program: Program) : IAstProcessor {
|
||||
private val reportedErrorMessages = mutableSetOf<String>()
|
||||
|
||||
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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<INameScope>()
|
||||
@ -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<IStatement>): MutableList<Int> {
|
||||
// removes 'duplicate' assignments that assign the same target
|
||||
// removes 'duplicate' assignments that assign the isSameAs target
|
||||
val linesToRemove = mutableListOf<Int>()
|
||||
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 <operator> 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
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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("<<<implicit-import>>>", 0, 0 ,0))
|
||||
), Position("<<<implicit-import>>>", 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")
|
||||
}
|
||||
|
@ -122,7 +122,7 @@ class Program (val name: String,
|
||||
val instructions = mutableListOf<Instruction>()
|
||||
val labels = mutableMapOf<String, Instruction>()
|
||||
val splitpattern = Pattern.compile("\\s+")
|
||||
val nextInstructionLabels = Stack<String>() // more than one label can occur on the same line
|
||||
val nextInstructionLabels = Stack<String>() // more than one label can occur on the isSameAs line
|
||||
|
||||
while(true) {
|
||||
val (lineNr, line) = lines.next()
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user