diff --git a/compiler/src/prog8/CompilerMain.kt b/compiler/src/prog8/CompilerMain.kt index 25dc5d8a5..49fadc35e 100644 --- a/compiler/src/prog8/CompilerMain.kt +++ b/compiler/src/prog8/CompilerMain.kt @@ -77,7 +77,7 @@ private fun compileMain(args: Array) { val event = watchservice.take() for(changed in event.pollEvents()) { val changedPath = changed.context() as Path - println(" change detected: ${changedPath}") + println(" change detected: $changedPath") } event.reset() println("\u001b[H\u001b[2J") // clear the screen diff --git a/compiler/src/prog8/ast/AstToSourceCode.kt b/compiler/src/prog8/ast/AstToSourceCode.kt index dd7bbf48d..0c83ac01d 100644 --- a/compiler/src/prog8/ast/AstToSourceCode.kt +++ b/compiler/src/prog8/ast/AstToSourceCode.kt @@ -132,7 +132,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) { val reg = when { - true==param.second.stack -> "stack" + param.second.stack -> "stack" param.second.registerOrPair!=null -> param.second.registerOrPair.toString() param.second.statusflag!=null -> param.second.statusflag.toString() else -> "?????1" @@ -256,15 +256,12 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program): output(numLiteral.number.toString()) } - override fun visit(refLiteral: ReferenceLiteralValue) { - when { - refLiteral.isString -> output("\"${escape(refLiteral.str!!)}\"") - refLiteral.isArray -> { - if(refLiteral.array!=null) { - outputListMembers(refLiteral.array.asSequence(), '[', ']') - } - } - } + override fun visit(string: StringLiteralValue) { + output("\"${escape(string.value)}\"") + } + + override fun visit(array: ArrayLiteralValue) { + outputListMembers(array.value.asSequence(), '[', ']') } private fun outputListMembers(array: Sequence, openchar: Char, closechar: Char) { diff --git a/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt b/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt index 215d93f9b..78fba3971 100644 --- a/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt +++ b/compiler/src/prog8/ast/antlr/Antr2Kotlin.kt @@ -429,7 +429,7 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression { else -> throw FatalAstException("invalid datatype for numeric literal") } litval.floatliteral()!=null -> NumericLiteralValue(DataType.FLOAT, litval.floatliteral().toAst(), litval.toPosition()) - litval.stringliteral()!=null -> ReferenceLiteralValue(DataType.STR, unescape(litval.stringliteral().text, litval.toPosition()), position = litval.toPosition()) + litval.stringliteral()!=null -> StringLiteralValue(DataType.STR, unescape(litval.stringliteral().text, litval.toPosition()), position = litval.toPosition()) litval.charliteral()!=null -> { try { NumericLiteralValue(DataType.UBYTE, Petscii.encodePetscii(unescape(litval.charliteral().text, litval.toPosition()), true)[0], litval.toPosition()) @@ -438,10 +438,10 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression { } } litval.arrayliteral()!=null -> { - val array = litval.arrayliteral()?.toAst() + val array = litval.arrayliteral().toAst() // the actual type of the arraysize can not yet be determined here (missing namespace & heap) // the ConstantFold takes care of that and converts the type if needed. - ReferenceLiteralValue(DataType.ARRAY_UB, array = array, position = litval.toPosition()) + ArrayLiteralValue(DataType.ARRAY_UB, array, position = litval.toPosition()) } litval.structliteral()!=null -> { val values = litval.structliteral().expression().map { it.toAst() } @@ -596,10 +596,10 @@ private fun prog8Parser.WhenstmtContext.toAst(): WhenStatement { private fun prog8Parser.When_choiceContext.toAst(): WhenChoice { val values = expression_list()?.toAst() val stmt = statement()?.toAst() - val stmt_block = statement_block()?.toAst()?.toMutableList() ?: mutableListOf() + val stmtBlock = statement_block()?.toAst()?.toMutableList() ?: mutableListOf() if(stmt!=null) - stmt_block.add(stmt) - val scope = AnonymousScope(stmt_block, toPosition()) + stmtBlock.add(stmt) + val scope = AnonymousScope(stmtBlock, toPosition()) return WhenChoice(values, scope, toPosition()) } diff --git a/compiler/src/prog8/ast/expressions/AstExpressions.kt b/compiler/src/prog8/ast/expressions/AstExpressions.kt index bbf9419d7..c932172af 100644 --- a/compiler/src/prog8/ast/expressions/AstExpressions.kt +++ b/compiler/src/prog8/ast/expressions/AstExpressions.kt @@ -406,119 +406,98 @@ class StructLiteralValue(var values: List, } } -class ReferenceLiteralValue(val type: DataType, // only reference types allowed here - val str: String? = null, - val array: Array? = null, - initHeapId: Int? =null, - override val position: Position) : Expression() { +class StringLiteralValue(val type: DataType, // only string types + val value: String, + initHeapId: Int? =null, + override val position: Position) : Expression() { override lateinit var parent: Node - override fun referencesIdentifiers(vararg name: String) = array?.any { it.referencesIdentifiers(*name) } ?: false - - val isString = type in StringDatatypes - val isArray = type in ArrayDatatypes var heapId = initHeapId private set - init { - when(type){ - in StringDatatypes -> - if(str==null) throw FatalAstException("literal value missing strvalue/heapId") - in ArrayDatatypes -> - if(array==null) throw FatalAstException("literal value missing arrayvalue/heapId") - else -> throw FatalAstException("invalid type $type") - } - if(array==null && str==null) - throw FatalAstException("literal ref value without actual value") + override fun linkParents(parent: Node) { + this.parent = parent } + override fun referencesIdentifiers(vararg name: String) = false + override fun constValue(program: Program): NumericLiteralValue? = null + override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) + override fun accept(visitor: IAstVisitor) = visitor.visit(this) + override fun toString(): String = "'${escape(value)}'" + override fun inferType(program: Program) = type + operator fun compareTo(other: StringLiteralValue): Int = value.compareTo(other.value) + override fun hashCode(): Int = Objects.hash(value, type) + override fun equals(other: Any?): Boolean { + if(other==null || other !is StringLiteralValue) + return false + return value==other.value && type==other.type + } + + fun addToHeap(heap: HeapValues) { + if (heapId != null) + return + else + heapId = heap.addString(type, value) + } +} + +class ArrayLiteralValue(val type: DataType, // only array types + val value: Array, + initHeapId: Int? =null, + override val position: Position) : Expression() { + override lateinit var parent: Node + + var heapId = initHeapId + private set override fun linkParents(parent: Node) { this.parent = parent - array?.forEach {it.linkParents(this)} + value.forEach {it.linkParents(this)} } - - override fun constValue(program: Program): NumericLiteralValue? { - // note that we can't handle arrays that only contain constant numbers here anymore - // so they're not treated as constants anymore - return null - } - + override fun referencesIdentifiers(vararg name: String) = value.any { it.referencesIdentifiers(*name) } + override fun constValue(program: Program): NumericLiteralValue? = null override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this) override fun accept(visitor: IAstVisitor) = visitor.visit(this) - - override fun toString(): String { - val valueStr = when(type) { - in StringDatatypes -> "'${escape(str!!)}'" - in ArrayDatatypes -> "$array" - else -> throw FatalAstException("weird ref type") - } - return "RefValueLit($type, $valueStr)" - } - + override fun toString(): String = "$value" override fun inferType(program: Program) = type - - override fun hashCode(): Int = Objects.hash(str, array, type) - + operator fun compareTo(other: ArrayLiteralValue): Int = throw ExpressionError("cannot order compare arrays", position) + override fun hashCode(): Int = Objects.hash(value, type) override fun equals(other: Any?): Boolean { - if(other==null || other !is ReferenceLiteralValue) + if(other==null || other !is ArrayLiteralValue) return false - if(isArray && other.isArray) - return array!!.contentEquals(other.array!!) && heapId==other.heapId - if(isString && other.isString) - return str==other.str && heapId==other.heapId - - if(type!=other.type) - return false - - return compareTo(other) == 0 + return type==other.type && value.contentEquals(other.value) } - operator fun compareTo(other: ReferenceLiteralValue): Int { - throw ExpressionError("cannot order compare type $type with ${other.type}", other.position) - } - - fun cast(targettype: DataType): ReferenceLiteralValue? { + fun cast(targettype: DataType): ArrayLiteralValue? { if(type==targettype) return this - when(type) { - in StringDatatypes -> { - if(targettype in StringDatatypes) - return ReferenceLiteralValue(targettype, str, position = position) - } - in ArrayDatatypes -> { - if(targettype in ArrayDatatypes) { - val elementType = ArrayElementTypes.getValue(targettype) - val castArray = array!!.map{ - val num = it as? NumericLiteralValue - if(num==null) { - // an array of UWORDs could possibly also contain AddressOfs - if (elementType != DataType.UWORD || it !is AddressOf) - throw FatalAstException("weird array element $it") - it - } else { - try { - num.cast(elementType) - } catch(x: ExpressionError) { - return null - } - } - }.toTypedArray() - return ReferenceLiteralValue(targettype, null, array=castArray, position = position) + if(targettype in ArrayDatatypes) { + val elementType = ArrayElementTypes.getValue(targettype) + val castArray = value.map{ + val num = it as? NumericLiteralValue + if(num==null) { + // an array of UWORDs could possibly also contain AddressOfs + if (elementType != DataType.UWORD || it !is AddressOf) + throw FatalAstException("weird array element $it") + it + } else { + try { + num.cast(elementType) + } catch(x: ExpressionError) { + return null + } } - } - else -> {} + }.toTypedArray() + return ArrayLiteralValue(targettype, castArray, position = position) } return null // invalid type conversion from $this to $targettype } fun addToHeap(heap: HeapValues) { - if (heapId != null) return - if (str != null) { - heapId = heap.addString(type, str) - } - else if (array!=null) { - if(array.any {it is AddressOf }) { - val intArrayWithAddressOfs = array.map { + if (heapId != null) + return + else { + if(value.any {it is AddressOf }) { + val intArrayWithAddressOfs = value.map { when (it) { is AddressOf -> IntegerOrAddressOf(null, it) is NumericLiteralValue -> IntegerOrAddressOf(it.number.toInt(), null) @@ -527,7 +506,7 @@ class ReferenceLiteralValue(val type: DataType, // only reference types allo } heapId = heap.addIntegerArray(type, intArrayWithAddressOfs.toTypedArray()) } else { - val valuesInArray = array.map { (it as? NumericLiteralValue)?.number } + val valuesInArray = value.map { (it as? NumericLiteralValue)?.number } if(null !in valuesInArray) { heapId = if (type == DataType.ARRAY_F) { val doubleArray = valuesInArray.map { it!!.toDouble() }.toDoubleArray() @@ -588,12 +567,12 @@ class RangeExpr(var from: Expression, fun toConstantIntegerRange(): IntProgression? { val fromVal: Int val toVal: Int - val fromRlv = from as? ReferenceLiteralValue - val toRlv = to as? ReferenceLiteralValue - if(fromRlv!=null && fromRlv.isString && toRlv!=null && toRlv.isString) { + val fromString = from as? StringLiteralValue + val toString = to as? StringLiteralValue + if(fromString!=null && toString!=null ) { // string range -> int range over petscii values - fromVal = Petscii.encodePetscii(fromRlv.str!!, true)[0].toInt() - toVal = Petscii.encodePetscii(toRlv.str!!, true)[0].toInt() + fromVal = Petscii.encodePetscii(fromString.value, true)[0].toInt() + toVal = Petscii.encodePetscii(toString.value, true)[0].toInt() } else { val fromLv = from as? NumericLiteralValue val toLv = to as? NumericLiteralValue @@ -689,17 +668,11 @@ data class IdentifierReference(val nameInSource: List, override val posi val value = (node as? VarDecl)?.value ?: throw FatalAstException("requires a reference value") return when (value) { is IdentifierReference -> value.heapId(namespace) - is ReferenceLiteralValue -> value.heapId ?: throw FatalAstException("refLv is not on the heap: $value") + is StringLiteralValue -> value.heapId ?: throw FatalAstException("string is not on the heap: $value") + is ArrayLiteralValue -> value.heapId ?: throw FatalAstException("array is not on the heap: $value") else -> throw FatalAstException("requires a reference value") } } - - fun withPrefixedName(nameprefix: String): IdentifierReference { - val prefixed = nameInSource.dropLast(1) + listOf(nameprefix+nameInSource.last()) - val new = IdentifierReference(prefixed, position) - new.parent = parent - return new - } } class FunctionCall(override var target: IdentifierReference, diff --git a/compiler/src/prog8/ast/processing/AstChecker.kt b/compiler/src/prog8/ast/processing/AstChecker.kt index c347df79f..99173d554 100644 --- a/compiler/src/prog8/ast/processing/AstChecker.kt +++ b/compiler/src/prog8/ast/processing/AstChecker.kt @@ -7,7 +7,6 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.statements.* import prog8.compiler.CompilationOptions -import prog8.compiler.HeapValues import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE import prog8.functions.BuiltinFunctions @@ -526,14 +525,12 @@ internal class AstChecker(private val program: Program, } when(decl.value) { is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value") - is ReferenceLiteralValue -> { - val arraySpec = decl.arraysize ?: ( - if((decl.value as ReferenceLiteralValue).isArray) - ArrayIndex.forArray(decl.value as ReferenceLiteralValue, program.heap) - else - ArrayIndex(NumericLiteralValue.optimalInteger(-2, decl.position), decl.position) - ) - checkValueTypeAndRange(decl.datatype, decl.struct, arraySpec, decl.value as ReferenceLiteralValue, program.heap) + is StringLiteralValue -> { + checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue) + } + is ArrayLiteralValue -> { + val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue) + checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue) } is NumericLiteralValue -> { checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue) @@ -682,30 +679,24 @@ internal class AstChecker(private val program: Program, checkResult.add(NameError("included file not found: $filename", directive.position)) } - override fun visit(refLiteral: ReferenceLiteralValue) { - if(!compilerOptions.floats && refLiteral.type in setOf(DataType.FLOAT, DataType.ARRAY_F)) { - checkResult.add(SyntaxError("floating point used, but that is not enabled via options", refLiteral.position)) + override fun visit(array: ArrayLiteralValue) { + if(!compilerOptions.floats && array.type in setOf(DataType.FLOAT, DataType.ARRAY_F)) { + checkResult.add(SyntaxError("floating point used, but that is not enabled via options", array.position)) } - val arrayspec = - if(refLiteral.isArray) - ArrayIndex.forArray(refLiteral, program.heap) - else - ArrayIndex(NumericLiteralValue.optimalInteger(-3, refLiteral.position), refLiteral.position) - checkValueTypeAndRange(refLiteral.type, null, arrayspec, refLiteral, program.heap) + val arrayspec = ArrayIndex.forArray(array) + checkValueTypeAndRangeArray(array.type, null, arrayspec, array) - super.visit(refLiteral) + super.visit(array) - when(refLiteral.type) { - in StringDatatypes -> { - if(refLiteral.heapId==null) - throw FatalAstException("string should have been moved to heap at ${refLiteral.position}") - } - in ArrayDatatypes -> { - if(refLiteral.heapId==null) - throw FatalAstException("array should have been moved to heap at ${refLiteral.position}") - } - else -> {} - } + if(array.heapId==null) + throw FatalAstException("array should have been moved to heap at ${array.position}") + } + + override fun visit(string: StringLiteralValue) { + checkValueTypeAndRangeString(string.type, string) + super.visit(string) + if(string.heapId==null) + throw FatalAstException("string should have been moved to heap at ${string.position}") } override fun visit(expr: PrefixExpression) { @@ -956,9 +947,9 @@ internal class AstChecker(private val program: Program, if(index!=null && (index<0 || index>=arraysize)) checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position)) } else if(target.datatype in StringDatatypes) { - if(target.value is ReferenceLiteralValue) { + if(target.value is StringLiteralValue) { // check string lengths for non-memory mapped strings - val heapId = (target.value as ReferenceLiteralValue).heapId!! + val heapId = (target.value as StringLiteralValue).heapId!! val stringLen = program.heap.get(heapId).str!!.length val index = (arrayIndexedExpression.arrayspec.index as? NumericLiteralValue)?.number?.toInt() if (index != null && (index < 0 || index >= stringLen)) @@ -1037,26 +1028,37 @@ internal class AstChecker(private val program: Program, return null } - private fun checkValueTypeAndRange(targetDt: DataType, struct: StructDecl?, - arrayspec: ArrayIndex, value: ReferenceLiteralValue, heap: HeapValues) : Boolean { + private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteralValue) : Boolean { + fun err(msg: String): Boolean { + checkResult.add(ExpressionError(msg, value.position)) + return false + } + return when (targetDt) { + in StringDatatypes -> { + return if (value.value.length > 255) + err("string length must be 0-255") + else + true + } + else -> false + } + } + + private fun checkValueTypeAndRangeArray(targetDt: DataType, struct: StructDecl?, + arrayspec: ArrayIndex, value: ArrayLiteralValue) : Boolean { fun err(msg: String) : Boolean { checkResult.add(ExpressionError(msg, value.position)) return false } when (targetDt) { - in StringDatatypes -> { - if(!value.isString) - return err("string value expected") - if (value.str!!.length > 255) - return err("string length must be 0-255") - } + in StringDatatypes -> return err("string value expected") DataType.ARRAY_UB, DataType.ARRAY_B -> { // value may be either a single byte, or a byte arraysize (of all constant values), or a range if(value.type==targetDt) { if(!checkArrayValues(value, targetDt)) return false val arraySpecSize = arrayspec.size() - val arraySize = value.array?.size ?: heap.get(value.heapId!!).arraysize + val arraySize = value.value.size if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize<1 || arraySpecSize>256) return err("byte array length must be 1-256") @@ -1078,7 +1080,7 @@ internal class AstChecker(private val program: Program, if(!checkArrayValues(value, targetDt)) return false val arraySpecSize = arrayspec.size() - val arraySize = value.array?.size ?: heap.get(value.heapId!!).arraysize + val arraySize = value.value.size if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize<1 || arraySpecSize>128) return err("word array length must be 1-128") @@ -1099,7 +1101,7 @@ internal class AstChecker(private val program: Program, if(value.type==targetDt) { if(!checkArrayValues(value, targetDt)) return false - val arraySize = value.array?.size ?: heap.get(value.heapId!!).doubleArray!!.size + val arraySize = value.value.size val arraySpecSize = arrayspec.size() if(arraySpecSize!=null && arraySpecSize>0) { if(arraySpecSize < 1 || arraySpecSize>51) @@ -1114,10 +1116,7 @@ internal class AstChecker(private val program: Program, return err("invalid float array size, must be 1-51") // check if the floating point values are all within range - val doubles = if(value.array!=null) - value.array.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() - else - heap.get(value.heapId!!).doubleArray!! + val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray() if(doubles.any { it < FLOAT_MAX_NEGATIVE || it> FLOAT_MAX_POSITIVE }) return err("floating point value overflow") return true @@ -1126,9 +1125,9 @@ internal class AstChecker(private val program: Program, } DataType.STRUCT -> { if(value.type in ArrayDatatypes) { - if(value.array!!.size != struct!!.numberOfElements) + if(value.value.size != struct!!.numberOfElements) return err("number of values is not the same as the number of members in the struct") - for(elt in value.array.zip(struct.statements)) { + for(elt in value.value.zip(struct.statements)) { val vardecl = elt.second as VarDecl val valuetype = elt.first.inferType(program)!! if (!(valuetype isAssignableTo vardecl.datatype)) { @@ -1142,7 +1141,6 @@ internal class AstChecker(private val program: Program, } else -> return false } - return true } private fun checkValueTypeAndRange(targetDt: DataType, value: NumericLiteralValue) : Boolean { @@ -1189,10 +1187,10 @@ internal class AstChecker(private val program: Program, return true } - private fun checkArrayValues(value: ReferenceLiteralValue, type: DataType): Boolean { - if(value.isArray && value.heapId==null) { + private fun checkArrayValues(value: ArrayLiteralValue, type: DataType): Boolean { + if(value.heapId==null) { // hmm weird, array literal that hasn't been moved to the heap yet? - val array = value.array!!.map { it.constValue(program)!! } + val array = value.value.map { it.constValue(program)!! } val correct: Boolean when(type) { DataType.ARRAY_UB -> { diff --git a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt index b23b64d78..c32ced96f 100644 --- a/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt +++ b/compiler/src/prog8/ast/processing/AstIdentifiersChecker.kt @@ -247,75 +247,83 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi return super.visit(returnStmt) } - override fun visit(refLiteral: ReferenceLiteralValue): Expression { - val litval = super.visit(refLiteral) - if(litval is ReferenceLiteralValue) { - val vardecl = litval.parent as? VarDecl - if (litval.isString) { - // intern the string; move it into the heap - if (litval.str!!.length !in 1..255) - checkResult.add(ExpressionError("string literal length must be between 1 and 255", litval.position)) - else { - litval.addToHeap(program.heap) - } - return if(vardecl!=null) - litval - else - makeIdentifierFromRefLv(litval) // replace the literal string by a identifier reference. - } else if (litval.isArray) { - if (vardecl!=null) { - return fixupArrayDatatype(litval, vardecl, program.heap) - } else { - // fix the datatype of the array (also on the heap) to the 'biggest' datatype in the array - // (we don't know the desired datatype here exactly so we guess) - val datatype = determineArrayDt(litval.array!!) ?: return litval - val litval2 = litval.cast(datatype)!! - litval2.parent = litval.parent - // finally, replace the literal array by a identifier reference. - return makeIdentifierFromRefLv(litval2) - } + override fun visit(arrayLiteral: ArrayLiteralValue): Expression { + val array = super.visit(arrayLiteral) + if(array is ArrayLiteralValue) { + val vardecl = array.parent as? VarDecl + return if (vardecl!=null) { + fixupArrayDatatype(array, vardecl, program.heap) + } else { + // fix the datatype of the array (also on the heap) to the 'biggest' datatype in the array + // (we don't know the desired datatype here exactly so we guess) + val datatype = determineArrayDt(array.value) + val litval2 = array.cast(datatype)!! + litval2.parent = array.parent + // finally, replace the literal array by a identifier reference. + makeIdentifierFromRefLv(litval2) } } - - return litval + return array } - private fun determineArrayDt(array: Array): DataType? { + override fun visit(stringLiteral: StringLiteralValue): Expression { + val string = super.visit(stringLiteral) + if(string is StringLiteralValue) { + val vardecl = string.parent as? VarDecl + // intern the string; move it into the heap + if (string.value.length !in 1..255) + checkResult.add(ExpressionError("string literal length must be between 1 and 255", string.position)) + else { + string.addToHeap(program.heap) + } + return if (vardecl != null) + string + else + makeIdentifierFromRefLv(string) // replace the literal string by a identifier reference. + } + return string + } + + private fun determineArrayDt(array: Array): DataType { val datatypesInArray = array.mapNotNull { it.inferType(program) } if(datatypesInArray.isEmpty()) - return null - if(DataType.FLOAT in datatypesInArray) - return DataType.ARRAY_F - if(DataType.WORD in datatypesInArray) - return DataType.ARRAY_W - if(DataType.UWORD in datatypesInArray) - return DataType.ARRAY_UW - if(DataType.BYTE in datatypesInArray) - return DataType.ARRAY_B - if(DataType.UBYTE in datatypesInArray) - return DataType.ARRAY_UB - return null + throw IllegalArgumentException("can't determine type of empty array") + return when { + DataType.FLOAT in datatypesInArray -> DataType.ARRAY_F + DataType.WORD in datatypesInArray -> DataType.ARRAY_W + DataType.UWORD in datatypesInArray -> DataType.ARRAY_UW + DataType.BYTE in datatypesInArray -> DataType.ARRAY_B + DataType.UBYTE in datatypesInArray -> DataType.ARRAY_UB + else -> throw IllegalArgumentException("can't determine type of array") + } } - private fun makeIdentifierFromRefLv(refLiteral: ReferenceLiteralValue): IdentifierReference { + private fun makeIdentifierFromRefLv(array: ArrayLiteralValue): IdentifierReference { // a referencetype literal value that's not declared as a variable // we need to introduce an auto-generated variable for this to be able to refer to the value // note: if the var references the same literal value, it is not yet de-duplicated here. - refLiteral.addToHeap(program.heap) - val scope = refLiteral.definingScope() - var variable = VarDecl.createAuto(refLiteral, program.heap) - val existing = scope.lookup(listOf(variable.name), refLiteral) - variable = addVarDecl(scope, variable) - // replace the reference literal by a identifier reference - val identifier = IdentifierReference(listOf(variable.name), variable.position) - identifier.parent = refLiteral.parent - return identifier + array.addToHeap(program.heap) + val scope = array.definingScope() + val variable = VarDecl.createAuto(array) + return replaceWithIdentifier(variable, scope, array.parent) } - override fun visit(addressOf: AddressOf): Expression { - // register the scoped name of the referenced identifier - val variable= addressOf.identifier.targetVarDecl(program.namespace) ?: return addressOf - return super.visit(addressOf) + private fun makeIdentifierFromRefLv(string: StringLiteralValue): IdentifierReference { + // a referencetype literal value that's not declared as a variable + // we need to introduce an auto-generated variable for this to be able to refer to the value + // note: if the var references the same literal value, it is not yet de-duplicated here. + string.addToHeap(program.heap) + val scope = string.definingScope() + val variable = VarDecl.createAuto(string) + return replaceWithIdentifier(variable, scope, string.parent) + } + + private fun replaceWithIdentifier(variable: VarDecl, scope: INameScope, parent: Node): IdentifierReference { + val variable1 = addVarDecl(scope, variable) + // replace the reference literal by a identifier reference + val identifier = IdentifierReference(listOf(variable1.name), variable1.position) + identifier.parent = parent + return identifier } override fun visit(structDecl: StructDecl): Statement { @@ -330,33 +338,28 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi override fun visit(expr: BinaryExpression): Expression { return when { - expr.left is ReferenceLiteralValue -> - processBinaryExprWithReferenceVal(expr.left as ReferenceLiteralValue, expr.right, expr) - expr.right is ReferenceLiteralValue -> - processBinaryExprWithReferenceVal(expr.right as ReferenceLiteralValue, expr.left, expr) + expr.left is StringLiteralValue -> + processBinaryExprWithString(expr.left as StringLiteralValue, expr.right, expr) + expr.right is StringLiteralValue -> + processBinaryExprWithString(expr.right as StringLiteralValue, expr.left, expr) else -> super.visit(expr) } } - private fun processBinaryExprWithReferenceVal(refLv: ReferenceLiteralValue, operand: Expression, expr: BinaryExpression): Expression { - // expressions on strings or arrays - if(refLv.isString) { - val constvalue = operand.constValue(program) - if(constvalue!=null) { - if (expr.operator == "*") { - // repeat a string a number of times - return ReferenceLiteralValue(refLv.inferType(program), - refLv.str!!.repeat(constvalue.number.toInt()), null, null, expr.position) - } - } - if(expr.operator == "+" && operand is ReferenceLiteralValue) { - if (operand.isString) { - // concatenate two strings - return ReferenceLiteralValue(refLv.inferType(program), - "${refLv.str}${operand.str}", null, null, expr.position) - } + private fun processBinaryExprWithString(string: StringLiteralValue, operand: Expression, expr: BinaryExpression): Expression { + val constvalue = operand.constValue(program) + if(constvalue!=null) { + if (expr.operator == "*") { + // repeat a string a number of times + return StringLiteralValue(string.inferType(program), + string.value.repeat(constvalue.number.toInt()), null, expr.position) } } + if(expr.operator == "+" && operand is StringLiteralValue) { + // concatenate two strings + return StringLiteralValue(string.inferType(program), + "${string.value}${operand.value}", null, expr.position) + } return expr } @@ -375,7 +378,7 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi } -internal fun fixupArrayDatatype(array: ReferenceLiteralValue, vardecl: VarDecl, heap: HeapValues): ReferenceLiteralValue { +internal fun fixupArrayDatatype(array: ArrayLiteralValue, vardecl: VarDecl, heap: HeapValues): ArrayLiteralValue { if(array.heapId!=null) { val arrayDt = array.type if(arrayDt!=vardecl.datatype) { @@ -386,7 +389,7 @@ internal fun fixupArrayDatatype(array: ReferenceLiteralValue, vardecl: VarDecl, } catch(x: ExpressionError) { // couldn't cast permanently. // instead, simply adjust the array type and trust the AstChecker to report the exact error - ReferenceLiteralValue(vardecl.datatype, null, array.array, array.heapId, array.position) + ArrayLiteralValue(vardecl.datatype, array.value, array.heapId, array.position) } vardecl.value = litval2 litval2.linkParents(vardecl) diff --git a/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt b/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt index 64ec91006..6c7e55049 100644 --- a/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt +++ b/compiler/src/prog8/ast/processing/IAstModifyingVisitor.kt @@ -110,14 +110,16 @@ interface IAstModifyingVisitor { return literalValue } - fun visit(refLiteral: ReferenceLiteralValue): Expression { - if(refLiteral.array!=null) { - for(av in refLiteral.array.withIndex()) { - val newvalue = av.value.accept(this) - refLiteral.array[av.index] = newvalue - } + fun visit(stringLiteral: StringLiteralValue): Expression { + return stringLiteral + } + + fun visit(arrayLiteral: ArrayLiteralValue): Expression { + for(av in arrayLiteral.value.withIndex()) { + val newvalue = av.value.accept(this) + arrayLiteral.value[av.index] = newvalue } - return refLiteral + return arrayLiteral } fun visit(assignment: Assignment): Statement { diff --git a/compiler/src/prog8/ast/processing/IAstVisitor.kt b/compiler/src/prog8/ast/processing/IAstVisitor.kt index 6afe7ae74..3a3c4116d 100644 --- a/compiler/src/prog8/ast/processing/IAstVisitor.kt +++ b/compiler/src/prog8/ast/processing/IAstVisitor.kt @@ -79,8 +79,11 @@ interface IAstVisitor { fun visit(numLiteral: NumericLiteralValue) { } - fun visit(refLiteral: ReferenceLiteralValue) { - refLiteral.array?.let { it.forEach { v->v.accept(this) }} + fun visit(string: StringLiteralValue) { + } + + fun visit(array: ArrayLiteralValue) { + array.value.forEach { v->v.accept(this) } } fun visit(assignment: Assignment) { diff --git a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt index fc9f91754..9bd8137a3 100644 --- a/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt +++ b/compiler/src/prog8/ast/processing/VarInitValueAndAddressOfCreator.kt @@ -42,7 +42,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA if(decl.isArray && decl.value==null) { // array datatype without initialization value, add list of zeros val arraysize = decl.arraysize!!.size()!! - val array = ReferenceLiteralValue(decl.datatype, null, + val array = ArrayLiteralValue(decl.datatype, Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) }, null, decl.position) array.addToHeap(program.heap) @@ -107,7 +107,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA if(argparam.second is AddressOf) continue val idref = argparam.second as? IdentifierReference - val strvalue = argparam.second as? ReferenceLiteralValue + val strvalue = argparam.second as? StringLiteralValue if(idref!=null) { val variable = idref.targetVarDecl(program.namespace) if(variable!=null && (variable.datatype in StringDatatypes || variable.datatype in ArrayDatatypes)) { @@ -117,16 +117,14 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA } } else if(strvalue!=null) { - if(strvalue.isString) { - // add a vardecl so that the autovar can be resolved in later lookups - val variable = VarDecl.createAuto(strvalue, program.heap) - addVarDecl(strvalue.definingScope(), variable) - // replace the argument with &autovar - val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position) - val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position) - pointerExpr.linkParents(arglist[argparam.first.index].parent) - arglist[argparam.first.index] = pointerExpr - } + // add a vardecl so that the autovar can be resolved in later lookups + val variable = VarDecl.createAuto(strvalue) + addVarDecl(strvalue.definingScope(), variable) + // replace the argument with &autovar + val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position) + val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position) + pointerExpr.linkParents(arglist[argparam.first.index].parent) + arglist[argparam.first.index] = pointerExpr } } } diff --git a/compiler/src/prog8/ast/statements/AstStatements.kt b/compiler/src/prog8/ast/statements/AstStatements.kt index 764822f1f..d045841f0 100644 --- a/compiler/src/prog8/ast/statements/AstStatements.kt +++ b/compiler/src/prog8/ast/statements/AstStatements.kt @@ -5,7 +5,6 @@ import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.processing.IAstVisitor -import prog8.compiler.HeapValues sealed class Statement : Node { @@ -111,8 +110,6 @@ data class Label(val name: String, override val position: Position) : Statement( override fun toString(): String { return "Label(name=$name, pos=$position)" } - - val scopedname: String by lazy { makeScopedName(name) } } open class Return(var value: Expression?, override val position: Position) : Statement() { @@ -197,20 +194,23 @@ class VarDecl(val type: VarDeclType, companion object { private var autoHeapValueSequenceNumber = 0 - fun createAuto(refLv: ReferenceLiteralValue, heap: HeapValues): VarDecl { - if(refLv.heapId==null) - throw FatalAstException("can only create autovar for a ref lv that has a heapid $refLv") + fun createAuto(string: StringLiteralValue): VarDecl { + if(string.heapId==null) + throw FatalAstException("can only create autovar for a string that has a heapid $string") + val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}" + return VarDecl(VarDeclType.VAR, string.type, ZeropageWish.NOT_IN_ZEROPAGE, null, autoVarName, null, string, + isArray = false, autogeneratedDontRemove = true, position = string.position) + } + + fun createAuto(array: ArrayLiteralValue): VarDecl { + if(array.heapId==null) + throw FatalAstException("can only create autovar for an array that has a heapid $array") val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}" - return if(refLv.isArray) { - val declaredType = ArrayElementTypes.getValue(refLv.type) - val arraysize = ArrayIndex.forArray(refLv, heap) - VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, refLv, - isArray = true, autogeneratedDontRemove = true, position = refLv.position) - } else { - VarDecl(VarDeclType.VAR, refLv.type, ZeropageWish.NOT_IN_ZEROPAGE, null, autoVarName, null, refLv, - isArray = false, autogeneratedDontRemove = true, position = refLv.position) - } + val declaredType = ArrayElementTypes.getValue(array.type) + val arraysize = ArrayIndex.forArray(array) + return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array, + isArray = true, autogeneratedDontRemove = true, position = array.position) } } @@ -284,12 +284,6 @@ class VarDecl(val type: VarDeclType, structHasBeenFlattened = true return result } - - fun withPrefixedName(nameprefix: String): Statement { - val new = VarDecl(type, declaredDatatype, zeropage, arraysize, nameprefix+name, structName, value, isArray, autogeneratedDontRemove, position) - new.parent = parent - return new - } } class ArrayIndex(var index: Expression, override val position: Position) : Node { @@ -301,9 +295,8 @@ class ArrayIndex(var index: Expression, override val position: Position) : Node } companion object { - fun forArray(v: ReferenceLiteralValue, heap: HeapValues): ArrayIndex { - val arraySize = v.array?.size ?: heap.get(v.heapId!!).arraysize - return ArrayIndex(NumericLiteralValue.optimalNumeric(arraySize, v.position), v.position) + fun forArray(v: ArrayLiteralValue): ArrayIndex { + return ArrayIndex(NumericLiteralValue.optimalNumeric(v.value.size, v.position), v.position) } } diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt index 6c1231f9f..efa721c78 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AnonymousScopeVarsCleanup.kt @@ -21,7 +21,7 @@ class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor { super.visit(program) for((scope, decls) in varsToMove) { val sub = scope.definingSubroutine()!! - val existingVariables = sub.statements.filterIsInstance().associate { it.name to it } + val existingVariables = sub.statements.filterIsInstance().associateBy { it.name } var conflicts = false decls.forEach { val existing = existingVariables[it.name] diff --git a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt index 492e1a07c..415d67ee6 100644 --- a/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt +++ b/compiler/src/prog8/compiler/target/c64/codegen2/AsmGen2.kt @@ -251,7 +251,7 @@ internal class AsmGen2(val program: Program, DataType.FLOAT -> out("${decl.name}\t.byte 0,0,0,0,0 ; float") DataType.STRUCT -> {} // is flattened DataType.STR, DataType.STR_S -> { - val string = (decl.value as ReferenceLiteralValue).str!! + val string = (decl.value as StringLiteralValue).value val encoded = encodeStr(string, decl.datatype) outputStringvar(decl, encoded) } @@ -296,7 +296,7 @@ internal class AsmGen2(val program: Program, } } DataType.ARRAY_F -> { - val array = (decl.value as ReferenceLiteralValue).array ?: throw AssemblyError("array should not be null?") + val array = (decl.value as ArrayLiteralValue).value val floatFills = array.map { val number = (it as NumericLiteralValue).number makeFloatFill(MachineDefinition.Mflpt5.fromNumber(number)) @@ -337,7 +337,7 @@ internal class AsmGen2(val program: Program, // special treatment for string types: merge strings that are identical val encodedstringVars = normalVars .filter {it.datatype in StringDatatypes } - .map { it to encodeStr((it.value as ReferenceLiteralValue).str!!, it.datatype) } + .map { it to encodeStr((it.value as StringLiteralValue).value, it.datatype) } .groupBy({it.second}, {it.first}) for((encoded, variables) in encodedstringVars) { variables.dropLast(1).forEach { out(it.name) } @@ -353,7 +353,7 @@ internal class AsmGen2(val program: Program, } private fun outputStringvar(lastvar: VarDecl, encoded: List) { - val string = (lastvar.value as ReferenceLiteralValue).str!! + val string = (lastvar.value as StringLiteralValue).value out("${lastvar.name}\t; ${lastvar.datatype} \"${escape(string).replace("\u0000", "")}\"") val outputBytes = encoded.map { "$" + it.toString(16).padStart(2, '0') } for (chunk in outputBytes.chunked(16)) @@ -361,7 +361,7 @@ internal class AsmGen2(val program: Program, } private fun makeArrayFillDataUnsigned(decl: VarDecl): List { - val array = (decl.value as ReferenceLiteralValue).array ?: throw AssemblyError("array should not be null?") + val array = (decl.value as ArrayLiteralValue).value return when { decl.datatype == DataType.ARRAY_UB -> // byte array can never contain pointer-to types, so treat values as all integers @@ -381,7 +381,7 @@ internal class AsmGen2(val program: Program, } private fun makeArrayFillDataSigned(decl: VarDecl): List { - val array = (decl.value as ReferenceLiteralValue).array ?: throw AssemblyError("array should not be null?") + val array = (decl.value as ArrayLiteralValue).value return when { decl.datatype == DataType.ARRAY_UB -> @@ -808,22 +808,31 @@ internal class AsmGen2(val program: Program, is NumericLiteralValue -> { // optimize when the argument is a constant literal val hex = value.number.toHex() - if (register == RegisterOrPair.AX) out(" lda #<$hex | ldx #>$hex") - else if (register == RegisterOrPair.AY) out(" lda #<$hex | ldy #>$hex") - else if (register == RegisterOrPair.XY) out(" ldx #<$hex | ldy #>$hex") + when (register) { + RegisterOrPair.AX -> out(" lda #<$hex | ldx #>$hex") + RegisterOrPair.AY -> out(" lda #<$hex | ldy #>$hex") + RegisterOrPair.XY -> out(" ldx #<$hex | ldy #>$hex") + else -> {} + } } is AddressOf -> { // optimize when the argument is an address of something val sourceName = asmIdentifierName(value.identifier) - if (register == RegisterOrPair.AX) out(" lda #<$sourceName | ldx #>$sourceName") - else if (register == RegisterOrPair.AY) out(" lda #<$sourceName | ldy #>$sourceName") - else if (register == RegisterOrPair.XY) out(" ldx #<$sourceName | ldy #>$sourceName") + when (register) { + RegisterOrPair.AX -> out(" lda #<$sourceName | ldx #>$sourceName") + RegisterOrPair.AY -> out(" lda #<$sourceName | ldy #>$sourceName") + RegisterOrPair.XY -> out(" ldx #<$sourceName | ldy #>$sourceName") + else -> {} + } } is IdentifierReference -> { val sourceName = asmIdentifierName(value) - if (register == RegisterOrPair.AX) out(" lda $sourceName | ldx $sourceName+1") - else if (register == RegisterOrPair.AY) out(" lda $sourceName | ldy $sourceName+1") - else if (register == RegisterOrPair.XY) out(" ldx $sourceName | ldy $sourceName+1") + when (register) { + RegisterOrPair.AX -> out(" lda $sourceName | ldx $sourceName+1") + RegisterOrPair.AY -> out(" lda $sourceName | ldy $sourceName+1") + RegisterOrPair.XY -> out(" ldx $sourceName | ldy $sourceName+1") + else -> {} + } } else -> { translateExpression(value) @@ -1748,7 +1757,7 @@ $endLabel""") translateExpression(assign.value as FunctionCall) assignFromEvalResult(assign.target) } - is ReferenceLiteralValue -> TODO("string/array/struct assignment?") + is ArrayLiteralValue, is StringLiteralValue -> TODO("string/array/struct assignment?") is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values") } @@ -1851,7 +1860,7 @@ $endLabel""") translateSubroutineCall(expression) val sub = expression.target.targetSubroutine(program.namespace)!! val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters) - for((t, reg) in returns) { + for((_, reg) in returns) { if(!reg.stack) { // result value in cpu or status registers, put it on the stack if(reg.registerOrPair!=null) { @@ -1867,7 +1876,7 @@ $endLabel""") } } } - is ReferenceLiteralValue -> TODO("string/array/struct assignment?") + is ArrayLiteralValue, is StringLiteralValue -> TODO("string/array/struct assignment?") is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened") is RangeExpr -> throw AssemblyError("range expression should have been changed into array values") } diff --git a/compiler/src/prog8/functions/BuiltinFunctions.kt b/compiler/src/prog8/functions/BuiltinFunctions.kt index d256188b0..753e05141 100644 --- a/compiler/src/prog8/functions/BuiltinFunctions.kt +++ b/compiler/src/prog8/functions/BuiltinFunctions.kt @@ -115,9 +115,9 @@ val BuiltinFunctions = mapOf( fun builtinFunctionReturnType(function: String, args: List, program: Program): DataType? { fun datatypeFromIterableArg(arglist: Expression): DataType { - if(arglist is ReferenceLiteralValue) { + if(arglist is ArrayLiteralValue) { if(arglist.type== DataType.ARRAY_UB || arglist.type== DataType.ARRAY_UW || arglist.type== DataType.ARRAY_F) { - val dt = arglist.array!!.map {it.inferType(program)} + val dt = arglist.value.map {it.inferType(program)} if(dt.any { it!= DataType.UBYTE && it!= DataType.UWORD && it!= DataType.FLOAT}) { throw FatalAstException("fuction $function only accepts arraysize of numeric values") } @@ -271,10 +271,10 @@ private fun builtinLen(args: List, position: Position, program: Prog NumericLiteralValue.optimalInteger(arraySize, args[0].position) } in StringDatatypes -> { - val refLv = target.value as ReferenceLiteralValue - if(refLv.str!!.length>255) + val refLv = target.value as StringLiteralValue + if(refLv.value.length>255) throw CompilerException("string length exceeds byte limit ${refLv.position}") - NumericLiteralValue.optimalInteger(refLv.str.length, args[0].position) + NumericLiteralValue.optimalInteger(refLv.value.length, args[0].position) } in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position) else -> throw CompilerException("weird datatype") diff --git a/compiler/src/prog8/optimizer/ConstantFolding.kt b/compiler/src/prog8/optimizer/ConstantFolding.kt index 6be1bb7e3..d26452e1d 100644 --- a/compiler/src/prog8/optimizer/ConstantFolding.kt +++ b/compiler/src/prog8/optimizer/ConstantFolding.kt @@ -39,11 +39,9 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { if(decl.isArray){ if(decl.arraysize==null) { // for arrays that have no size specifier (or a non-constant one) attempt to deduce the size - val arrayval = (decl.value as? ReferenceLiteralValue)?.array - if(arrayval!=null) { - decl.arraysize = ArrayIndex(NumericLiteralValue.optimalInteger(arrayval.size, decl.position), decl.position) - optimizationsDone++ - } + val arrayval = (decl.value as ArrayLiteralValue).value + decl.arraysize = ArrayIndex(NumericLiteralValue.optimalInteger(arrayval.size, decl.position), decl.position) + optimizationsDone++ } else if(decl.arraysize?.size()==null) { val size = decl.arraysize!!.index.accept(this) @@ -83,13 +81,13 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { if(constRange!=null) { val eltType = rangeExpr.inferType(program)!! if(eltType in ByteDatatypes) { - decl.value = ReferenceLiteralValue(decl.datatype, - array = constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) } - .toTypedArray(), position = decl.value!!.position) + decl.value = ArrayLiteralValue(decl.datatype, + constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) } else { - decl.value = ReferenceLiteralValue(decl.datatype, - array = constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) } - .toTypedArray(), position = decl.value!!.position) + decl.value = ArrayLiteralValue(decl.datatype, + constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(), + position = decl.value!!.position) } decl.value!!.linkParents(decl) optimizationsDone++ @@ -123,7 +121,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { } // create the array itself, filled with the fillvalue. val array = Array(size) {fillvalue}.map { NumericLiteralValue.optimalInteger(it, numericLv.position) as Expression}.toTypedArray() - val refValue = ReferenceLiteralValue(decl.datatype, array = array, position = numericLv.position) + val refValue = ArrayLiteralValue(decl.datatype, array, position = numericLv.position) refValue.addToHeap(program.heap) decl.value = refValue refValue.parent=decl @@ -145,7 +143,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { else { // create the array itself, filled with the fillvalue. val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray() - val refValue = ReferenceLiteralValue(DataType.ARRAY_F, array = array, position = litval.position) + val refValue = ArrayLiteralValue(DataType.ARRAY_F, array, position = litval.position) refValue.addToHeap(program.heap) decl.value = refValue refValue.parent=decl @@ -311,7 +309,8 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { return try { super.visit(expr) - if(expr.left is ReferenceLiteralValue || expr.right is ReferenceLiteralValue) + if(expr.left is StringLiteralValue || expr.left is ArrayLiteralValue + || expr.right is StringLiteralValue || expr.right is ArrayLiteralValue) throw FatalAstException("binexpr with reference litval instead of numeric") val leftconst = expr.left.constValue(program) @@ -597,17 +596,15 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor { return resultStmt } - override fun visit(refLiteral: ReferenceLiteralValue): Expression { - val litval = super.visit(refLiteral) - if(litval is ReferenceLiteralValue) { - if (litval.isArray) { - val vardecl = litval.parent as? VarDecl - if (vardecl!=null) { - return fixupArrayDatatype(litval, vardecl, program.heap) - } + override fun visit(arrayLiteral: ArrayLiteralValue): Expression { + val array = super.visit(arrayLiteral) + if(array is ArrayLiteralValue) { + val vardecl = array.parent as? VarDecl + if (vardecl!=null) { + return fixupArrayDatatype(array, vardecl, program.heap) } } - return litval + return array } override fun visit(assignment: Assignment): Statement { diff --git a/compiler/src/prog8/optimizer/StatementOptimizer.kt b/compiler/src/prog8/optimizer/StatementOptimizer.kt index 80ef6697a..b69ae3726 100644 --- a/compiler/src/prog8/optimizer/StatementOptimizer.kt +++ b/compiler/src/prog8/optimizer/StatementOptimizer.kt @@ -1,6 +1,9 @@ package prog8.optimizer -import prog8.ast.* +import prog8.ast.INameScope +import prog8.ast.Module +import prog8.ast.Node +import prog8.ast.Program import prog8.ast.base.* import prog8.ast.expressions.* import prog8.ast.processing.IAstModifyingVisitor diff --git a/compiler/src/prog8/vm/RuntimeValue.kt b/compiler/src/prog8/vm/RuntimeValue.kt index 67f5c52af..1df48a823 100644 --- a/compiler/src/prog8/vm/RuntimeValue.kt +++ b/compiler/src/prog8/vm/RuntimeValue.kt @@ -1,8 +1,9 @@ package prog8.vm import prog8.ast.base.* +import prog8.ast.expressions.ArrayLiteralValue import prog8.ast.expressions.NumericLiteralValue -import prog8.ast.expressions.ReferenceLiteralValue +import prog8.ast.expressions.StringLiteralValue import prog8.compiler.HeapValues import prog8.compiler.target.c64.Petscii import java.util.* @@ -28,13 +29,8 @@ open class RuntimeValue(val type: DataType, num: Number?=null, val str: String?= return RuntimeValue(literalValue.type, num = literalValue.number) } - fun fromLv(literalValue: ReferenceLiteralValue, heap: HeapValues): RuntimeValue { - return when(literalValue.type) { - in StringDatatypes -> fromHeapId(literalValue.heapId!!, heap) - in ArrayDatatypes -> fromHeapId(literalValue.heapId!!, heap) - else -> throw IllegalArgumentException("weird source value $literalValue") - } - } + fun fromLv(string: StringLiteralValue, heap: HeapValues): RuntimeValue = fromHeapId(string.heapId!!, heap) + fun fromLv(array: ArrayLiteralValue, heap: HeapValues): RuntimeValue = fromHeapId(array.heapId!!, heap) fun fromHeapId(heapId: Int, heap: HeapValues): RuntimeValue { val value = heap.get(heapId) diff --git a/compiler/src/prog8/vm/astvm/AstVm.kt b/compiler/src/prog8/vm/astvm/AstVm.kt index 7ae98df5e..b931e40d7 100644 --- a/compiler/src/prog8/vm/astvm/AstVm.kt +++ b/compiler/src/prog8/vm/astvm/AstVm.kt @@ -166,10 +166,10 @@ class AstVm(val program: Program) { fun memwrite(address: Int, value: Short): Short { if(address==0xa0 || address==0xa1 || address==0xa2) { // a write to the jiffy clock, update the clock offset for the irq - val time_hi = if(address==0xa0) value else mem.getUByte_DMA(0xa0) - val time_mid = if(address==0xa1) value else mem.getUByte_DMA(0xa1) - val time_lo = if(address==0xa2) value else mem.getUByte_DMA(0xa2) - val jiffies = (time_hi.toInt() shl 16) + (time_mid.toInt() shl 8) + time_lo + val timeHi = if(address==0xa0) value else mem.getUByte_DMA(0xa0) + val timeMid = if(address==0xa1) value else mem.getUByte_DMA(0xa1) + val timeLo = if(address==0xa2) value else mem.getUByte_DMA(0xa2) + val jiffies = (timeHi.toInt() shl 16) + (timeMid.toInt() shl 8) + timeLo rtcOffset = bootTime - (jiffies*1000/60) } if(address in 1024..2023) { diff --git a/compiler/src/prog8/vm/astvm/Expressions.kt b/compiler/src/prog8/vm/astvm/Expressions.kt index 08290fc78..84647ffee 100644 --- a/compiler/src/prog8/vm/astvm/Expressions.kt +++ b/compiler/src/prog8/vm/astvm/Expressions.kt @@ -30,12 +30,9 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue { return RuntimeValue.fromLv(constval) when(expr) { - is NumericLiteralValue -> { - return RuntimeValue.fromLv(expr) - } - is ReferenceLiteralValue -> { - return RuntimeValue.fromLv(expr, ctx.program.heap) - } + is NumericLiteralValue -> return RuntimeValue.fromLv(expr) + is StringLiteralValue -> return RuntimeValue.fromLv(expr, ctx.program.heap) + is ArrayLiteralValue -> return RuntimeValue.fromLv(expr, ctx.program.heap) is PrefixExpression -> { return when(expr.operator) { "-" -> evaluate(expr.expression, ctx).neg() diff --git a/compiler/src/prog8/vm/astvm/VariablesCreator.kt b/compiler/src/prog8/vm/astvm/VariablesCreator.kt index 27167f3d8..7d433aa89 100644 --- a/compiler/src/prog8/vm/astvm/VariablesCreator.kt +++ b/compiler/src/prog8/vm/astvm/VariablesCreator.kt @@ -5,8 +5,9 @@ import prog8.ast.base.DataType import prog8.ast.base.Position import prog8.ast.base.Register import prog8.ast.base.VarDeclType +import prog8.ast.expressions.ArrayLiteralValue import prog8.ast.expressions.NumericLiteralValue -import prog8.ast.expressions.ReferenceLiteralValue +import prog8.ast.expressions.StringLiteralValue import prog8.ast.processing.IAstModifyingVisitor import prog8.ast.statements.Statement import prog8.ast.statements.StructDecl @@ -50,8 +51,10 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v val value = if(numericLv!=null) { RuntimeValue.fromLv(numericLv) } else { - val referenceLv = decl.value as ReferenceLiteralValue - RuntimeValue.fromLv(referenceLv, heap) + if(decl.value is StringLiteralValue) + RuntimeValue.fromLv(decl.value as StringLiteralValue, heap) + else + RuntimeValue.fromLv(decl.value as ArrayLiteralValue, heap) } runtimeVariables.define(decl.definingScope(), decl.name, value) } diff --git a/compiler/test/LiteralValueTests.kt b/compiler/test/LiteralValueTests.kt index 091536a4c..89cfab9e3 100644 --- a/compiler/test/LiteralValueTests.kt +++ b/compiler/test/LiteralValueTests.kt @@ -4,8 +4,9 @@ import org.junit.jupiter.api.Test import org.junit.jupiter.api.TestInstance import prog8.ast.base.DataType import prog8.ast.base.Position +import prog8.ast.expressions.ArrayLiteralValue import prog8.ast.expressions.NumericLiteralValue -import prog8.ast.expressions.ReferenceLiteralValue +import prog8.ast.expressions.StringLiteralValue import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertNotEquals @@ -16,10 +17,6 @@ private fun sameValueAndType(lv1: NumericLiteralValue, lv2: NumericLiteralValue) return lv1.type==lv2.type && lv1==lv2 } -private fun sameValueAndType(rv1: ReferenceLiteralValue, rv2: ReferenceLiteralValue): Boolean { - return rv1.type==rv2.type && rv1==rv2 -} - @TestInstance(TestInstance.Lifecycle.PER_CLASS) class TestParserNumericLiteralValue { @@ -86,8 +83,8 @@ class TestParserNumericLiteralValue { @Test fun testEqualsRef() { - assertTrue(sameValueAndType(ReferenceLiteralValue(DataType.STR, str = "hello", position = dummyPos), ReferenceLiteralValue(DataType.STR, str = "hello", position = dummyPos))) - assertFalse(sameValueAndType(ReferenceLiteralValue(DataType.STR, str = "hello", position = dummyPos), ReferenceLiteralValue(DataType.STR, str = "bye", position = dummyPos))) + assertTrue(StringLiteralValue(DataType.STR, "hello", position = dummyPos) == StringLiteralValue(DataType.STR, "hello", position = dummyPos)) + assertFalse(StringLiteralValue(DataType.STR, "hello", position = dummyPos) == StringLiteralValue(DataType.STR, "bye", position = dummyPos)) val lvOne = NumericLiteralValue(DataType.UBYTE, 1, dummyPos) val lvTwo = NumericLiteralValue(DataType.UBYTE, 2, dummyPos) @@ -96,9 +93,9 @@ class TestParserNumericLiteralValue { val lvTwoR = NumericLiteralValue(DataType.UBYTE, 2, dummyPos) val lvThreeR = NumericLiteralValue(DataType.UBYTE, 3, dummyPos) val lvFour= NumericLiteralValue(DataType.UBYTE, 4, dummyPos) - val lv1 = ReferenceLiteralValue(DataType.ARRAY_UB, array = arrayOf(lvOne, lvTwo, lvThree), position = dummyPos) - val lv2 = ReferenceLiteralValue(DataType.ARRAY_UB, array = arrayOf(lvOneR, lvTwoR, lvThreeR), position = dummyPos) - val lv3 = ReferenceLiteralValue(DataType.ARRAY_UB, array = arrayOf(lvOneR, lvTwoR, lvFour), position = dummyPos) + val lv1 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOne, lvTwo, lvThree), position = dummyPos) + val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), position = dummyPos) + val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), position = dummyPos) assertEquals(lv1, lv2) assertNotEquals(lv1, lv3) } diff --git a/compiler/test/UnitTests.kt b/compiler/test/UnitTests.kt index b764f60a9..8ccd852aa 100644 --- a/compiler/test/UnitTests.kt +++ b/compiler/test/UnitTests.kt @@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestInstance import prog8.ast.base.DataType import prog8.ast.base.Position import prog8.ast.expressions.NumericLiteralValue -import prog8.ast.expressions.ReferenceLiteralValue +import prog8.ast.expressions.StringLiteralValue import prog8.compiler.* import prog8.compiler.target.c64.MachineDefinition.C64Zeropage import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE @@ -371,8 +371,8 @@ class TestPetscii { assertTrue(ten <= ten) assertFalse(ten < ten) - val abc = ReferenceLiteralValue(DataType.STR, str = "abc", position = Position("", 0, 0, 0)) - val abd = ReferenceLiteralValue(DataType.STR, str = "abd", position = Position("", 0, 0, 0)) + val abc = StringLiteralValue(DataType.STR, "abc", position = Position("", 0, 0, 0)) + val abd = StringLiteralValue(DataType.STR, "abd", position = Position("", 0, 0, 0)) assertEquals(abc, abc) assertTrue(abc!=abd) assertFalse(abc!=abc) diff --git a/examples/test.p8 b/examples/test.p8 index 58a082749..a20405b08 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -6,42 +6,9 @@ main { sub start() { - byte[] barr = [-100, 0, 99, -122, 22] - ubyte[] ubarr = [100, 0, 99, 199, 22] - word[] warr = [-1000, 0, 999, -4444, 222] - uword[] uwarr = [1000, 0, 222, 4444, 999] - float[] farr = [-1000.1, 0, 999.9, -4444.4, 222.2] - str name = "irmen" - ubyte ub - byte bb - word ww - uword uw - float ff - - ; LEN/STRLEN - ubyte length = len(name) - if(length!=5) c64scr.print("error len1\n") - length = len(uwarr) - if(length!=5) c64scr.print("error len2\n") - length=strlen(name) - if(length!=5) c64scr.print("error strlen1\n") - name[3] = 0 - length=strlen(name) - if(length!=3) c64scr.print("error strlen2\n") - - ; MAX -; ub = max(ubarr) -; bb = max(barr) -; ww = max(warr) -; uw = max(uwarr) -; ff = max(farr) - -; word ww = sum(barr) -; uword uw = sum(ubarr) -; ww = sum(warr) -; uw = sum(uwarr) -; float ff = sum(farr) + c64scr.print("\nbreakpoint after this.") + %breakpoint c64scr.print("\nyou should see no errors above.") } }