mirror of
https://github.com/irmen/prog8.git
synced 2024-11-25 19:31:36 +00:00
split array and string literal classes
This commit is contained in:
parent
9fb9bcfebd
commit
b64d611e02
@ -77,7 +77,7 @@ private fun compileMain(args: Array<String>) {
|
|||||||
val event = watchservice.take()
|
val event = watchservice.take()
|
||||||
for(changed in event.pollEvents()) {
|
for(changed in event.pollEvents()) {
|
||||||
val changedPath = changed.context() as Path
|
val changedPath = changed.context() as Path
|
||||||
println(" change detected: ${changedPath}")
|
println(" change detected: $changedPath")
|
||||||
}
|
}
|
||||||
event.reset()
|
event.reset()
|
||||||
println("\u001b[H\u001b[2J") // clear the screen
|
println("\u001b[H\u001b[2J") // clear the screen
|
||||||
|
@ -132,7 +132,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
|||||||
for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) {
|
for(param in subroutine.parameters.zip(subroutine.asmParameterRegisters)) {
|
||||||
val reg =
|
val reg =
|
||||||
when {
|
when {
|
||||||
true==param.second.stack -> "stack"
|
param.second.stack -> "stack"
|
||||||
param.second.registerOrPair!=null -> param.second.registerOrPair.toString()
|
param.second.registerOrPair!=null -> param.second.registerOrPair.toString()
|
||||||
param.second.statusflag!=null -> param.second.statusflag.toString()
|
param.second.statusflag!=null -> param.second.statusflag.toString()
|
||||||
else -> "?????1"
|
else -> "?????1"
|
||||||
@ -256,15 +256,12 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
|||||||
output(numLiteral.number.toString())
|
output(numLiteral.number.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(refLiteral: ReferenceLiteralValue) {
|
override fun visit(string: StringLiteralValue) {
|
||||||
when {
|
output("\"${escape(string.value)}\"")
|
||||||
refLiteral.isString -> output("\"${escape(refLiteral.str!!)}\"")
|
}
|
||||||
refLiteral.isArray -> {
|
|
||||||
if(refLiteral.array!=null) {
|
override fun visit(array: ArrayLiteralValue) {
|
||||||
outputListMembers(refLiteral.array.asSequence(), '[', ']')
|
outputListMembers(array.value.asSequence(), '[', ']')
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun outputListMembers(array: Sequence<Expression>, openchar: Char, closechar: Char) {
|
private fun outputListMembers(array: Sequence<Expression>, openchar: Char, closechar: Char) {
|
||||||
|
@ -429,7 +429,7 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression {
|
|||||||
else -> throw FatalAstException("invalid datatype for numeric literal")
|
else -> throw FatalAstException("invalid datatype for numeric literal")
|
||||||
}
|
}
|
||||||
litval.floatliteral()!=null -> NumericLiteralValue(DataType.FLOAT, litval.floatliteral().toAst(), litval.toPosition())
|
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 -> {
|
litval.charliteral()!=null -> {
|
||||||
try {
|
try {
|
||||||
NumericLiteralValue(DataType.UBYTE, Petscii.encodePetscii(unescape(litval.charliteral().text, litval.toPosition()), true)[0], litval.toPosition())
|
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 -> {
|
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 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.
|
// 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 -> {
|
litval.structliteral()!=null -> {
|
||||||
val values = litval.structliteral().expression().map { it.toAst() }
|
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 {
|
private fun prog8Parser.When_choiceContext.toAst(): WhenChoice {
|
||||||
val values = expression_list()?.toAst()
|
val values = expression_list()?.toAst()
|
||||||
val stmt = statement()?.toAst()
|
val stmt = statement()?.toAst()
|
||||||
val stmt_block = statement_block()?.toAst()?.toMutableList() ?: mutableListOf()
|
val stmtBlock = statement_block()?.toAst()?.toMutableList() ?: mutableListOf()
|
||||||
if(stmt!=null)
|
if(stmt!=null)
|
||||||
stmt_block.add(stmt)
|
stmtBlock.add(stmt)
|
||||||
val scope = AnonymousScope(stmt_block, toPosition())
|
val scope = AnonymousScope(stmtBlock, toPosition())
|
||||||
return WhenChoice(values, scope, toPosition())
|
return WhenChoice(values, scope, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,119 +406,98 @@ class StructLiteralValue(var values: List<Expression>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReferenceLiteralValue(val type: DataType, // only reference types allowed here
|
class StringLiteralValue(val type: DataType, // only string types
|
||||||
val str: String? = null,
|
val value: String,
|
||||||
val array: Array<Expression>? = null,
|
initHeapId: Int? =null,
|
||||||
initHeapId: Int? =null,
|
override val position: Position) : Expression() {
|
||||||
override val position: Position) : Expression() {
|
|
||||||
override lateinit var parent: Node
|
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
|
var heapId = initHeapId
|
||||||
private set
|
private set
|
||||||
|
|
||||||
init {
|
override fun linkParents(parent: Node) {
|
||||||
when(type){
|
this.parent = parent
|
||||||
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 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) {
|
override fun linkParents(parent: Node) {
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
array?.forEach {it.linkParents(this)}
|
value.forEach {it.linkParents(this)}
|
||||||
}
|
}
|
||||||
|
override fun referencesIdentifiers(vararg name: String) = value.any { it.referencesIdentifiers(*name) }
|
||||||
override fun constValue(program: Program): NumericLiteralValue? {
|
override fun constValue(program: Program): NumericLiteralValue? = null
|
||||||
// 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 accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
||||||
|
override fun toString(): String = "$value"
|
||||||
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 inferType(program: Program) = type
|
override fun inferType(program: Program) = type
|
||||||
|
operator fun compareTo(other: ArrayLiteralValue): Int = throw ExpressionError("cannot order compare arrays", position)
|
||||||
override fun hashCode(): Int = Objects.hash(str, array, type)
|
override fun hashCode(): Int = Objects.hash(value, type)
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if(other==null || other !is ReferenceLiteralValue)
|
if(other==null || other !is ArrayLiteralValue)
|
||||||
return false
|
return false
|
||||||
if(isArray && other.isArray)
|
return type==other.type && value.contentEquals(other.value)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun compareTo(other: ReferenceLiteralValue): Int {
|
fun cast(targettype: DataType): ArrayLiteralValue? {
|
||||||
throw ExpressionError("cannot order compare type $type with ${other.type}", other.position)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cast(targettype: DataType): ReferenceLiteralValue? {
|
|
||||||
if(type==targettype)
|
if(type==targettype)
|
||||||
return this
|
return this
|
||||||
when(type) {
|
if(targettype in ArrayDatatypes) {
|
||||||
in StringDatatypes -> {
|
val elementType = ArrayElementTypes.getValue(targettype)
|
||||||
if(targettype in StringDatatypes)
|
val castArray = value.map{
|
||||||
return ReferenceLiteralValue(targettype, str, position = position)
|
val num = it as? NumericLiteralValue
|
||||||
}
|
if(num==null) {
|
||||||
in ArrayDatatypes -> {
|
// an array of UWORDs could possibly also contain AddressOfs
|
||||||
if(targettype in ArrayDatatypes) {
|
if (elementType != DataType.UWORD || it !is AddressOf)
|
||||||
val elementType = ArrayElementTypes.getValue(targettype)
|
throw FatalAstException("weird array element $it")
|
||||||
val castArray = array!!.map{
|
it
|
||||||
val num = it as? NumericLiteralValue
|
} else {
|
||||||
if(num==null) {
|
try {
|
||||||
// an array of UWORDs could possibly also contain AddressOfs
|
num.cast(elementType)
|
||||||
if (elementType != DataType.UWORD || it !is AddressOf)
|
} catch(x: ExpressionError) {
|
||||||
throw FatalAstException("weird array element $it")
|
return null
|
||||||
it
|
}
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
num.cast(elementType)
|
|
||||||
} catch(x: ExpressionError) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.toTypedArray()
|
|
||||||
return ReferenceLiteralValue(targettype, null, array=castArray, position = position)
|
|
||||||
}
|
}
|
||||||
}
|
}.toTypedArray()
|
||||||
else -> {}
|
return ArrayLiteralValue(targettype, castArray, position = position)
|
||||||
}
|
}
|
||||||
return null // invalid type conversion from $this to $targettype
|
return null // invalid type conversion from $this to $targettype
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addToHeap(heap: HeapValues) {
|
fun addToHeap(heap: HeapValues) {
|
||||||
if (heapId != null) return
|
if (heapId != null)
|
||||||
if (str != null) {
|
return
|
||||||
heapId = heap.addString(type, str)
|
else {
|
||||||
}
|
if(value.any {it is AddressOf }) {
|
||||||
else if (array!=null) {
|
val intArrayWithAddressOfs = value.map {
|
||||||
if(array.any {it is AddressOf }) {
|
|
||||||
val intArrayWithAddressOfs = array.map {
|
|
||||||
when (it) {
|
when (it) {
|
||||||
is AddressOf -> IntegerOrAddressOf(null, it)
|
is AddressOf -> IntegerOrAddressOf(null, it)
|
||||||
is NumericLiteralValue -> IntegerOrAddressOf(it.number.toInt(), null)
|
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())
|
heapId = heap.addIntegerArray(type, intArrayWithAddressOfs.toTypedArray())
|
||||||
} else {
|
} else {
|
||||||
val valuesInArray = array.map { (it as? NumericLiteralValue)?.number }
|
val valuesInArray = value.map { (it as? NumericLiteralValue)?.number }
|
||||||
if(null !in valuesInArray) {
|
if(null !in valuesInArray) {
|
||||||
heapId = if (type == DataType.ARRAY_F) {
|
heapId = if (type == DataType.ARRAY_F) {
|
||||||
val doubleArray = valuesInArray.map { it!!.toDouble() }.toDoubleArray()
|
val doubleArray = valuesInArray.map { it!!.toDouble() }.toDoubleArray()
|
||||||
@ -588,12 +567,12 @@ class RangeExpr(var from: Expression,
|
|||||||
fun toConstantIntegerRange(): IntProgression? {
|
fun toConstantIntegerRange(): IntProgression? {
|
||||||
val fromVal: Int
|
val fromVal: Int
|
||||||
val toVal: Int
|
val toVal: Int
|
||||||
val fromRlv = from as? ReferenceLiteralValue
|
val fromString = from as? StringLiteralValue
|
||||||
val toRlv = to as? ReferenceLiteralValue
|
val toString = to as? StringLiteralValue
|
||||||
if(fromRlv!=null && fromRlv.isString && toRlv!=null && toRlv.isString) {
|
if(fromString!=null && toString!=null ) {
|
||||||
// string range -> int range over petscii values
|
// string range -> int range over petscii values
|
||||||
fromVal = Petscii.encodePetscii(fromRlv.str!!, true)[0].toInt()
|
fromVal = Petscii.encodePetscii(fromString.value, true)[0].toInt()
|
||||||
toVal = Petscii.encodePetscii(toRlv.str!!, true)[0].toInt()
|
toVal = Petscii.encodePetscii(toString.value, true)[0].toInt()
|
||||||
} else {
|
} else {
|
||||||
val fromLv = from as? NumericLiteralValue
|
val fromLv = from as? NumericLiteralValue
|
||||||
val toLv = to 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")
|
val value = (node as? VarDecl)?.value ?: throw FatalAstException("requires a reference value")
|
||||||
return when (value) {
|
return when (value) {
|
||||||
is IdentifierReference -> value.heapId(namespace)
|
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")
|
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,
|
class FunctionCall(override var target: IdentifierReference,
|
||||||
|
@ -7,7 +7,6 @@ import prog8.ast.base.*
|
|||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.statements.*
|
import prog8.ast.statements.*
|
||||||
import prog8.compiler.CompilationOptions
|
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_NEGATIVE
|
||||||
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
|
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_POSITIVE
|
||||||
import prog8.functions.BuiltinFunctions
|
import prog8.functions.BuiltinFunctions
|
||||||
@ -526,14 +525,12 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
when(decl.value) {
|
when(decl.value) {
|
||||||
is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value")
|
is RangeExpr -> throw FatalAstException("range expression should have been converted to a true array value")
|
||||||
is ReferenceLiteralValue -> {
|
is StringLiteralValue -> {
|
||||||
val arraySpec = decl.arraysize ?: (
|
checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue)
|
||||||
if((decl.value as ReferenceLiteralValue).isArray)
|
}
|
||||||
ArrayIndex.forArray(decl.value as ReferenceLiteralValue, program.heap)
|
is ArrayLiteralValue -> {
|
||||||
else
|
val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
|
||||||
ArrayIndex(NumericLiteralValue.optimalInteger(-2, decl.position), decl.position)
|
checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue)
|
||||||
)
|
|
||||||
checkValueTypeAndRange(decl.datatype, decl.struct, arraySpec, decl.value as ReferenceLiteralValue, program.heap)
|
|
||||||
}
|
}
|
||||||
is NumericLiteralValue -> {
|
is NumericLiteralValue -> {
|
||||||
checkValueTypeAndRange(decl.datatype, decl.value as 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))
|
checkResult.add(NameError("included file not found: $filename", directive.position))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(refLiteral: ReferenceLiteralValue) {
|
override fun visit(array: ArrayLiteralValue) {
|
||||||
if(!compilerOptions.floats && refLiteral.type in setOf(DataType.FLOAT, DataType.ARRAY_F)) {
|
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", refLiteral.position))
|
checkResult.add(SyntaxError("floating point used, but that is not enabled via options", array.position))
|
||||||
}
|
}
|
||||||
val arrayspec =
|
val arrayspec = ArrayIndex.forArray(array)
|
||||||
if(refLiteral.isArray)
|
checkValueTypeAndRangeArray(array.type, null, arrayspec, array)
|
||||||
ArrayIndex.forArray(refLiteral, program.heap)
|
|
||||||
else
|
|
||||||
ArrayIndex(NumericLiteralValue.optimalInteger(-3, refLiteral.position), refLiteral.position)
|
|
||||||
checkValueTypeAndRange(refLiteral.type, null, arrayspec, refLiteral, program.heap)
|
|
||||||
|
|
||||||
super.visit(refLiteral)
|
super.visit(array)
|
||||||
|
|
||||||
when(refLiteral.type) {
|
if(array.heapId==null)
|
||||||
in StringDatatypes -> {
|
throw FatalAstException("array should have been moved to heap at ${array.position}")
|
||||||
if(refLiteral.heapId==null)
|
}
|
||||||
throw FatalAstException("string should have been moved to heap at ${refLiteral.position}")
|
|
||||||
}
|
override fun visit(string: StringLiteralValue) {
|
||||||
in ArrayDatatypes -> {
|
checkValueTypeAndRangeString(string.type, string)
|
||||||
if(refLiteral.heapId==null)
|
super.visit(string)
|
||||||
throw FatalAstException("array should have been moved to heap at ${refLiteral.position}")
|
if(string.heapId==null)
|
||||||
}
|
throw FatalAstException("string should have been moved to heap at ${string.position}")
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(expr: PrefixExpression) {
|
override fun visit(expr: PrefixExpression) {
|
||||||
@ -956,9 +947,9 @@ internal class AstChecker(private val program: Program,
|
|||||||
if(index!=null && (index<0 || index>=arraysize))
|
if(index!=null && (index<0 || index>=arraysize))
|
||||||
checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position))
|
checkResult.add(ExpressionError("array index out of bounds", arrayIndexedExpression.arrayspec.position))
|
||||||
} else if(target.datatype in StringDatatypes) {
|
} else if(target.datatype in StringDatatypes) {
|
||||||
if(target.value is ReferenceLiteralValue) {
|
if(target.value is StringLiteralValue) {
|
||||||
// check string lengths for non-memory mapped strings
|
// 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 stringLen = program.heap.get(heapId).str!!.length
|
||||||
val index = (arrayIndexedExpression.arrayspec.index as? NumericLiteralValue)?.number?.toInt()
|
val index = (arrayIndexedExpression.arrayspec.index as? NumericLiteralValue)?.number?.toInt()
|
||||||
if (index != null && (index < 0 || index >= stringLen))
|
if (index != null && (index < 0 || index >= stringLen))
|
||||||
@ -1037,26 +1028,37 @@ internal class AstChecker(private val program: Program,
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkValueTypeAndRange(targetDt: DataType, struct: StructDecl?,
|
private fun checkValueTypeAndRangeString(targetDt: DataType, value: StringLiteralValue) : Boolean {
|
||||||
arrayspec: ArrayIndex, value: ReferenceLiteralValue, heap: HeapValues) : 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 {
|
fun err(msg: String) : Boolean {
|
||||||
checkResult.add(ExpressionError(msg, value.position))
|
checkResult.add(ExpressionError(msg, value.position))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
when (targetDt) {
|
when (targetDt) {
|
||||||
in StringDatatypes -> {
|
in StringDatatypes -> return err("string value expected")
|
||||||
if(!value.isString)
|
|
||||||
return err("string value expected")
|
|
||||||
if (value.str!!.length > 255)
|
|
||||||
return err("string length must be 0-255")
|
|
||||||
}
|
|
||||||
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
DataType.ARRAY_UB, DataType.ARRAY_B -> {
|
||||||
// value may be either a single byte, or a byte arraysize (of all constant values), or a range
|
// value may be either a single byte, or a byte arraysize (of all constant values), or a range
|
||||||
if(value.type==targetDt) {
|
if(value.type==targetDt) {
|
||||||
if(!checkArrayValues(value, targetDt))
|
if(!checkArrayValues(value, targetDt))
|
||||||
return false
|
return false
|
||||||
val arraySpecSize = arrayspec.size()
|
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!=null && arraySpecSize>0) {
|
||||||
if(arraySpecSize<1 || arraySpecSize>256)
|
if(arraySpecSize<1 || arraySpecSize>256)
|
||||||
return err("byte array length must be 1-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))
|
if(!checkArrayValues(value, targetDt))
|
||||||
return false
|
return false
|
||||||
val arraySpecSize = arrayspec.size()
|
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!=null && arraySpecSize>0) {
|
||||||
if(arraySpecSize<1 || arraySpecSize>128)
|
if(arraySpecSize<1 || arraySpecSize>128)
|
||||||
return err("word array length must be 1-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(value.type==targetDt) {
|
||||||
if(!checkArrayValues(value, targetDt))
|
if(!checkArrayValues(value, targetDt))
|
||||||
return false
|
return false
|
||||||
val arraySize = value.array?.size ?: heap.get(value.heapId!!).doubleArray!!.size
|
val arraySize = value.value.size
|
||||||
val arraySpecSize = arrayspec.size()
|
val arraySpecSize = arrayspec.size()
|
||||||
if(arraySpecSize!=null && arraySpecSize>0) {
|
if(arraySpecSize!=null && arraySpecSize>0) {
|
||||||
if(arraySpecSize < 1 || arraySpecSize>51)
|
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")
|
return err("invalid float array size, must be 1-51")
|
||||||
|
|
||||||
// check if the floating point values are all within range
|
// check if the floating point values are all within range
|
||||||
val doubles = if(value.array!=null)
|
val doubles = value.value.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray()
|
||||||
value.array.map {it.constValue(program)?.number!!.toDouble()}.toDoubleArray()
|
|
||||||
else
|
|
||||||
heap.get(value.heapId!!).doubleArray!!
|
|
||||||
if(doubles.any { it < FLOAT_MAX_NEGATIVE || it> FLOAT_MAX_POSITIVE })
|
if(doubles.any { it < FLOAT_MAX_NEGATIVE || it> FLOAT_MAX_POSITIVE })
|
||||||
return err("floating point value overflow")
|
return err("floating point value overflow")
|
||||||
return true
|
return true
|
||||||
@ -1126,9 +1125,9 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
DataType.STRUCT -> {
|
DataType.STRUCT -> {
|
||||||
if(value.type in ArrayDatatypes) {
|
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")
|
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 vardecl = elt.second as VarDecl
|
||||||
val valuetype = elt.first.inferType(program)!!
|
val valuetype = elt.first.inferType(program)!!
|
||||||
if (!(valuetype isAssignableTo vardecl.datatype)) {
|
if (!(valuetype isAssignableTo vardecl.datatype)) {
|
||||||
@ -1142,7 +1141,6 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
else -> return false
|
else -> return false
|
||||||
}
|
}
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkValueTypeAndRange(targetDt: DataType, value: NumericLiteralValue) : Boolean {
|
private fun checkValueTypeAndRange(targetDt: DataType, value: NumericLiteralValue) : Boolean {
|
||||||
@ -1189,10 +1187,10 @@ internal class AstChecker(private val program: Program,
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkArrayValues(value: ReferenceLiteralValue, type: DataType): Boolean {
|
private fun checkArrayValues(value: ArrayLiteralValue, type: DataType): Boolean {
|
||||||
if(value.isArray && value.heapId==null) {
|
if(value.heapId==null) {
|
||||||
// hmm weird, array literal that hasn't been moved to the heap yet?
|
// 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
|
val correct: Boolean
|
||||||
when(type) {
|
when(type) {
|
||||||
DataType.ARRAY_UB -> {
|
DataType.ARRAY_UB -> {
|
||||||
|
@ -247,75 +247,83 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
return super.visit(returnStmt)
|
return super.visit(returnStmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(refLiteral: ReferenceLiteralValue): Expression {
|
override fun visit(arrayLiteral: ArrayLiteralValue): Expression {
|
||||||
val litval = super.visit(refLiteral)
|
val array = super.visit(arrayLiteral)
|
||||||
if(litval is ReferenceLiteralValue) {
|
if(array is ArrayLiteralValue) {
|
||||||
val vardecl = litval.parent as? VarDecl
|
val vardecl = array.parent as? VarDecl
|
||||||
if (litval.isString) {
|
return if (vardecl!=null) {
|
||||||
// intern the string; move it into the heap
|
fixupArrayDatatype(array, vardecl, program.heap)
|
||||||
if (litval.str!!.length !in 1..255)
|
} else {
|
||||||
checkResult.add(ExpressionError("string literal length must be between 1 and 255", litval.position))
|
// fix the datatype of the array (also on the heap) to the 'biggest' datatype in the array
|
||||||
else {
|
// (we don't know the desired datatype here exactly so we guess)
|
||||||
litval.addToHeap(program.heap)
|
val datatype = determineArrayDt(array.value)
|
||||||
}
|
val litval2 = array.cast(datatype)!!
|
||||||
return if(vardecl!=null)
|
litval2.parent = array.parent
|
||||||
litval
|
// finally, replace the literal array by a identifier reference.
|
||||||
else
|
makeIdentifierFromRefLv(litval2)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return array
|
||||||
return litval
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) }
|
val datatypesInArray = array.mapNotNull { it.inferType(program) }
|
||||||
if(datatypesInArray.isEmpty())
|
if(datatypesInArray.isEmpty())
|
||||||
return null
|
throw IllegalArgumentException("can't determine type of empty array")
|
||||||
if(DataType.FLOAT in datatypesInArray)
|
return when {
|
||||||
return DataType.ARRAY_F
|
DataType.FLOAT in datatypesInArray -> DataType.ARRAY_F
|
||||||
if(DataType.WORD in datatypesInArray)
|
DataType.WORD in datatypesInArray -> DataType.ARRAY_W
|
||||||
return DataType.ARRAY_W
|
DataType.UWORD in datatypesInArray -> DataType.ARRAY_UW
|
||||||
if(DataType.UWORD in datatypesInArray)
|
DataType.BYTE in datatypesInArray -> DataType.ARRAY_B
|
||||||
return DataType.ARRAY_UW
|
DataType.UBYTE in datatypesInArray -> DataType.ARRAY_UB
|
||||||
if(DataType.BYTE in datatypesInArray)
|
else -> throw IllegalArgumentException("can't determine type of array")
|
||||||
return DataType.ARRAY_B
|
}
|
||||||
if(DataType.UBYTE in datatypesInArray)
|
|
||||||
return DataType.ARRAY_UB
|
|
||||||
return null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeIdentifierFromRefLv(refLiteral: ReferenceLiteralValue): IdentifierReference {
|
private fun makeIdentifierFromRefLv(array: ArrayLiteralValue): IdentifierReference {
|
||||||
// a referencetype literal value that's not declared as a variable
|
// 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
|
// 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.
|
// note: if the var references the same literal value, it is not yet de-duplicated here.
|
||||||
refLiteral.addToHeap(program.heap)
|
array.addToHeap(program.heap)
|
||||||
val scope = refLiteral.definingScope()
|
val scope = array.definingScope()
|
||||||
var variable = VarDecl.createAuto(refLiteral, program.heap)
|
val variable = VarDecl.createAuto(array)
|
||||||
val existing = scope.lookup(listOf(variable.name), refLiteral)
|
return replaceWithIdentifier(variable, scope, array.parent)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(addressOf: AddressOf): Expression {
|
private fun makeIdentifierFromRefLv(string: StringLiteralValue): IdentifierReference {
|
||||||
// register the scoped name of the referenced identifier
|
// a referencetype literal value that's not declared as a variable
|
||||||
val variable= addressOf.identifier.targetVarDecl(program.namespace) ?: return addressOf
|
// we need to introduce an auto-generated variable for this to be able to refer to the value
|
||||||
return super.visit(addressOf)
|
// 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 {
|
override fun visit(structDecl: StructDecl): Statement {
|
||||||
@ -330,33 +338,28 @@ internal class AstIdentifiersChecker(private val program: Program) : IAstModifyi
|
|||||||
|
|
||||||
override fun visit(expr: BinaryExpression): Expression {
|
override fun visit(expr: BinaryExpression): Expression {
|
||||||
return when {
|
return when {
|
||||||
expr.left is ReferenceLiteralValue ->
|
expr.left is StringLiteralValue ->
|
||||||
processBinaryExprWithReferenceVal(expr.left as ReferenceLiteralValue, expr.right, expr)
|
processBinaryExprWithString(expr.left as StringLiteralValue, expr.right, expr)
|
||||||
expr.right is ReferenceLiteralValue ->
|
expr.right is StringLiteralValue ->
|
||||||
processBinaryExprWithReferenceVal(expr.right as ReferenceLiteralValue, expr.left, expr)
|
processBinaryExprWithString(expr.right as StringLiteralValue, expr.left, expr)
|
||||||
else -> super.visit(expr)
|
else -> super.visit(expr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processBinaryExprWithReferenceVal(refLv: ReferenceLiteralValue, operand: Expression, expr: BinaryExpression): Expression {
|
private fun processBinaryExprWithString(string: StringLiteralValue, operand: Expression, expr: BinaryExpression): Expression {
|
||||||
// expressions on strings or arrays
|
val constvalue = operand.constValue(program)
|
||||||
if(refLv.isString) {
|
if(constvalue!=null) {
|
||||||
val constvalue = operand.constValue(program)
|
if (expr.operator == "*") {
|
||||||
if(constvalue!=null) {
|
// repeat a string a number of times
|
||||||
if (expr.operator == "*") {
|
return StringLiteralValue(string.inferType(program),
|
||||||
// repeat a string a number of times
|
string.value.repeat(constvalue.number.toInt()), null, expr.position)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(expr.operator == "+" && operand is StringLiteralValue) {
|
||||||
|
// concatenate two strings
|
||||||
|
return StringLiteralValue(string.inferType(program),
|
||||||
|
"${string.value}${operand.value}", null, expr.position)
|
||||||
|
}
|
||||||
return expr
|
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) {
|
if(array.heapId!=null) {
|
||||||
val arrayDt = array.type
|
val arrayDt = array.type
|
||||||
if(arrayDt!=vardecl.datatype) {
|
if(arrayDt!=vardecl.datatype) {
|
||||||
@ -386,7 +389,7 @@ internal fun fixupArrayDatatype(array: ReferenceLiteralValue, vardecl: VarDecl,
|
|||||||
} catch(x: ExpressionError) {
|
} catch(x: ExpressionError) {
|
||||||
// couldn't cast permanently.
|
// couldn't cast permanently.
|
||||||
// instead, simply adjust the array type and trust the AstChecker to report the exact error
|
// 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
|
vardecl.value = litval2
|
||||||
litval2.linkParents(vardecl)
|
litval2.linkParents(vardecl)
|
||||||
|
@ -110,14 +110,16 @@ interface IAstModifyingVisitor {
|
|||||||
return literalValue
|
return literalValue
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(refLiteral: ReferenceLiteralValue): Expression {
|
fun visit(stringLiteral: StringLiteralValue): Expression {
|
||||||
if(refLiteral.array!=null) {
|
return stringLiteral
|
||||||
for(av in refLiteral.array.withIndex()) {
|
}
|
||||||
val newvalue = av.value.accept(this)
|
|
||||||
refLiteral.array[av.index] = newvalue
|
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 {
|
fun visit(assignment: Assignment): Statement {
|
||||||
|
@ -79,8 +79,11 @@ interface IAstVisitor {
|
|||||||
fun visit(numLiteral: NumericLiteralValue) {
|
fun visit(numLiteral: NumericLiteralValue) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(refLiteral: ReferenceLiteralValue) {
|
fun visit(string: StringLiteralValue) {
|
||||||
refLiteral.array?.let { it.forEach { v->v.accept(this) }}
|
}
|
||||||
|
|
||||||
|
fun visit(array: ArrayLiteralValue) {
|
||||||
|
array.value.forEach { v->v.accept(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(assignment: Assignment) {
|
fun visit(assignment: Assignment) {
|
||||||
|
@ -42,7 +42,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
|
|||||||
if(decl.isArray && decl.value==null) {
|
if(decl.isArray && decl.value==null) {
|
||||||
// array datatype without initialization value, add list of zeros
|
// array datatype without initialization value, add list of zeros
|
||||||
val arraysize = decl.arraysize!!.size()!!
|
val arraysize = decl.arraysize!!.size()!!
|
||||||
val array = ReferenceLiteralValue(decl.datatype, null,
|
val array = ArrayLiteralValue(decl.datatype,
|
||||||
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
|
Array(arraysize) { NumericLiteralValue.optimalInteger(0, decl.position) },
|
||||||
null, decl.position)
|
null, decl.position)
|
||||||
array.addToHeap(program.heap)
|
array.addToHeap(program.heap)
|
||||||
@ -107,7 +107,7 @@ internal class VarInitValueAndAddressOfCreator(private val program: Program): IA
|
|||||||
if(argparam.second is AddressOf)
|
if(argparam.second is AddressOf)
|
||||||
continue
|
continue
|
||||||
val idref = argparam.second as? IdentifierReference
|
val idref = argparam.second as? IdentifierReference
|
||||||
val strvalue = argparam.second as? ReferenceLiteralValue
|
val strvalue = argparam.second as? StringLiteralValue
|
||||||
if(idref!=null) {
|
if(idref!=null) {
|
||||||
val variable = idref.targetVarDecl(program.namespace)
|
val variable = idref.targetVarDecl(program.namespace)
|
||||||
if(variable!=null && (variable.datatype in StringDatatypes || variable.datatype in ArrayDatatypes)) {
|
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) {
|
else if(strvalue!=null) {
|
||||||
if(strvalue.isString) {
|
// add a vardecl so that the autovar can be resolved in later lookups
|
||||||
// add a vardecl so that the autovar can be resolved in later lookups
|
val variable = VarDecl.createAuto(strvalue)
|
||||||
val variable = VarDecl.createAuto(strvalue, program.heap)
|
addVarDecl(strvalue.definingScope(), variable)
|
||||||
addVarDecl(strvalue.definingScope(), variable)
|
// replace the argument with &autovar
|
||||||
// replace the argument with &autovar
|
val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position)
|
||||||
val autoHeapvarRef = IdentifierReference(listOf(variable.name), strvalue.position)
|
val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position)
|
||||||
val pointerExpr = AddressOf(autoHeapvarRef, strvalue.position)
|
pointerExpr.linkParents(arglist[argparam.first.index].parent)
|
||||||
pointerExpr.linkParents(arglist[argparam.first.index].parent)
|
arglist[argparam.first.index] = pointerExpr
|
||||||
arglist[argparam.first.index] = pointerExpr
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@ import prog8.ast.base.*
|
|||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.processing.IAstModifyingVisitor
|
import prog8.ast.processing.IAstModifyingVisitor
|
||||||
import prog8.ast.processing.IAstVisitor
|
import prog8.ast.processing.IAstVisitor
|
||||||
import prog8.compiler.HeapValues
|
|
||||||
|
|
||||||
|
|
||||||
sealed class Statement : Node {
|
sealed class Statement : Node {
|
||||||
@ -111,8 +110,6 @@ data class Label(val name: String, override val position: Position) : Statement(
|
|||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Label(name=$name, pos=$position)"
|
return "Label(name=$name, pos=$position)"
|
||||||
}
|
}
|
||||||
|
|
||||||
val scopedname: String by lazy { makeScopedName(name) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
open class Return(var value: Expression?, override val position: Position) : Statement() {
|
open class Return(var value: Expression?, override val position: Position) : Statement() {
|
||||||
@ -197,20 +194,23 @@ class VarDecl(val type: VarDeclType,
|
|||||||
companion object {
|
companion object {
|
||||||
private var autoHeapValueSequenceNumber = 0
|
private var autoHeapValueSequenceNumber = 0
|
||||||
|
|
||||||
fun createAuto(refLv: ReferenceLiteralValue, heap: HeapValues): VarDecl {
|
fun createAuto(string: StringLiteralValue): VarDecl {
|
||||||
if(refLv.heapId==null)
|
if(string.heapId==null)
|
||||||
throw FatalAstException("can only create autovar for a ref lv that has a heapid $refLv")
|
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}"
|
val autoVarName = "auto_heap_value_${++autoHeapValueSequenceNumber}"
|
||||||
return if(refLv.isArray) {
|
val declaredType = ArrayElementTypes.getValue(array.type)
|
||||||
val declaredType = ArrayElementTypes.getValue(refLv.type)
|
val arraysize = ArrayIndex.forArray(array)
|
||||||
val arraysize = ArrayIndex.forArray(refLv, heap)
|
return VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, array,
|
||||||
VarDecl(VarDeclType.VAR, declaredType, ZeropageWish.NOT_IN_ZEROPAGE, arraysize, autoVarName, null, refLv,
|
isArray = true, autogeneratedDontRemove = true, position = array.position)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,12 +284,6 @@ class VarDecl(val type: VarDeclType,
|
|||||||
structHasBeenFlattened = true
|
structHasBeenFlattened = true
|
||||||
return result
|
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 {
|
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 {
|
companion object {
|
||||||
fun forArray(v: ReferenceLiteralValue, heap: HeapValues): ArrayIndex {
|
fun forArray(v: ArrayLiteralValue): ArrayIndex {
|
||||||
val arraySize = v.array?.size ?: heap.get(v.heapId!!).arraysize
|
return ArrayIndex(NumericLiteralValue.optimalNumeric(v.value.size, v.position), v.position)
|
||||||
return ArrayIndex(NumericLiteralValue.optimalNumeric(arraySize, v.position), v.position)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor {
|
|||||||
super.visit(program)
|
super.visit(program)
|
||||||
for((scope, decls) in varsToMove) {
|
for((scope, decls) in varsToMove) {
|
||||||
val sub = scope.definingSubroutine()!!
|
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
|
var conflicts = false
|
||||||
decls.forEach {
|
decls.forEach {
|
||||||
val existing = existingVariables[it.name]
|
val existing = existingVariables[it.name]
|
||||||
|
@ -251,7 +251,7 @@ internal class AsmGen2(val program: Program,
|
|||||||
DataType.FLOAT -> out("${decl.name}\t.byte 0,0,0,0,0 ; float")
|
DataType.FLOAT -> out("${decl.name}\t.byte 0,0,0,0,0 ; float")
|
||||||
DataType.STRUCT -> {} // is flattened
|
DataType.STRUCT -> {} // is flattened
|
||||||
DataType.STR, DataType.STR_S -> {
|
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)
|
val encoded = encodeStr(string, decl.datatype)
|
||||||
outputStringvar(decl, encoded)
|
outputStringvar(decl, encoded)
|
||||||
}
|
}
|
||||||
@ -296,7 +296,7 @@ internal class AsmGen2(val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
DataType.ARRAY_F -> {
|
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 floatFills = array.map {
|
||||||
val number = (it as NumericLiteralValue).number
|
val number = (it as NumericLiteralValue).number
|
||||||
makeFloatFill(MachineDefinition.Mflpt5.fromNumber(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
|
// special treatment for string types: merge strings that are identical
|
||||||
val encodedstringVars = normalVars
|
val encodedstringVars = normalVars
|
||||||
.filter {it.datatype in StringDatatypes }
|
.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})
|
.groupBy({it.second}, {it.first})
|
||||||
for((encoded, variables) in encodedstringVars) {
|
for((encoded, variables) in encodedstringVars) {
|
||||||
variables.dropLast(1).forEach { out(it.name) }
|
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>) {
|
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>")}\"")
|
out("${lastvar.name}\t; ${lastvar.datatype} \"${escape(string).replace("\u0000", "<NULL>")}\"")
|
||||||
val outputBytes = encoded.map { "$" + it.toString(16).padStart(2, '0') }
|
val outputBytes = encoded.map { "$" + it.toString(16).padStart(2, '0') }
|
||||||
for (chunk in outputBytes.chunked(16))
|
for (chunk in outputBytes.chunked(16))
|
||||||
@ -361,7 +361,7 @@ internal class AsmGen2(val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun makeArrayFillDataUnsigned(decl: VarDecl): List<String> {
|
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 {
|
return when {
|
||||||
decl.datatype == DataType.ARRAY_UB ->
|
decl.datatype == DataType.ARRAY_UB ->
|
||||||
// byte array can never contain pointer-to types, so treat values as all integers
|
// 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> {
|
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 {
|
return when {
|
||||||
decl.datatype == DataType.ARRAY_UB ->
|
decl.datatype == DataType.ARRAY_UB ->
|
||||||
@ -808,22 +808,31 @@ internal class AsmGen2(val program: Program,
|
|||||||
is NumericLiteralValue -> {
|
is NumericLiteralValue -> {
|
||||||
// optimize when the argument is a constant literal
|
// optimize when the argument is a constant literal
|
||||||
val hex = value.number.toHex()
|
val hex = value.number.toHex()
|
||||||
if (register == RegisterOrPair.AX) out(" lda #<$hex | ldx #>$hex")
|
when (register) {
|
||||||
else if (register == RegisterOrPair.AY) out(" lda #<$hex | ldy #>$hex")
|
RegisterOrPair.AX -> out(" lda #<$hex | ldx #>$hex")
|
||||||
else if (register == RegisterOrPair.XY) out(" ldx #<$hex | ldy #>$hex")
|
RegisterOrPair.AY -> out(" lda #<$hex | ldy #>$hex")
|
||||||
|
RegisterOrPair.XY -> out(" ldx #<$hex | ldy #>$hex")
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is AddressOf -> {
|
is AddressOf -> {
|
||||||
// optimize when the argument is an address of something
|
// optimize when the argument is an address of something
|
||||||
val sourceName = asmIdentifierName(value.identifier)
|
val sourceName = asmIdentifierName(value.identifier)
|
||||||
if (register == RegisterOrPair.AX) out(" lda #<$sourceName | ldx #>$sourceName")
|
when (register) {
|
||||||
else if (register == RegisterOrPair.AY) out(" lda #<$sourceName | ldy #>$sourceName")
|
RegisterOrPair.AX -> out(" lda #<$sourceName | ldx #>$sourceName")
|
||||||
else if (register == RegisterOrPair.XY) out(" ldx #<$sourceName | ldy #>$sourceName")
|
RegisterOrPair.AY -> out(" lda #<$sourceName | ldy #>$sourceName")
|
||||||
|
RegisterOrPair.XY -> out(" ldx #<$sourceName | ldy #>$sourceName")
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
is IdentifierReference -> {
|
is IdentifierReference -> {
|
||||||
val sourceName = asmIdentifierName(value)
|
val sourceName = asmIdentifierName(value)
|
||||||
if (register == RegisterOrPair.AX) out(" lda $sourceName | ldx $sourceName+1")
|
when (register) {
|
||||||
else if (register == RegisterOrPair.AY) out(" lda $sourceName | ldy $sourceName+1")
|
RegisterOrPair.AX -> out(" lda $sourceName | ldx $sourceName+1")
|
||||||
else if (register == RegisterOrPair.XY) out(" ldx $sourceName | ldy $sourceName+1")
|
RegisterOrPair.AY -> out(" lda $sourceName | ldy $sourceName+1")
|
||||||
|
RegisterOrPair.XY -> out(" ldx $sourceName | ldy $sourceName+1")
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
translateExpression(value)
|
translateExpression(value)
|
||||||
@ -1748,7 +1757,7 @@ $endLabel""")
|
|||||||
translateExpression(assign.value as FunctionCall)
|
translateExpression(assign.value as FunctionCall)
|
||||||
assignFromEvalResult(assign.target)
|
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 StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened")
|
||||||
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
||||||
}
|
}
|
||||||
@ -1851,7 +1860,7 @@ $endLabel""")
|
|||||||
translateSubroutineCall(expression)
|
translateSubroutineCall(expression)
|
||||||
val sub = expression.target.targetSubroutine(program.namespace)!!
|
val sub = expression.target.targetSubroutine(program.namespace)!!
|
||||||
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
val returns = sub.returntypes.zip(sub.asmReturnvaluesRegisters)
|
||||||
for((t, reg) in returns) {
|
for((_, reg) in returns) {
|
||||||
if(!reg.stack) {
|
if(!reg.stack) {
|
||||||
// result value in cpu or status registers, put it on the stack
|
// result value in cpu or status registers, put it on the stack
|
||||||
if(reg.registerOrPair!=null) {
|
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 StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened")
|
||||||
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
||||||
}
|
}
|
||||||
|
@ -115,9 +115,9 @@ val BuiltinFunctions = mapOf(
|
|||||||
fun builtinFunctionReturnType(function: String, args: List<Expression>, program: Program): DataType? {
|
fun builtinFunctionReturnType(function: String, args: List<Expression>, program: Program): DataType? {
|
||||||
|
|
||||||
fun datatypeFromIterableArg(arglist: Expression): 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) {
|
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}) {
|
if(dt.any { it!= DataType.UBYTE && it!= DataType.UWORD && it!= DataType.FLOAT}) {
|
||||||
throw FatalAstException("fuction $function only accepts arraysize of numeric values")
|
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)
|
NumericLiteralValue.optimalInteger(arraySize, args[0].position)
|
||||||
}
|
}
|
||||||
in StringDatatypes -> {
|
in StringDatatypes -> {
|
||||||
val refLv = target.value as ReferenceLiteralValue
|
val refLv = target.value as StringLiteralValue
|
||||||
if(refLv.str!!.length>255)
|
if(refLv.value.length>255)
|
||||||
throw CompilerException("string length exceeds byte limit ${refLv.position}")
|
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)
|
in NumericDatatypes -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
||||||
else -> throw CompilerException("weird datatype")
|
else -> throw CompilerException("weird datatype")
|
||||||
|
@ -39,11 +39,9 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
if(decl.isArray){
|
if(decl.isArray){
|
||||||
if(decl.arraysize==null) {
|
if(decl.arraysize==null) {
|
||||||
// for arrays that have no size specifier (or a non-constant one) attempt to deduce the size
|
// for arrays that have no size specifier (or a non-constant one) attempt to deduce the size
|
||||||
val arrayval = (decl.value as? ReferenceLiteralValue)?.array
|
val arrayval = (decl.value as ArrayLiteralValue).value
|
||||||
if(arrayval!=null) {
|
decl.arraysize = ArrayIndex(NumericLiteralValue.optimalInteger(arrayval.size, decl.position), decl.position)
|
||||||
decl.arraysize = ArrayIndex(NumericLiteralValue.optimalInteger(arrayval.size, decl.position), decl.position)
|
optimizationsDone++
|
||||||
optimizationsDone++
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(decl.arraysize?.size()==null) {
|
else if(decl.arraysize?.size()==null) {
|
||||||
val size = decl.arraysize!!.index.accept(this)
|
val size = decl.arraysize!!.index.accept(this)
|
||||||
@ -83,13 +81,13 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
if(constRange!=null) {
|
if(constRange!=null) {
|
||||||
val eltType = rangeExpr.inferType(program)!!
|
val eltType = rangeExpr.inferType(program)!!
|
||||||
if(eltType in ByteDatatypes) {
|
if(eltType in ByteDatatypes) {
|
||||||
decl.value = ReferenceLiteralValue(decl.datatype,
|
decl.value = ArrayLiteralValue(decl.datatype,
|
||||||
array = constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }
|
constRange.map { NumericLiteralValue(eltType, it.toShort(), decl.value!!.position) }.toTypedArray(),
|
||||||
.toTypedArray(), position = decl.value!!.position)
|
position = decl.value!!.position)
|
||||||
} else {
|
} else {
|
||||||
decl.value = ReferenceLiteralValue(decl.datatype,
|
decl.value = ArrayLiteralValue(decl.datatype,
|
||||||
array = constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }
|
constRange.map { NumericLiteralValue(eltType, it, decl.value!!.position) }.toTypedArray(),
|
||||||
.toTypedArray(), position = decl.value!!.position)
|
position = decl.value!!.position)
|
||||||
}
|
}
|
||||||
decl.value!!.linkParents(decl)
|
decl.value!!.linkParents(decl)
|
||||||
optimizationsDone++
|
optimizationsDone++
|
||||||
@ -123,7 +121,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
}
|
}
|
||||||
// create the array itself, filled with the fillvalue.
|
// create the array itself, filled with the fillvalue.
|
||||||
val array = Array(size) {fillvalue}.map { NumericLiteralValue.optimalInteger(it, numericLv.position) as Expression}.toTypedArray()
|
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)
|
refValue.addToHeap(program.heap)
|
||||||
decl.value = refValue
|
decl.value = refValue
|
||||||
refValue.parent=decl
|
refValue.parent=decl
|
||||||
@ -145,7 +143,7 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
else {
|
else {
|
||||||
// create the array itself, filled with the fillvalue.
|
// create the array itself, filled with the fillvalue.
|
||||||
val array = Array(size) {fillvalue}.map { NumericLiteralValue(DataType.FLOAT, it, litval.position) as Expression}.toTypedArray()
|
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)
|
refValue.addToHeap(program.heap)
|
||||||
decl.value = refValue
|
decl.value = refValue
|
||||||
refValue.parent=decl
|
refValue.parent=decl
|
||||||
@ -311,7 +309,8 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
return try {
|
return try {
|
||||||
super.visit(expr)
|
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")
|
throw FatalAstException("binexpr with reference litval instead of numeric")
|
||||||
|
|
||||||
val leftconst = expr.left.constValue(program)
|
val leftconst = expr.left.constValue(program)
|
||||||
@ -597,17 +596,15 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
|||||||
return resultStmt
|
return resultStmt
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(refLiteral: ReferenceLiteralValue): Expression {
|
override fun visit(arrayLiteral: ArrayLiteralValue): Expression {
|
||||||
val litval = super.visit(refLiteral)
|
val array = super.visit(arrayLiteral)
|
||||||
if(litval is ReferenceLiteralValue) {
|
if(array is ArrayLiteralValue) {
|
||||||
if (litval.isArray) {
|
val vardecl = array.parent as? VarDecl
|
||||||
val vardecl = litval.parent as? VarDecl
|
if (vardecl!=null) {
|
||||||
if (vardecl!=null) {
|
return fixupArrayDatatype(array, vardecl, program.heap)
|
||||||
return fixupArrayDatatype(litval, vardecl, program.heap)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return litval
|
return array
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(assignment: Assignment): Statement {
|
override fun visit(assignment: Assignment): Statement {
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
package prog8.optimizer
|
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.base.*
|
||||||
import prog8.ast.expressions.*
|
import prog8.ast.expressions.*
|
||||||
import prog8.ast.processing.IAstModifyingVisitor
|
import prog8.ast.processing.IAstModifyingVisitor
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
package prog8.vm
|
package prog8.vm
|
||||||
|
|
||||||
import prog8.ast.base.*
|
import prog8.ast.base.*
|
||||||
|
import prog8.ast.expressions.ArrayLiteralValue
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.ReferenceLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import prog8.compiler.HeapValues
|
import prog8.compiler.HeapValues
|
||||||
import prog8.compiler.target.c64.Petscii
|
import prog8.compiler.target.c64.Petscii
|
||||||
import java.util.*
|
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)
|
return RuntimeValue(literalValue.type, num = literalValue.number)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun fromLv(literalValue: ReferenceLiteralValue, heap: HeapValues): RuntimeValue {
|
fun fromLv(string: StringLiteralValue, heap: HeapValues): RuntimeValue = fromHeapId(string.heapId!!, heap)
|
||||||
return when(literalValue.type) {
|
fun fromLv(array: ArrayLiteralValue, heap: HeapValues): RuntimeValue = fromHeapId(array.heapId!!, heap)
|
||||||
in StringDatatypes -> fromHeapId(literalValue.heapId!!, heap)
|
|
||||||
in ArrayDatatypes -> fromHeapId(literalValue.heapId!!, heap)
|
|
||||||
else -> throw IllegalArgumentException("weird source value $literalValue")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun fromHeapId(heapId: Int, heap: HeapValues): RuntimeValue {
|
fun fromHeapId(heapId: Int, heap: HeapValues): RuntimeValue {
|
||||||
val value = heap.get(heapId)
|
val value = heap.get(heapId)
|
||||||
|
@ -166,10 +166,10 @@ class AstVm(val program: Program) {
|
|||||||
fun memwrite(address: Int, value: Short): Short {
|
fun memwrite(address: Int, value: Short): Short {
|
||||||
if(address==0xa0 || address==0xa1 || address==0xa2) {
|
if(address==0xa0 || address==0xa1 || address==0xa2) {
|
||||||
// a write to the jiffy clock, update the clock offset for the irq
|
// 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 timeHi = if(address==0xa0) value else mem.getUByte_DMA(0xa0)
|
||||||
val time_mid = if(address==0xa1) value else mem.getUByte_DMA(0xa1)
|
val timeMid = if(address==0xa1) value else mem.getUByte_DMA(0xa1)
|
||||||
val time_lo = if(address==0xa2) value else mem.getUByte_DMA(0xa2)
|
val timeLo = if(address==0xa2) value else mem.getUByte_DMA(0xa2)
|
||||||
val jiffies = (time_hi.toInt() shl 16) + (time_mid.toInt() shl 8) + time_lo
|
val jiffies = (timeHi.toInt() shl 16) + (timeMid.toInt() shl 8) + timeLo
|
||||||
rtcOffset = bootTime - (jiffies*1000/60)
|
rtcOffset = bootTime - (jiffies*1000/60)
|
||||||
}
|
}
|
||||||
if(address in 1024..2023) {
|
if(address in 1024..2023) {
|
||||||
|
@ -30,12 +30,9 @@ fun evaluate(expr: Expression, ctx: EvalContext): RuntimeValue {
|
|||||||
return RuntimeValue.fromLv(constval)
|
return RuntimeValue.fromLv(constval)
|
||||||
|
|
||||||
when(expr) {
|
when(expr) {
|
||||||
is NumericLiteralValue -> {
|
is NumericLiteralValue -> return RuntimeValue.fromLv(expr)
|
||||||
return RuntimeValue.fromLv(expr)
|
is StringLiteralValue -> return RuntimeValue.fromLv(expr, ctx.program.heap)
|
||||||
}
|
is ArrayLiteralValue -> return RuntimeValue.fromLv(expr, ctx.program.heap)
|
||||||
is ReferenceLiteralValue -> {
|
|
||||||
return RuntimeValue.fromLv(expr, ctx.program.heap)
|
|
||||||
}
|
|
||||||
is PrefixExpression -> {
|
is PrefixExpression -> {
|
||||||
return when(expr.operator) {
|
return when(expr.operator) {
|
||||||
"-" -> evaluate(expr.expression, ctx).neg()
|
"-" -> evaluate(expr.expression, ctx).neg()
|
||||||
|
@ -5,8 +5,9 @@ import prog8.ast.base.DataType
|
|||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.base.Register
|
import prog8.ast.base.Register
|
||||||
import prog8.ast.base.VarDeclType
|
import prog8.ast.base.VarDeclType
|
||||||
|
import prog8.ast.expressions.ArrayLiteralValue
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.ReferenceLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import prog8.ast.processing.IAstModifyingVisitor
|
import prog8.ast.processing.IAstModifyingVisitor
|
||||||
import prog8.ast.statements.Statement
|
import prog8.ast.statements.Statement
|
||||||
import prog8.ast.statements.StructDecl
|
import prog8.ast.statements.StructDecl
|
||||||
@ -50,8 +51,10 @@ class VariablesCreator(private val runtimeVariables: RuntimeVariables, private v
|
|||||||
val value = if(numericLv!=null) {
|
val value = if(numericLv!=null) {
|
||||||
RuntimeValue.fromLv(numericLv)
|
RuntimeValue.fromLv(numericLv)
|
||||||
} else {
|
} else {
|
||||||
val referenceLv = decl.value as ReferenceLiteralValue
|
if(decl.value is StringLiteralValue)
|
||||||
RuntimeValue.fromLv(referenceLv, heap)
|
RuntimeValue.fromLv(decl.value as StringLiteralValue, heap)
|
||||||
|
else
|
||||||
|
RuntimeValue.fromLv(decl.value as ArrayLiteralValue, heap)
|
||||||
}
|
}
|
||||||
runtimeVariables.define(decl.definingScope(), decl.name, value)
|
runtimeVariables.define(decl.definingScope(), decl.name, value)
|
||||||
}
|
}
|
||||||
|
@ -4,8 +4,9 @@ import org.junit.jupiter.api.Test
|
|||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
|
import prog8.ast.expressions.ArrayLiteralValue
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.ReferenceLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertFalse
|
import kotlin.test.assertFalse
|
||||||
import kotlin.test.assertNotEquals
|
import kotlin.test.assertNotEquals
|
||||||
@ -16,10 +17,6 @@ private fun sameValueAndType(lv1: NumericLiteralValue, lv2: NumericLiteralValue)
|
|||||||
return lv1.type==lv2.type && lv1==lv2
|
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)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
class TestParserNumericLiteralValue {
|
class TestParserNumericLiteralValue {
|
||||||
@ -86,8 +83,8 @@ class TestParserNumericLiteralValue {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testEqualsRef() {
|
fun testEqualsRef() {
|
||||||
assertTrue(sameValueAndType(ReferenceLiteralValue(DataType.STR, str = "hello", position = dummyPos), ReferenceLiteralValue(DataType.STR, str = "hello", position = dummyPos)))
|
assertTrue(StringLiteralValue(DataType.STR, "hello", position = dummyPos) == StringLiteralValue(DataType.STR, "hello", position = dummyPos))
|
||||||
assertFalse(sameValueAndType(ReferenceLiteralValue(DataType.STR, str = "hello", position = dummyPos), ReferenceLiteralValue(DataType.STR, str = "bye", position = dummyPos)))
|
assertFalse(StringLiteralValue(DataType.STR, "hello", position = dummyPos) == StringLiteralValue(DataType.STR, "bye", position = dummyPos))
|
||||||
|
|
||||||
val lvOne = NumericLiteralValue(DataType.UBYTE, 1, dummyPos)
|
val lvOne = NumericLiteralValue(DataType.UBYTE, 1, dummyPos)
|
||||||
val lvTwo = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)
|
val lvTwo = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)
|
||||||
@ -96,9 +93,9 @@ class TestParserNumericLiteralValue {
|
|||||||
val lvTwoR = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)
|
val lvTwoR = NumericLiteralValue(DataType.UBYTE, 2, dummyPos)
|
||||||
val lvThreeR = NumericLiteralValue(DataType.UBYTE, 3, dummyPos)
|
val lvThreeR = NumericLiteralValue(DataType.UBYTE, 3, dummyPos)
|
||||||
val lvFour= NumericLiteralValue(DataType.UBYTE, 4, dummyPos)
|
val lvFour= NumericLiteralValue(DataType.UBYTE, 4, dummyPos)
|
||||||
val lv1 = ReferenceLiteralValue(DataType.ARRAY_UB, array = arrayOf(lvOne, lvTwo, lvThree), position = dummyPos)
|
val lv1 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOne, lvTwo, lvThree), position = dummyPos)
|
||||||
val lv2 = ReferenceLiteralValue(DataType.ARRAY_UB, array = arrayOf(lvOneR, lvTwoR, lvThreeR), position = dummyPos)
|
val lv2 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvThreeR), position = dummyPos)
|
||||||
val lv3 = ReferenceLiteralValue(DataType.ARRAY_UB, array = arrayOf(lvOneR, lvTwoR, lvFour), position = dummyPos)
|
val lv3 = ArrayLiteralValue(DataType.ARRAY_UB, arrayOf(lvOneR, lvTwoR, lvFour), position = dummyPos)
|
||||||
assertEquals(lv1, lv2)
|
assertEquals(lv1, lv2)
|
||||||
assertNotEquals(lv1, lv3)
|
assertNotEquals(lv1, lv3)
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import org.junit.jupiter.api.TestInstance
|
|||||||
import prog8.ast.base.DataType
|
import prog8.ast.base.DataType
|
||||||
import prog8.ast.base.Position
|
import prog8.ast.base.Position
|
||||||
import prog8.ast.expressions.NumericLiteralValue
|
import prog8.ast.expressions.NumericLiteralValue
|
||||||
import prog8.ast.expressions.ReferenceLiteralValue
|
import prog8.ast.expressions.StringLiteralValue
|
||||||
import prog8.compiler.*
|
import prog8.compiler.*
|
||||||
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage
|
import prog8.compiler.target.c64.MachineDefinition.C64Zeropage
|
||||||
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE
|
import prog8.compiler.target.c64.MachineDefinition.FLOAT_MAX_NEGATIVE
|
||||||
@ -371,8 +371,8 @@ class TestPetscii {
|
|||||||
assertTrue(ten <= ten)
|
assertTrue(ten <= ten)
|
||||||
assertFalse(ten < ten)
|
assertFalse(ten < ten)
|
||||||
|
|
||||||
val abc = ReferenceLiteralValue(DataType.STR, str = "abc", position = Position("", 0, 0, 0))
|
val abc = StringLiteralValue(DataType.STR, "abc", position = Position("", 0, 0, 0))
|
||||||
val abd = ReferenceLiteralValue(DataType.STR, str = "abd", position = Position("", 0, 0, 0))
|
val abd = StringLiteralValue(DataType.STR, "abd", position = Position("", 0, 0, 0))
|
||||||
assertEquals(abc, abc)
|
assertEquals(abc, abc)
|
||||||
assertTrue(abc!=abd)
|
assertTrue(abc!=abd)
|
||||||
assertFalse(abc!=abc)
|
assertFalse(abc!=abc)
|
||||||
|
@ -6,42 +6,9 @@
|
|||||||
main {
|
main {
|
||||||
|
|
||||||
sub start() {
|
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.")
|
c64scr.print("\nyou should see no errors above.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user