split array and string literal classes

This commit is contained in:
Irmen de Jong 2019-08-13 03:00:17 +02:00
parent 9fb9bcfebd
commit b64d611e02
22 changed files with 349 additions and 413 deletions

View File

@ -77,7 +77,7 @@ private fun compileMain(args: Array<String>) {
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

View File

@ -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<Expression>, openchar: Char, closechar: Char) {

View File

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

View File

@ -406,119 +406,98 @@ class StructLiteralValue(var values: List<Expression>,
}
}
class ReferenceLiteralValue(val type: DataType, // only reference types allowed here
val str: String? = null,
val array: Array<Expression>? = 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<Expression>,
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<String>, 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,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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<VarDecl>().associate { it.name to it }
val existingVariables = sub.statements.filterIsInstance<VarDecl>().associateBy { it.name }
var conflicts = false
decls.forEach {
val existing = existingVariables[it.name]

View File

@ -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<Short>) {
val string = (lastvar.value as ReferenceLiteralValue).str!!
val string = (lastvar.value as StringLiteralValue).value
out("${lastvar.name}\t; ${lastvar.datatype} \"${escape(string).replace("\u0000", "<NULL>")}\"")
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<String> {
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<String> {
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")
}

View File

@ -115,9 +115,9 @@ val BuiltinFunctions = mapOf(
fun builtinFunctionReturnType(function: String, args: List<Expression>, 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<Expression>, 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")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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