reducing ast dependencies

This commit is contained in:
Irmen de Jong 2021-02-07 18:34:55 +01:00
parent be75b8dbe5
commit f1f51a01c6
24 changed files with 207 additions and 171 deletions

View File

@ -3,6 +3,8 @@ package prog8.ast
import prog8.ast.base.*
import prog8.ast.expressions.Expression
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.walk.IAstVisitor
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
@ -242,11 +244,18 @@ interface IAssignable {
// just a tag for now
}
interface IBuiltinFunctions {
val names: Set<String>
fun constValue(name: String, args: List<Expression>, position: Position): NumericLiteralValue?
fun returnType(name: String, args: MutableList<Expression>): InferredTypes.InferredType
}
/*********** Everything starts from here, the Program; zero or more modules *************/
class Program(val name: String, val modules: MutableList<Module>, builtinFunctionNames: Set<String>): Node {
val namespace = GlobalNamespace(modules, builtinFunctionNames)
class Program(val name: String, val modules: MutableList<Module>, val builtinFunctions: IBuiltinFunctions): Node {
val namespace = GlobalNamespace(modules, builtinFunctions.names)
val definedLoadAddress: Int
get() = modules.first().loadAddress

View File

@ -6,10 +6,6 @@ import prog8.ast.base.*
import prog8.ast.walk.IAstVisitor
import prog8.ast.statements.*
import prog8.ast.walk.AstWalker
import prog8.functions.BuiltinFunctions
import prog8.functions.CannotEvaluateException
import prog8.functions.NotConstArgumentException
import prog8.functions.builtinFunctionReturnType
import java.util.*
import kotlin.math.abs
@ -256,7 +252,7 @@ class ArrayIndexedExpression(var arrayvar: IdentifierReference,
override fun referencesIdentifier(vararg scopedName: String) = arrayvar.referencesIdentifier(*scopedName)
override fun inferType(program: Program): InferredTypes.InferredType {
val target = arrayvar.targetStatement(program.namespace)
val target = arrayvar.targetStatement(program)
if (target is VarDecl) {
return when (target.datatype) {
DataType.STR -> InferredTypes.knownFor(DataType.UBYTE)
@ -711,14 +707,14 @@ internal fun makeRange(fromVal: Int, toVal: Int, stepVal: Int): IntProgression {
data class IdentifierReference(val nameInSource: List<String>, override val position: Position) : Expression(), IAssignable {
override lateinit var parent: Node
fun targetStatement(namespace: INameScope) =
if(nameInSource.size==1 && nameInSource[0] in BuiltinFunctions)
fun targetStatement(program: Program) =
if(nameInSource.size==1 && nameInSource[0] in program.builtinFunctions.names)
BuiltinFunctionStatementPlaceholder(nameInSource[0], position)
else
namespace.lookup(nameInSource, this)
program.namespace.lookup(nameInSource, this)
fun targetVarDecl(namespace: INameScope): VarDecl? = targetStatement(namespace) as? VarDecl
fun targetSubroutine(namespace: INameScope): Subroutine? = targetStatement(namespace) as? Subroutine
fun targetVarDecl(program: Program): VarDecl? = targetStatement(program) as? VarDecl
fun targetSubroutine(program: Program): Subroutine? = targetStatement(program) as? Subroutine
override fun equals(other: Any?) = other is IdentifierReference && other.nameInSource==nameInSource
override fun hashCode() = nameInSource.hashCode()
@ -754,14 +750,14 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
nameInSource.size==scopedName.size && nameInSource.toTypedArray().contentEquals(scopedName)
override fun inferType(program: Program): InferredTypes.InferredType {
return when (val targetStmt = targetStatement(program.namespace)) {
return when (val targetStmt = targetStatement(program)) {
is VarDecl -> InferredTypes.knownFor(targetStmt.datatype)
is StructDecl -> InferredTypes.knownFor(DataType.STRUCT)
else -> InferredTypes.InferredType.unknown()
}
}
fun memberOfStruct(namespace: INameScope) = this.targetVarDecl(namespace)?.struct
fun memberOfStruct(program: Program) = this.targetVarDecl(program)?.struct
fun heapId(namespace: INameScope): Int {
val node = namespace.lookup(nameInSource, this) ?: throw UndefinedSymbolError(this)
@ -774,11 +770,11 @@ data class IdentifierReference(val nameInSource: List<String>, override val posi
}
}
fun firstStructVarName(namespace: INameScope): String? {
fun firstStructVarName(program: Program): String? {
// take the name of the first struct member of the structvariable instead
// if it's just a regular variable, return null.
val struct = memberOfStruct(namespace) ?: return null
val decl = targetVarDecl(namespace)!!
val struct = memberOfStruct(program) ?: return null
val decl = targetVarDecl(program)!!
if(decl.datatype!=DataType.STRUCT)
return null
@ -816,34 +812,16 @@ class FunctionCall(override var target: IdentifierReference,
private fun constValue(program: Program, withDatatypeCheck: Boolean): NumericLiteralValue? {
// if the function is a built-in function and the args are consts, should try to const-evaluate!
// lenghts of arrays and strings are constants that are determined at compile time!
if(target.nameInSource.size>1) return null
try {
var resultValue: NumericLiteralValue? = null
val func = BuiltinFunctions[target.nameInSource[0]]
if(func!=null) {
val exprfunc = func.constExpressionFunc
if(exprfunc!=null)
resultValue = exprfunc(args, position, program)
else if(func.known_returntype==null)
throw ExpressionError("builtin function ${target.nameInSource[0]} can't be used here because it doesn't return a value", position)
}
if(withDatatypeCheck) {
val resultDt = this.inferType(program)
if(resultValue==null || resultDt istype resultValue.type)
return resultValue
throw FatalAstException("evaluated const expression result value doesn't match expected datatype $resultDt, pos=$position")
} else {
if(target.nameInSource.size>1)
return null
val resultValue: NumericLiteralValue? = program.builtinFunctions.constValue(target.nameInSource[0], args, position)
if(withDatatypeCheck) {
val resultDt = this.inferType(program)
if(resultValue==null || resultDt istype resultValue.type)
return resultValue
}
}
catch(x: NotConstArgumentException) {
// const-evaluating the builtin function call failed.
return null
}
catch(x: CannotEvaluateException) {
// const-evaluating the builtin function call failed.
return null
throw FatalAstException("evaluated const expression result value doesn't match expected datatype $resultDt, pos=$position")
} else {
return resultValue
}
}
@ -860,14 +838,14 @@ class FunctionCall(override var target: IdentifierReference,
val constVal = constValue(program ,false)
if(constVal!=null)
return InferredTypes.knownFor(constVal.type)
val stmt = target.targetStatement(program.namespace) ?: return InferredTypes.unknown()
val stmt = target.targetStatement(program) ?: return InferredTypes.unknown()
when (stmt) {
is BuiltinFunctionStatementPlaceholder -> {
if(target.nameInSource[0] == "set_carry" || target.nameInSource[0]=="set_irqd" ||
target.nameInSource[0] == "clear_carry" || target.nameInSource[0]=="clear_irqd") {
return InferredTypes.void() // these have no return value
}
return builtinFunctionReturnType(target.nameInSource[0], this.args, program)
return program.builtinFunctions.returnType(target.nameInSource[0], this.args)
}
is Subroutine -> {
if(stmt.returntypes.isEmpty())

View File

@ -38,7 +38,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
// But it can only be done if the target variable IS NOT OCCURRING AS AN OPERAND ITSELF.
if(!assignment.isAugmentable
&& assignment.target.identifier != null
&& CompilationTarget.instance.isInRegularRAM(assignment.target, program.namespace)) {
&& CompilationTarget.instance.isInRegularRAM(assignment.target, program)) {
val binExpr = assignment.value as? BinaryExpression
if (binExpr != null && binExpr.operator !in comparisonOperators) {
if (binExpr.left !is BinaryExpression) {
@ -157,7 +157,7 @@ internal class BeforeAsmGenerationAstChanger(val program: Program, val errors: E
if(typecast.type in WordDatatypes) {
val fcall = typecast.parent as? IFunctionCall
if (fcall != null) {
val sub = fcall.target.targetStatement(program.namespace) as? Subroutine
val sub = fcall.target.targetStatement(program) as? Subroutine
if (sub != null && sub.isAsmSubroutine) {
return listOf(IAstModification.ReplaceNode(typecast, typecast.expression, parent))
}

View File

@ -1,8 +1,12 @@
package prog8.compiler
import prog8.ast.AstToSourceCode
import prog8.ast.IBuiltinFunctions
import prog8.ast.Program
import prog8.ast.base.*
import prog8.ast.expressions.Expression
import prog8.ast.expressions.InferredTypes
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.statements.Directive
import prog8.compiler.astprocessing.*
import prog8.compiler.astprocessing.addTypecasts
@ -12,7 +16,7 @@ import prog8.compiler.astprocessing.reorderStatements
import prog8.compiler.target.C64Target
import prog8.compiler.target.CompilationTarget
import prog8.compiler.target.Cx16Target
import prog8.functions.BuiltinFunctions
import prog8.functions.*
import prog8.optimizer.*
import prog8.optimizer.UnusedCodeRemover
import prog8.optimizer.constantFold
@ -97,13 +101,44 @@ fun compileProgram(filepath: Path,
throw x
}
return CompilationResult(false, Program("failed", mutableListOf(), setOf()), programName, emptyList())
val failedProgram = Program("failed", mutableListOf(), BuiltinFunctionsFacade(BuiltinFunctions))
return CompilationResult(false, failedProgram, programName, emptyList())
}
private class BuiltinFunctionsFacade(functions: Map<String, FSignature>): IBuiltinFunctions {
lateinit var program: Program
override val names = functions.keys
override fun constValue(name: String, args: List<Expression>, position: Position): NumericLiteralValue? {
val func = BuiltinFunctions[name]
if(func!=null) {
val exprfunc = func.constExpressionFunc
if(exprfunc!=null) {
return try {
exprfunc(args, position, program)
} catch(x: NotConstArgumentException) {
// const-evaluating the builtin function call failed.
null
} catch(x: CannotEvaluateException) {
// const-evaluating the builtin function call failed.
null
}
}
else if(func.known_returntype==null)
throw IllegalArgumentException("builtin function $name can't be used here because it doesn't return a value")
}
return null
}
override fun returnType(name: String, args: MutableList<Expression>) =
builtinFunctionReturnType(name, args, program)
}
private fun parseImports(filepath: Path, errors: ErrorReporter): Triple<Program, CompilationOptions, List<Path>> {
println("Compiler target: ${CompilationTarget.instance.name}. Parsing...")
val importer = ModuleImporter()
val programAst = Program(moduleName(filepath.fileName), mutableListOf(), BuiltinFunctions.keys)
val bf = BuiltinFunctionsFacade(BuiltinFunctions)
val programAst = Program(moduleName(filepath.fileName), mutableListOf(), bf)
bf.program = programAst
importer.importModule(programAst, filepath)
errors.handle()

View File

@ -100,7 +100,7 @@ internal class AstChecker(private val program: Program,
if(iterableDt !in IterableDatatypes && forLoop.iterable !is RangeExpr) {
errors.err("can only loop over an iterable type", forLoop.position)
} else {
val loopvar = forLoop.loopVar.targetVarDecl(program.namespace)
val loopvar = forLoop.loopVar.targetVarDecl(program)
if(loopvar==null || loopvar.type== VarDeclType.CONST) {
errors.err("for loop requires a variable to loop with", forLoop.position)
} else {
@ -377,7 +377,7 @@ internal class AstChecker(private val program: Program,
override fun visit(assignment: Assignment) {
if(assignment.value is FunctionCall) {
val stmt = (assignment.value as FunctionCall).target.targetStatement(program.namespace)
val stmt = (assignment.value as FunctionCall).target.targetStatement(program)
if (stmt is Subroutine) {
val idt = assignment.target.inferType(program)
if(!idt.isKnown) {
@ -391,7 +391,7 @@ internal class AstChecker(private val program: Program,
val targetIdent = assignment.target.identifier
if(targetIdent!=null) {
val targetVar = targetIdent.targetVarDecl(program.namespace)
val targetVar = targetIdent.targetVarDecl(program)
if(targetVar?.struct != null) {
val sourceStructLv = assignment.value as? ArrayLiteralValue
if (sourceStructLv != null) {
@ -400,7 +400,7 @@ internal class AstChecker(private val program: Program,
} else {
val sourceIdent = assignment.value as? IdentifierReference
if (sourceIdent != null) {
val sourceVar = sourceIdent.targetVarDecl(program.namespace)
val sourceVar = sourceIdent.targetVarDecl(program)
if (sourceVar?.struct != null) {
if (sourceVar.struct !== targetVar.struct)
errors.err("assignment of different struct types", assignment.position)
@ -488,7 +488,7 @@ internal class AstChecker(private val program: Program,
}
override fun visit(addressOf: AddressOf) {
val variable=addressOf.identifier.targetVarDecl(program.namespace)
val variable=addressOf.identifier.targetVarDecl(program)
if(variable!=null
&& variable.datatype !in ArrayDatatypes
&& variable.type!=VarDeclType.MEMORY
@ -783,7 +783,7 @@ internal class AstChecker(private val program: Program,
fun isPassByReferenceElement(e: Expression): Boolean {
if(e is IdentifierReference) {
val decl = e.targetVarDecl(program.namespace)!!
val decl = e.targetVarDecl(program)!!
return decl.datatype in PassByReferenceDatatypes
}
return e is StringLiteralValue
@ -936,12 +936,12 @@ internal class AstChecker(private val program: Program,
errors.warn("sgn() of unsigned type is always 0 or 1, this is perhaps not what was intended", functionCall.args.first().position)
}
val error = VerifyFunctionArgTypes.checkTypes(functionCall, functionCall.definingScope(), program)
val error = VerifyFunctionArgTypes.checkTypes(functionCall, program)
if(error!=null)
errors.err(error, functionCall.position)
// check the functions that return multiple returnvalues.
val stmt = functionCall.target.targetStatement(program.namespace)
val stmt = functionCall.target.targetStatement(program)
if (stmt is Subroutine) {
if (stmt.returntypes.size > 1) {
// Currently, it's only possible to handle ONE (or zero) return values from a subroutine.
@ -1000,7 +1000,7 @@ internal class AstChecker(private val program: Program,
}
val error =
VerifyFunctionArgTypes.checkTypes(functionCallStatement, functionCallStatement.definingScope(), program)
VerifyFunctionArgTypes.checkTypes(functionCallStatement, program)
if(error!=null) {
errors.err(error, functionCallStatement.args.firstOrNull()?.position ?: functionCallStatement.position)
}
@ -1027,7 +1027,7 @@ internal class AstChecker(private val program: Program,
errors.err("swap requires args of numerical type", position)
}
else if(target.name=="all" || target.name=="any") {
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program.namespace)?.datatype == DataType.STR) {
if((args[0] as? AddressOf)?.identifier?.targetVarDecl(program)?.datatype == DataType.STR) {
errors.err("any/all on a string is useless (is always true unless the string is empty)", position)
}
if(args[0].inferType(program).typeOrElse(DataType.STR) == DataType.STR) {
@ -1082,7 +1082,7 @@ internal class AstChecker(private val program: Program,
}
}
} else if(postIncrDecr.target.arrayindexed != null) {
val target = postIncrDecr.target.arrayindexed?.arrayvar?.targetStatement(program.namespace)
val target = postIncrDecr.target.arrayindexed?.arrayvar?.targetStatement(program)
if(target==null) {
errors.err("undefined symbol", postIncrDecr.position)
}
@ -1097,7 +1097,7 @@ internal class AstChecker(private val program: Program,
}
override fun visit(arrayIndexedExpression: ArrayIndexedExpression) {
val target = arrayIndexedExpression.arrayvar.targetStatement(program.namespace)
val target = arrayIndexedExpression.arrayvar.targetStatement(program)
if(target is VarDecl) {
if(target.datatype !in IterableDatatypes)
errors.err("indexing requires an iterable variable", arrayIndexedExpression.position)
@ -1189,7 +1189,7 @@ internal class AstChecker(private val program: Program,
}
private fun checkFunctionOrLabelExists(target: IdentifierReference, statement: Statement): Statement? {
val targetStatement = target.targetStatement(program.namespace)
val targetStatement = target.targetStatement(program)
if(targetStatement is Label || targetStatement is Subroutine || targetStatement is BuiltinFunctionStatementPlaceholder)
return targetStatement
else if(targetStatement==null)
@ -1407,7 +1407,7 @@ internal class AstChecker(private val program: Program,
if(sourceDatatype==DataType.STRUCT) {
val structLv = sourceValue as ArrayLiteralValue
val numValues = structLv.value.size
val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!!
val targetstruct = target.identifier!!.targetVarDecl(program)!!.struct!!
return targetstruct.numberOfElements == numValues
}
false

View File

@ -84,7 +84,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
override fun after(arrayIndexedExpression: ArrayIndexedExpression, parent: Node): Iterable<IAstModification> {
val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program.namespace)
val arrayVar = arrayIndexedExpression.arrayvar.targetVarDecl(program)
if(arrayVar!=null && arrayVar.datatype == DataType.UWORD) {
// rewrite pointervar[index] into @(pointervar+index)
val indexer = arrayIndexedExpression.indexer
@ -142,7 +142,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
}
is IFunctionCall -> {
val argnum = parent.args.indexOf(expr)
when (val callee = parent.target.targetStatement(program.namespace)) {
when (val callee = parent.target.targetStatement(program)) {
is Subroutine -> {
val paramType = callee.parameters[argnum].type
if(leftDt isAssignableTo paramType) {
@ -315,16 +315,16 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
private fun flattenArrayAssignmentFromArrayLiteral(assign: Assignment): List<Assignment> {
val identifier = assign.target.identifier!!
val targetVar = identifier.targetVarDecl(program.namespace)!!
val targetVar = identifier.targetVarDecl(program)!!
val alv = assign.value as? ArrayLiteralValue
return flattenArrayAssign(targetVar, alv, identifier, assign.position)
}
private fun flattenArrayAssignmentFromIdentifier(assign: Assignment): List<Assignment> {
val identifier = assign.target.identifier!!
val targetVar = identifier.targetVarDecl(program.namespace)!!
val targetVar = identifier.targetVarDecl(program)!!
val sourceIdent = assign.value as IdentifierReference
val sourceVar = sourceIdent.targetVarDecl(program.namespace)!!
val sourceVar = sourceIdent.targetVarDecl(program)!!
if(!sourceVar.isArray) {
errors.err("value must be an array", sourceIdent.position)
return emptyList()
@ -354,7 +354,7 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
private fun flattenStructAssignmentFromStructLiteral(structAssignment: Assignment): List<Assignment> {
val identifier = structAssignment.target.identifier!!
val identifierName = identifier.nameInSource.single()
val targetVar = identifier.targetVarDecl(program.namespace)!!
val targetVar = identifier.targetVarDecl(program)!!
val struct = targetVar.struct!!
val slv = structAssignment.value as? ArrayLiteralValue
@ -378,11 +378,11 @@ internal class StatementReorderer(val program: Program, val errors: ErrorReporte
// TODO use memcopy beyond a certain number of elements
val identifier = structAssignment.target.identifier!!
val identifierName = identifier.nameInSource.single()
val targetVar = identifier.targetVarDecl(program.namespace)!!
val targetVar = identifier.targetVarDecl(program)!!
val struct = targetVar.struct!!
when (structAssignment.value) {
is IdentifierReference -> {
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program.namespace)!!
val sourceVar = (structAssignment.value as IdentifierReference).targetVarDecl(program)!!
when {
sourceVar.struct!=null -> {
// struct memberwise copy

View File

@ -1,7 +1,6 @@
package prog8.compiler.astprocessing
import prog8.ast.IFunctionCall
import prog8.ast.INameScope
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.base.*
@ -108,18 +107,18 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
}
override fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> {
return afterFunctionCallArgs(functionCallStatement, functionCallStatement.definingScope())
return afterFunctionCallArgs(functionCallStatement)
}
override fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
return afterFunctionCallArgs(functionCall, functionCall.definingScope())
return afterFunctionCallArgs(functionCall)
}
private fun afterFunctionCallArgs(call: IFunctionCall, scope: INameScope): Iterable<IAstModification> {
private fun afterFunctionCallArgs(call: IFunctionCall): Iterable<IAstModification> {
// see if a typecast is needed to convert the arguments into the required parameter's type
val modifications = mutableListOf<IAstModification>()
when(val sub = call.target.targetStatement(scope)) {
when(val sub = call.target.targetStatement(program)) {
is Subroutine -> {
sub.parameters.zip(call.args).forEachIndexed { index, pair ->
val argItype = pair.second.inferType(program)

View File

@ -1,7 +1,6 @@
package prog8.compiler.astprocessing
import prog8.ast.IFunctionCall
import prog8.ast.INameScope
import prog8.ast.Program
import prog8.ast.base.DataType
import prog8.ast.expressions.Expression
@ -15,13 +14,13 @@ import prog8.functions.BuiltinFunctions
class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
override fun visit(functionCall: FunctionCall) {
val error = checkTypes(functionCall as IFunctionCall, functionCall.definingScope(), program)
val error = checkTypes(functionCall as IFunctionCall, program)
if(error!=null)
throw CompilerException(error)
}
override fun visit(functionCallStatement: FunctionCallStatement) {
val error = checkTypes(functionCallStatement as IFunctionCall, functionCallStatement.definingScope(), program)
val error = checkTypes(functionCallStatement as IFunctionCall, program)
if (error!=null)
throw CompilerException(error)
}
@ -40,13 +39,13 @@ class VerifyFunctionArgTypes(val program: Program) : IAstVisitor {
return false
}
fun checkTypes(call: IFunctionCall, scope: INameScope, program: Program): String? {
fun checkTypes(call: IFunctionCall, program: Program): String? {
val argITypes = call.args.map { it.inferType(program) }
val firstUnknownDt = argITypes.indexOfFirst { it.isUnknown }
if(firstUnknownDt>=0)
return "argument ${firstUnknownDt+1} invalid argument type"
val argtypes = argITypes.map { it.typeOrElse(DataType.STRUCT) }
val target = call.target.targetStatement(scope)
val target = call.target.targetStatement(program)
if (target is Subroutine) {
if(call.args.size != target.parameters.size)
return "invalid number of arguments"

View File

@ -1,6 +1,5 @@
package prog8.compiler.target
import prog8.ast.INameScope
import prog8.ast.IStringEncoding
import prog8.ast.Program
import prog8.ast.base.*
@ -28,7 +27,7 @@ internal interface CompilationTarget: IStringEncoding {
lateinit var instance: CompilationTarget
}
fun isInRegularRAM(target: AssignTarget, namespace: INameScope): Boolean {
fun isInRegularRAM(target: AssignTarget, program: Program): Boolean {
when {
target.memoryAddress != null -> {
return when (target.memoryAddress.addressExpression) {
@ -36,7 +35,7 @@ internal interface CompilationTarget: IStringEncoding {
machine.isRegularRAMaddress((target.memoryAddress.addressExpression as NumericLiteralValue).number.toInt())
}
is IdentifierReference -> {
val decl = (target.memoryAddress.addressExpression as IdentifierReference).targetVarDecl(namespace)
val decl = (target.memoryAddress.addressExpression as IdentifierReference).targetVarDecl(program)
if ((decl?.type == VarDeclType.VAR || decl?.type == VarDeclType.CONST) && decl.value is NumericLiteralValue)
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
else
@ -46,7 +45,7 @@ internal interface CompilationTarget: IStringEncoding {
}
}
target.arrayindexed != null -> {
val targetStmt = target.arrayindexed!!.arrayvar.targetVarDecl(namespace)
val targetStmt = target.arrayindexed!!.arrayvar.targetVarDecl(program)
return if (targetStmt?.type == VarDeclType.MEMORY) {
val addr = targetStmt.value as? NumericLiteralValue
if (addr != null)
@ -56,7 +55,7 @@ internal interface CompilationTarget: IStringEncoding {
} else true
}
target.identifier != null -> {
val decl = target.identifier!!.targetVarDecl(namespace)!!
val decl = target.identifier!!.targetVarDecl(program)!!
return if (decl.type == VarDeclType.MEMORY && decl.value is NumericLiteralValue)
machine.isRegularRAMaddress((decl.value as NumericLiteralValue).number.toInt())
else

View File

@ -430,10 +430,10 @@ internal class AsmGen(private val program: Program,
"$" + it.number.toInt().toString(16).padStart(4, '0')
}
is AddressOf -> {
it.identifier.firstStructVarName(program.namespace) ?: asmSymbolName(it.identifier)
it.identifier.firstStructVarName(program) ?: asmSymbolName(it.identifier)
}
is IdentifierReference -> {
it.firstStructVarName(program.namespace) ?: asmSymbolName(it)
it.firstStructVarName(program) ?: asmSymbolName(it)
}
else -> throw AssemblyError("weird array elt dt")
}
@ -495,8 +495,8 @@ internal class AsmGen(private val program: Program,
}
internal fun asmSymbolName(identifier: IdentifierReference): String {
return if(identifier.memberOfStruct(program.namespace)!=null) {
val name = identifier.targetVarDecl(program.namespace)!!.name
return if(identifier.memberOfStruct(program)!=null) {
val name = identifier.targetVarDecl(program)!!.name
fixNameSymbols(name)
} else {
fixNameSymbols(identifier.nameInSource.joinToString("."))
@ -510,8 +510,8 @@ internal class AsmGen(private val program: Program,
throw AssemblyError("no symbol name for register $regs")
internal fun asmVariableName(identifier: IdentifierReference): String {
return if(identifier.memberOfStruct(program.namespace)!=null) {
val name = identifier.targetVarDecl(program.namespace)!!.name
return if(identifier.memberOfStruct(program)!=null) {
val name = identifier.targetVarDecl(program)!!.name
fixNameSymbols(name)
} else {
fixNameSymbols(identifier.nameInSource.joinToString("."))
@ -527,7 +527,7 @@ internal class AsmGen(private val program: Program,
internal fun loadByteFromPointerIntoA(pointervar: IdentifierReference): Pair<Boolean, String> {
// returns if the pointer is already on the ZP itself or not (in the latter case SCRATCH_W1 is used as intermediary)
val sourceName = asmVariableName(pointervar)
val vardecl = pointervar.targetVarDecl(program.namespace)!!
val vardecl = pointervar.targetVarDecl(program)!!
val scopedName = vardecl.makeScopedName(vardecl.name)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
return if (isZpVar(scopedName)) {
@ -965,7 +965,7 @@ internal class AsmGen(private val program: Program,
}
}
is IdentifierReference -> {
val vardecl = (stmt.iterations as IdentifierReference).targetStatement(program.namespace) as VarDecl
val vardecl = (stmt.iterations as IdentifierReference).targetStatement(program) as VarDecl
val name = asmVariableName(stmt.iterations as IdentifierReference)
when(vardecl.datatype) {
DataType.UBYTE, DataType.BYTE -> {
@ -1275,7 +1275,7 @@ $label nop""")
private fun getJumpTarget(jmp: Jump): String {
return when {
jmp.identifier!=null -> {
val target = jmp.identifier.targetStatement(program.namespace)
val target = jmp.identifier.targetStatement(program)
val asmName = asmSymbolName(jmp.identifier)
if(target is Label)
"_$asmName" // prefix with underscore to jump to local label
@ -1362,7 +1362,7 @@ $label nop""")
internal fun isZpVar(scopedName: String): Boolean = scopedName in allocatedZeropageVariables
internal fun isZpVar(variable: IdentifierReference): Boolean {
val vardecl = variable.targetVarDecl(program.namespace)!!
val vardecl = variable.targetVarDecl(program)!!
return vardecl.makeScopedName(vardecl.name) in allocatedZeropageVariables
}

View File

@ -71,7 +71,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
throw AssemblyError("should not discard result of memory allocation at $fcall")
val scope = fcall.definingScope()
val nameRef = fcall.args[0] as IdentifierReference
val name = (nameRef.targetVarDecl(program.namespace)!!.value as StringLiteralValue).value
val name = (nameRef.targetVarDecl(program)!!.value as StringLiteralValue).value
val size = (fcall.args[1] as NumericLiteralValue).number.toInt()
val existingSize = asmgen.slabs[name]
@ -125,7 +125,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcReverse(fcall: IFunctionCall) {
val variable = fcall.args.single()
if (variable is IdentifierReference) {
val decl = variable.targetVarDecl(program.namespace)!!
val decl = variable.targetVarDecl(program)!!
val varName = asmgen.asmVariableName(variable)
val numElements = decl.arraysize!!.constIndex()
when (decl.datatype) {
@ -164,7 +164,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun funcSort(fcall: IFunctionCall) {
val variable = fcall.args.single()
if (variable is IdentifierReference) {
val decl = variable.targetVarDecl(program.namespace)!!
val decl = variable.targetVarDecl(program)!!
val varName = asmgen.asmVariableName(variable)
val numElements = decl.arraysize!!.constIndex()
when (decl.datatype) {
@ -1108,7 +1108,7 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
// address in P8ZP_SCRATCH_W1, number of elements in A
arg as IdentifierReference
val identifierName = asmgen.asmVariableName(arg)
val size = arg.targetVarDecl(program.namespace)!!.arraysize!!.constIndex()!!
val size = arg.targetVarDecl(program)!!.arraysize!!.constIndex()!!
asmgen.out("""
lda #<$identifierName
ldy #>$identifierName

View File

@ -1327,7 +1327,7 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
private fun translateFunctionCallResultOntoStack(call: FunctionCall) {
// only for use in nested expression evaluation
val sub = call.target.targetStatement(program.namespace)
val sub = call.target.targetStatement(program)
if(sub is BuiltinFunctionStatementPlaceholder) {
val builtinFunc = BuiltinFunctions.getValue(sub.name)
asmgen.translateBuiltinFunctionCallExpression(call, builtinFunc, true, null)

View File

@ -239,7 +239,7 @@ $endLabel""")
val endLabel = asmgen.makeLabel("for_end")
asmgen.loopEndLabels.push(endLabel)
val iterableName = asmgen.asmVariableName(ident)
val decl = ident.targetVarDecl(program.namespace)!!
val decl = ident.targetVarDecl(program)!!
when(iterableDt) {
DataType.STR -> {
asmgen.out("""

View File

@ -22,7 +22,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
}
internal fun saveXbeforeCall(stmt: IFunctionCall) {
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
if(sub.shouldSaveX()) {
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA()
@ -34,7 +34,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
}
internal fun restoreXafterCall(stmt: IFunctionCall) {
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
if(sub.shouldSaveX()) {
val regSaveOnStack = sub.asmAddress==null // rom-routines don't require registers to be saved on stack, normal subroutines do because they can contain nested calls
val (keepAonEntry: Boolean, keepAonReturn: Boolean) = sub.shouldKeepA()
@ -52,7 +52,7 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
// NOTE: does NOT output code to save/restore the X register for this call! Every caller should deal with this in their own way!!
// (you can use subroutine.shouldSaveX() and saveX()/restoreX() routines as a help for this)
val sub = stmt.target.targetSubroutine(program.namespace) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
val sub = stmt.target.targetSubroutine(program) ?: throw AssemblyError("undefined subroutine ${stmt.target}")
val subName = asmgen.asmSymbolName(stmt.target)
if(stmt.args.isNotEmpty()) {

View File

@ -157,7 +157,7 @@ internal class AsmAssignSource(val kind: SourceStorageKind,
AsmAssignSource(SourceStorageKind.ARRAY, program, asmgen, dt, array = value)
}
is FunctionCall -> {
when (val sub = value.target.targetStatement(program.namespace)) {
when (val sub = value.target.targetStatement(program)) {
is Subroutine -> {
val returnType = sub.returntypes.zip(sub.asmReturnvaluesRegisters).firstOrNull { rr -> rr.second.registerOrPair != null || rr.second.statusflag!=null }?.first
?: throw AssemblyError("can't translate zero return values in assignment")

View File

@ -143,7 +143,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
SourceStorageKind.EXPRESSION -> {
when(val value = assign.source.expression!!) {
is AddressOf -> {
val sourceName = value.identifier.firstStructVarName(program.namespace) ?: asmgen.asmVariableName(value.identifier)
val sourceName = value.identifier.firstStructVarName(program) ?: asmgen.asmVariableName(value.identifier)
assignAddressOf(assign.target, sourceName)
}
is NumericLiteralValue -> throw AssemblyError("source kind should have been literalnumber")
@ -152,7 +152,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
is DirectMemoryRead -> throw AssemblyError("source kind should have been memory")
is TypecastExpression -> assignTypeCastedValue(assign.target, value.type, value.expression, value)
is FunctionCall -> {
when (val sub = value.target.targetStatement(program.namespace)) {
when (val sub = value.target.targetStatement(program)) {
is Subroutine -> {
asmgen.saveXbeforeCall(value)
asmgen.translateFunctionCall(value)
@ -2061,7 +2061,7 @@ internal class AssignmentAsmGen(private val program: Program, private val asmgen
fun storeAIntoPointerVar(pointervar: IdentifierReference) {
val sourceName = asmgen.asmVariableName(pointervar)
val vardecl = pointervar.targetVarDecl(program.namespace)!!
val vardecl = pointervar.targetVarDecl(program)!!
val scopedName = vardecl.makeScopedName(vardecl.name)
if (CompilationTarget.instance.machine.cpu == CpuType.CPU65c02) {
if (asmgen.isZpVar(scopedName)) {

View File

@ -986,7 +986,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
private fun inplaceModification_word_variable_to_variable(name: String, dt: DataType, operator: String, ident: IdentifierReference) {
val otherName = asmgen.asmVariableName(ident)
val valueDt = ident.targetVarDecl(program.namespace)!!.datatype
val valueDt = ident.targetVarDecl(program)!!.datatype
when (valueDt) {
in ByteDatatypes -> {
// the other variable is a BYTE type so optimize for that
@ -1467,7 +1467,7 @@ internal class AugmentableAssignmentAsmGen(private val program: Program,
}
private fun inplaceModification_float_variable_to_variable(name: String, operator: String, ident: IdentifierReference, scope: Subroutine) {
val valueDt = ident.targetVarDecl(program.namespace)!!.datatype
val valueDt = ident.targetVarDecl(program)!!.datatype
if(valueDt != DataType.FLOAT)
throw AssemblyError("float variable expected")

View File

@ -287,7 +287,7 @@ private fun builtinOffsetof(args: List<Expression>, position: Position, program:
val idref = args[0] as? IdentifierReference
?: throw SyntaxError("offsetof argument should be an identifier", position)
val vardecl = idref.targetVarDecl(program.namespace)!!
val vardecl = idref.targetVarDecl(program)!!
val struct = vardecl.struct
if (struct == null || vardecl.datatype == DataType.STRUCT)
throw SyntaxError("offsetof can only be used on struct members", position)
@ -311,7 +311,7 @@ private fun builtinSizeof(args: List<Expression>, position: Position, program: P
val dt = args[0].inferType(program)
if(dt.isKnown) {
val target = (args[0] as IdentifierReference).targetStatement(program.namespace)
val target = (args[0] as IdentifierReference).targetStatement(program)
?: throw CannotEvaluateException("sizeof", "no target")
fun structSize(target: StructDecl) =
@ -343,7 +343,7 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
if(args.size!=1)
throw SyntaxError("len requires one argument", position)
val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(program.namespace)
val directMemVar = ((args[0] as? DirectMemoryRead)?.addressExpression as? IdentifierReference)?.targetVarDecl(program)
var arraySize = directMemVar?.arraysize?.constIndex()
if(arraySize != null)
return NumericLiteralValue.optimalInteger(arraySize, position)
@ -351,7 +351,7 @@ private fun builtinLen(args: List<Expression>, position: Position, program: Prog
return NumericLiteralValue.optimalInteger((args[0] as ArrayLiteralValue).value.size, position)
if(args[0] !is IdentifierReference)
throw SyntaxError("len argument should be an identifier", position)
val target = (args[0] as IdentifierReference).targetVarDecl(program.namespace)
val target = (args[0] as IdentifierReference).targetVarDecl(program)
?: throw CannotEvaluateException("len", "no target vardecl")
return when(target.datatype) {

View File

@ -1,6 +1,5 @@
package prog8.optimizer
import prog8.ast.INameScope
import prog8.ast.Node
import prog8.ast.Program
import prog8.ast.expressions.*
@ -54,7 +53,7 @@ X = BinExpr X = LeftExpr
*/
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program.namespace)) {
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program)) {
if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right)
return noModifications
@ -79,9 +78,9 @@ X = BinExpr X = LeftExpr
private fun isSimpleExpression(expr: Expression) =
expr is IdentifierReference || expr is NumericLiteralValue || expr is AddressOf || expr is DirectMemoryRead || expr is StringLiteralValue || expr is ArrayLiteralValue || expr is RangeExpr
private fun isSimpleTarget(target: AssignTarget, namespace: INameScope) =
private fun isSimpleTarget(target: AssignTarget, program: Program) =
if (target.identifier!=null || target.memoryAddress!=null)
CompilationTarget.instance.isInRegularRAM(target, namespace)
CompilationTarget.instance.isInRegularRAM(target, program)
else
false

View File

@ -89,7 +89,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
override fun visit(identifier: IdentifierReference) {
// track symbol usage
val target = identifier.targetStatement(this.program.namespace)
val target = identifier.targetStatement(program)
if (target != null) {
addNodeAndParentScopes(target)
}
@ -126,7 +126,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
override fun visit(functionCall: FunctionCall) {
val otherSub = functionCall.target.targetSubroutine(program.namespace)
val otherSub = functionCall.target.targetSubroutine(program)
if (otherSub != null) {
functionCall.definingSubroutine()?.let { thisSub ->
calls[thisSub] = calls.getValue(thisSub).plus(otherSub)
@ -137,7 +137,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
override fun visit(functionCallStatement: FunctionCallStatement) {
val otherSub = functionCallStatement.target.targetSubroutine(program.namespace)
val otherSub = functionCallStatement.target.targetSubroutine(program)
if (otherSub != null) {
functionCallStatement.definingSubroutine()?.let { thisSub ->
calls[thisSub] = calls.getValue(thisSub).plus(otherSub)
@ -148,7 +148,7 @@ class CallGraph(private val program: Program) : IAstVisitor {
}
override fun visit(jump: Jump) {
val otherSub = jump.identifier?.targetSubroutine(program.namespace)
val otherSub = jump.identifier?.targetSubroutine(program)
if (otherSub != null) {
jump.definingSubroutine()?.let { thisSub ->
calls[thisSub] = calls.getValue(thisSub).plus(otherSub)

View File

@ -231,7 +231,7 @@ internal class ConstantFoldingOptimizer(private val program: Program) : AstWalke
val rangeTo = iterableRange.to as? NumericLiteralValue
if(rangeFrom==null || rangeTo==null) return noModifications
val loopvar = forLoop.loopVar.targetVarDecl(program.namespace) ?: throw UndefinedSymbolError(forLoop.loopVar)
val loopvar = forLoop.loopVar.targetVarDecl(program) ?: throw UndefinedSymbolError(forLoop.loopVar)
val stepLiteral = iterableRange.step as? NumericLiteralValue
when(loopvar.datatype) {

View File

@ -89,7 +89,7 @@ internal class StatementOptimizer(private val program: Program,
arg as? IdentifierReference
}
if(stringVar!=null) {
val vardecl = stringVar.targetVarDecl(program.namespace)!!
val vardecl = stringVar.targetVarDecl(program)!!
val string = vardecl.value as? StringLiteralValue
if(string!=null) {
val pos = functionCallStatement.position
@ -123,7 +123,7 @@ internal class StatementOptimizer(private val program: Program,
}
// if the first instruction in the called subroutine is a return statement, remove the jump altogeter
val subroutine = functionCallStatement.target.targetSubroutine(program.namespace)
val subroutine = functionCallStatement.target.targetSubroutine(program)
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Return)
@ -135,7 +135,7 @@ internal class StatementOptimizer(private val program: Program,
override fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> {
// if the first instruction in the called subroutine is a return statement with constant value, replace with the constant value
val subroutine = functionCall.target.targetSubroutine(program.namespace)
val subroutine = functionCall.target.targetSubroutine(program)
if(subroutine!=null) {
val first = subroutine.statements.asSequence().filterNot { it is VarDecl || it is Directive }.firstOrNull()
if(first is Return && first.value!=null) {
@ -203,7 +203,7 @@ internal class StatementOptimizer(private val program: Program,
return listOf(IAstModification.ReplaceNode(forLoop, scope, parent))
}
}
val iterable = (forLoop.iterable as? IdentifierReference)?.targetVarDecl(program.namespace)
val iterable = (forLoop.iterable as? IdentifierReference)?.targetVarDecl(program)
if(iterable!=null) {
if(iterable.datatype==DataType.STR) {
val sv = iterable.value as StringLiteralValue
@ -306,7 +306,7 @@ internal class StatementOptimizer(private val program: Program,
override fun after(jump: Jump, parent: Node): Iterable<IAstModification> {
// if the jump is to the next statement, remove the jump
val scope = jump.definingScope()
val label = jump.identifier?.targetStatement(scope)
val label = jump.identifier?.targetStatement(program)
if(label!=null && scope.statements.indexOf(label) == scope.statements.indexOf(jump)+1)
return listOf(IAstModification.Remove(jump, jump.definingScope()))
@ -390,7 +390,7 @@ internal class StatementOptimizer(private val program: Program,
// assignments of the form: X = X <operator> <expr>
// remove assignments that have no effect (such as X=X+0)
// optimize/rewrite some other expressions
val vardeclDt = (assignment.target.identifier?.targetVarDecl(program.namespace))?.type
val vardeclDt = (assignment.target.identifier?.targetVarDecl(program))?.type
when (bexpr.operator) {
"+" -> {
if (rightCv == 0.0) {

View File

@ -93,7 +93,7 @@ internal class UnusedCodeRemover(private val program: Program, private val error
val assign1 = stmtPairs[0] as? Assignment
val assign2 = stmtPairs[1] as? Assignment
if (assign1 != null && assign2 != null && !assign2.isAugmentable) {
if (assign1.target.isSameAs(assign2.target, program) && CompilationTarget.instance.isInRegularRAM(assign1.target, program.namespace)) {
if (assign1.target.isSameAs(assign2.target, program) && CompilationTarget.instance.isInRegularRAM(assign1.target, program)) {
if(assign2.target.identifier==null || !assign2.value.referencesIdentifier(*(assign2.target.identifier!!.nameInSource.toTypedArray())))
// only remove the second assignment if its value is a simple expression!
when(assign2.value) {

View File

@ -5,6 +5,9 @@ import org.hamcrest.Matchers.closeTo
import org.hamcrest.Matchers.equalTo
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import prog8.ast.IBuiltinFunctions
import prog8.ast.Program
import prog8.ast.Module
import prog8.ast.base.*
import prog8.ast.expressions.*
import prog8.ast.statements.*
@ -19,6 +22,7 @@ import prog8.compiler.target.c64.C64MachineDefinition.Mflpt5
import prog8.compiler.target.c64.Petscii
import prog8.compiler.target.cx16.CX16MachineDefinition
import java.io.CharConversionException
import java.nio.file.Path
import kotlin.test.*
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
@ -402,34 +406,36 @@ class TestPetscii {
class TestMemory {
private class DummyFunctions: IBuiltinFunctions {
override val names: Set<String> = emptySet()
override fun constValue(name: String, args: List<Expression>, position: Position): NumericLiteralValue? = null
override fun returnType(name: String, args: MutableList<Expression>) = InferredTypes.InferredType.unknown()
}
@Test
fun testInValidRamC64_memory_addresses() {
CompilationTarget.instance = C64Target
var memexpr = NumericLiteralValue.optimalInteger(0x0000, Position.DUMMY)
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
var scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope))
val program = Program("test", mutableListOf(), DummyFunctions())
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope))
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0x9fff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope))
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0xc000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope))
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0xcfff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, scope))
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -438,38 +444,37 @@ class TestMemory {
var memexpr = NumericLiteralValue.optimalInteger(0xa000, Position.DUMMY)
var target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
var scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope))
val program = Program("test", mutableListOf(), DummyFunctions())
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0xafff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope))
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0xd000, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope))
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
memexpr = NumericLiteralValue.optimalInteger(0xffff, Position.DUMMY)
target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope))
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
fun testInValidRamC64_memory_identifiers() {
CompilationTarget.instance = C64Target
var target = createTestProgramForMemoryRefViaVar(0x1000, VarDeclType.VAR)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val program = Program("test", mutableListOf(), DummyFunctions())
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
target = createTestProgramForMemoryRefViaVar(0xd020, VarDeclType.VAR)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
target = createTestProgramForMemoryRefViaVar(0x1000, VarDeclType.CONST)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
target = createTestProgramForMemoryRefViaVar(0xd020, VarDeclType.CONST)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
target = createTestProgramForMemoryRefViaVar(0x1000, VarDeclType.MEMORY)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -479,7 +484,8 @@ class TestMemory {
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
module.linkParents(ParentSentinel)
return target
}
@ -488,8 +494,8 @@ class TestMemory {
CompilationTarget.instance = C64Target
val memexpr = PrefixExpression("+", NumericLiteralValue.optimalInteger(0x1000, Position.DUMMY), Position.DUMMY)
val target = AssignTarget(null, null, DirectMemoryWrite(memexpr, Position.DUMMY), Position.DUMMY)
val scope = AnonymousScope(mutableListOf(), Position.DUMMY)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, scope))
val program = Program("test", mutableListOf(), DummyFunctions())
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -499,8 +505,10 @@ class TestMemory {
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions())
module.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -511,8 +519,10 @@ class TestMemory {
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions())
module.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -523,8 +533,10 @@ class TestMemory {
val target = AssignTarget(IdentifierReference(listOf("address"), Position.DUMMY), null, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions())
module.linkParents(ParentSentinel)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -535,8 +547,10 @@ class TestMemory {
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions())
module.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -548,8 +562,10 @@ class TestMemory {
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions())
module.linkParents(ParentSentinel)
assertTrue(CompilationTarget.instance.isInRegularRAM(target, program))
}
@Test
@ -561,7 +577,9 @@ class TestMemory {
val target = AssignTarget(null, arrayindexed, null, Position.DUMMY)
val assignment = Assignment(target, NumericLiteralValue.optimalInteger(0, Position.DUMMY), Position.DUMMY)
val subroutine = Subroutine("test", emptyList(), emptyList(), emptyList(), emptyList(), emptySet(), null, false, false, mutableListOf(decl, assignment), Position.DUMMY)
subroutine.linkParents(ParentSentinel)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, target.definingScope()))
val module = Module("test", mutableListOf(subroutine), Position.DUMMY, false, Path.of(""))
val program = Program("test", mutableListOf(module), DummyFunctions())
module.linkParents(ParentSentinel)
assertFalse(CompilationTarget.instance.isInRegularRAM(target, program))
}
}