cleaned up some symbol visibilities

This commit is contained in:
Irmen de Jong 2019-06-23 13:49:35 +02:00
parent a6c3251668
commit ebd38f27e6
21 changed files with 152 additions and 155 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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