mirror of
https://github.com/irmen/prog8.git
synced 2024-06-30 02:29:51 +00:00
implemented floating-point arrays
This commit is contained in:
parent
0cdae48ce7
commit
38e7d48492
|
@ -4,18 +4,54 @@
|
|||
|
||||
sub start() {
|
||||
|
||||
byte[100] array
|
||||
byte[4,5] mvar
|
||||
byte[10] barray1
|
||||
byte[10] barray2 = 11
|
||||
byte[10] barray3 = [1,2,3,4,5,6,7,8,9,255]
|
||||
|
||||
A=AX[2]
|
||||
A=AY[2]
|
||||
A=XY[2]
|
||||
word[10] warray1
|
||||
word[10] warray2 = 112233
|
||||
word[10] warray3 = [1,2,3,4,5,6,7,8,9, 65535]
|
||||
|
||||
byte[4,5] mvar1
|
||||
byte[4,5] mvar2 = 22
|
||||
byte[2,3] mvar3 = [1,2,3,4,5,6]
|
||||
|
||||
float[3] farray1
|
||||
float[3] farray2 = 33.44
|
||||
float[3] farray2b = 33
|
||||
float[3] farray3 = [1,2,3]
|
||||
float[3] farray4 = [1,2,35566]
|
||||
float[3] farray5 = [1,2.22334,3.1415]
|
||||
|
||||
|
||||
byte i
|
||||
word w
|
||||
|
||||
for i in 0 to 2 {
|
||||
_vm_write_num(farray5[i])
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
for w in [1,2,3777] { ;@todo loop over array literal
|
||||
_vm_write_num(w)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
for i in barray3 { ; @todo loop over symbol
|
||||
_vm_write_num(i)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
for i in "hello" { ; @todo loop over string
|
||||
_vm_write_num(i)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
for w in "hello" { ; @todo loop over string
|
||||
_vm_write_num(w)
|
||||
_vm_write_char('\n')
|
||||
}
|
||||
|
||||
A=array[98]
|
||||
A=array[99]
|
||||
A=mvar[13]
|
||||
A=mvar[2,3]
|
||||
A=mvar[Y,X]
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package prog8.ast
|
|||
import org.antlr.v4.runtime.ParserRuleContext
|
||||
import org.antlr.v4.runtime.tree.TerminalNode
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.target.c64.Mflpt5
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
import prog8.compiler.unescape
|
||||
import prog8.functions.BuiltinFunctions
|
||||
|
@ -26,6 +27,7 @@ enum class DataType {
|
|||
STR_PS,
|
||||
ARRAY,
|
||||
ARRAY_W,
|
||||
ARRAY_F,
|
||||
MATRIX
|
||||
}
|
||||
|
||||
|
@ -60,7 +62,9 @@ enum class BranchCondition {
|
|||
POS
|
||||
}
|
||||
|
||||
val IterableDatatypes = setOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX)
|
||||
val IterableDatatypes = setOf(
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX)
|
||||
|
||||
class FatalAstException (override var message: String) : Exception(message)
|
||||
|
||||
|
@ -599,8 +603,9 @@ class VarDecl(val type: VarDeclType,
|
|||
else -> when (declaredDatatype) {
|
||||
DataType.BYTE -> DataType.ARRAY
|
||||
DataType.WORD -> DataType.ARRAY_W
|
||||
DataType.FLOAT -> DataType.ARRAY_F
|
||||
else -> {
|
||||
datatypeErrors.add(SyntaxError("array can only contain bytes or words", position))
|
||||
datatypeErrors.add(SyntaxError("array can only contain bytes/words/floats", position))
|
||||
DataType.BYTE
|
||||
}
|
||||
}
|
||||
|
@ -620,7 +625,7 @@ class VarDecl(val type: VarDeclType,
|
|||
get() = when(datatype) {
|
||||
DataType.BYTE -> 1
|
||||
DataType.WORD -> 2
|
||||
DataType.FLOAT -> 5 // MFLPT5
|
||||
DataType.FLOAT -> Mflpt5.MemorySize
|
||||
DataType.STR,
|
||||
DataType.STR_P,
|
||||
DataType.STR_S,
|
||||
|
@ -636,6 +641,10 @@ class VarDecl(val type: VarDeclType,
|
|||
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||
2*aX.asIntegerValue!!
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||
Mflpt5.MemorySize*aX.asIntegerValue!!
|
||||
}
|
||||
DataType.MATRIX -> {
|
||||
val aX = arrayspec?.x as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||
val aY = arrayspec.y as? LiteralValue ?: throw ExpressionError("need constant value expression for arrayspec", position)
|
||||
|
@ -833,10 +842,11 @@ class ArrayIndexedExpression(val identifier: IdentifierReference?,
|
|||
val target = identifier?.targetStatement(namespace)
|
||||
if (target is VarDecl) {
|
||||
return when (target.datatype) {
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> null
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
else -> null
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
}
|
||||
}
|
||||
throw FatalAstException("cannot get indexed element on $target")
|
||||
|
@ -861,7 +871,7 @@ class LiteralValue(val type: DataType,
|
|||
|
||||
val isString = type==DataType.STR || type==DataType.STR_P || type==DataType.STR_S || type==DataType.STR_PS
|
||||
val isNumeric = type==DataType.BYTE || type==DataType.WORD || type==DataType.FLOAT
|
||||
val isArray = type==DataType.ARRAY || type==DataType.ARRAY_W || type==DataType.MATRIX
|
||||
val isArray = type==DataType.ARRAY || type==DataType.ARRAY_W || type==DataType.ARRAY_F || type==DataType.MATRIX
|
||||
|
||||
companion object {
|
||||
fun fromBoolean(bool: Boolean, position: Position) =
|
||||
|
@ -908,7 +918,7 @@ class LiteralValue(val type: DataType,
|
|||
DataType.FLOAT -> if(floatvalue==null) throw FatalAstException("literal value missing floatvalue")
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS ->
|
||||
if(strvalue==null && heapId==null) throw FatalAstException("literal value missing strvalue/heapId")
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX ->
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX ->
|
||||
if(arrayvalue==null && heapId==null) throw FatalAstException("literal value missing arrayvalue/heapId")
|
||||
}
|
||||
if(bytevalue==null && wordvalue==null && floatvalue==null && arrayvalue==null && strvalue==null && heapId==null)
|
||||
|
@ -952,7 +962,7 @@ class LiteralValue(val type: DataType,
|
|||
if(heapId!=null) "str:#$heapId"
|
||||
else "str:$strvalue"
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W -> {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F -> {
|
||||
if(heapId!=null) "array:#$heapId"
|
||||
else "array:$arrayvalue"
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package prog8.ast
|
|||
|
||||
import prog8.compiler.CompilationOptions
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
|
||||
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
|
||||
import prog8.functions.BuiltinFunctions
|
||||
import prog8.parser.ParsingFailedError
|
||||
|
||||
|
@ -111,7 +113,7 @@ class AstChecker(private val namespace: INameScope,
|
|||
if (iterableDt != DataType.WORD && iterableDt != DataType.BYTE &&
|
||||
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
||||
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS &&
|
||||
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX)
|
||||
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.ARRAY_F && iterableDt!=DataType.MATRIX)
|
||||
checkResult.add(ExpressionError("register pair can only loop over words", forLoop.position))
|
||||
}
|
||||
}
|
||||
|
@ -127,13 +129,16 @@ class AstChecker(private val namespace: INameScope,
|
|||
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.ARRAY && iterableDt!=DataType.MATRIX &&
|
||||
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
||||
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
|
||||
checkResult.add(ExpressionError("can only loop over bytes", forLoop.position))
|
||||
checkResult.add(ExpressionError("byte loop variable can only loop over bytes", forLoop.position))
|
||||
}
|
||||
DataType.WORD -> {
|
||||
if(iterableDt!=DataType.BYTE && iterableDt!=DataType.WORD &&
|
||||
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX)
|
||||
checkResult.add(ExpressionError("can only loop over bytes or words", forLoop.position))
|
||||
iterableDt !=DataType.ARRAY && iterableDt!=DataType.ARRAY_W && iterableDt!=DataType.MATRIX &&
|
||||
iterableDt != DataType.STR && iterableDt != DataType.STR_P &&
|
||||
iterableDt != DataType.STR_S && iterableDt != DataType.STR_PS)
|
||||
checkResult.add(ExpressionError("word loop variable can only loop over bytes or words", forLoop.position))
|
||||
}
|
||||
// there's no support for a floating-point loop variable
|
||||
else -> checkResult.add(ExpressionError("loop variable must be byte or word type", forLoop.position))
|
||||
}
|
||||
}
|
||||
|
@ -331,7 +336,7 @@ class AstChecker(private val namespace: INameScope,
|
|||
litVal.parent = decl
|
||||
decl.value = litVal
|
||||
}
|
||||
else -> err("var/const declaration needs a compile-time constant initializer value for this type")
|
||||
else -> err("var/const declaration needs a compile-time constant initializer value for this type") // const fold should have provided it!
|
||||
}
|
||||
return super.process(decl)
|
||||
}
|
||||
|
@ -438,11 +443,11 @@ class AstChecker(private val namespace: INameScope,
|
|||
if(lv.heapId==null)
|
||||
throw FatalAstException("string should have been moved to heap at ${lv.position}")
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||
if(lv.heapId==null)
|
||||
throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}")
|
||||
}
|
||||
else -> {}
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> {}
|
||||
}
|
||||
return lv
|
||||
}
|
||||
|
@ -626,7 +631,7 @@ class AstChecker(private val namespace: INameScope,
|
|||
}
|
||||
return true
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||
// range and length check bytes
|
||||
val expectedSize = arrayspec!!.size()
|
||||
val rangeSize=range.size()
|
||||
|
@ -721,17 +726,39 @@ class AstChecker(private val namespace: INameScope,
|
|||
return err("value '$number' out of range for unsigned word")
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
// value may be either a single float, or a float array
|
||||
if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W || value.type==DataType.ARRAY_F) {
|
||||
val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).doubleArray!!.size
|
||||
if(arrayspec!=null) {
|
||||
// arrayspec is not always known when checking
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null)
|
||||
return err("array size specifier must be constant integer value")
|
||||
val expectedSize = constX.asIntegerValue
|
||||
if (arraySize != expectedSize)
|
||||
return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)")
|
||||
}
|
||||
} else {
|
||||
val number = value.asNumericValue!!.toDouble()
|
||||
if (number < FLOAT_MAX_NEGATIVE || number > FLOAT_MAX_POSITIVE)
|
||||
return err("value '$number' out of range for mfplt5 floating point")
|
||||
}
|
||||
}
|
||||
DataType.MATRIX -> {
|
||||
// value can only be a single byte, or a byte array (which represents the matrix)
|
||||
if(value.type==DataType.ARRAY || value.type==DataType.MATRIX) {
|
||||
val constX = arrayspec!!.x.constValue(namespace, heap)
|
||||
val constY = arrayspec.y!!.constValue(namespace, heap)
|
||||
if(constX?.asIntegerValue==null || constY?.asIntegerValue==null)
|
||||
return err("matrix size specifiers must be constant integer values")
|
||||
val matrix = heap.get(value.heapId!!).array!!
|
||||
val expectedSize = constX.asIntegerValue * constY.asIntegerValue
|
||||
if (matrix.size != expectedSize)
|
||||
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
||||
if(arrayspec!=null) {
|
||||
// arrayspec is not always known when checking
|
||||
val constX = arrayspec.x.constValue(namespace, heap)
|
||||
val constY = arrayspec.y!!.constValue(namespace, heap)
|
||||
if (constX?.asIntegerValue == null || constY?.asIntegerValue == null)
|
||||
return err("matrix size specifiers must be constant integer values")
|
||||
val matrix = heap.get(value.heapId!!).array!!
|
||||
val expectedSize = constX.asIntegerValue * constY.asIntegerValue
|
||||
if (matrix.size != expectedSize)
|
||||
return err("initializer matrix size mismatch (expecting $expectedSize, got ${matrix.size} elements)")
|
||||
}
|
||||
} else {
|
||||
val number = value.bytevalue
|
||||
?: return err("unsigned byte value expected")
|
||||
|
|
|
@ -51,18 +51,19 @@ fun String.unescape(): String {
|
|||
|
||||
|
||||
class HeapValues {
|
||||
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?) {
|
||||
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?, val doubleArray: DoubleArray?) {
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
other as HeapValue
|
||||
return type==other.type && str==other.str && Arrays.equals(array, other.array)
|
||||
return type==other.type && str==other.str && Arrays.equals(array, other.array) && Arrays.equals(doubleArray, other.doubleArray)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = type.hashCode()
|
||||
result = 31 * result + (str?.hashCode() ?: 0)
|
||||
result = 31 * result + (array?.let { Arrays.hashCode(it) } ?: 0)
|
||||
result = 31 * result + (doubleArray?.let { Arrays.hashCode(it) } ?: 0)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
@ -74,7 +75,7 @@ class HeapValues {
|
|||
throw IllegalArgumentException("string length must be 1-255")
|
||||
|
||||
// strings are 'interned' and shared if they're the same
|
||||
val value = HeapValue(type, str, null)
|
||||
val value = HeapValue(type, str, null, null)
|
||||
val existing = heap.indexOf(value)
|
||||
if(existing>=0)
|
||||
return existing
|
||||
|
@ -84,7 +85,13 @@ class HeapValues {
|
|||
|
||||
fun add(type: DataType, array: IntArray): Int {
|
||||
// arrays are never shared
|
||||
heap.add(HeapValue(type, null, array))
|
||||
heap.add(HeapValue(type, null, array, null))
|
||||
return heap.size-1
|
||||
}
|
||||
|
||||
fun add(type: DataType, darray: DoubleArray): Int {
|
||||
// arrays are never shared
|
||||
heap.add(HeapValue(type, null, null, darray))
|
||||
return heap.size-1
|
||||
}
|
||||
|
||||
|
@ -102,21 +109,15 @@ class HeapValues {
|
|||
}
|
||||
}
|
||||
|
||||
fun update(heapId: Int, array: IntArray) {
|
||||
when(heap[heapId].type){
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
if(heap[heapId].array!!.size != array.size)
|
||||
throw IllegalArgumentException("heap array length mismatch")
|
||||
heap[heapId] = heap[heapId].copy(array=array)
|
||||
}
|
||||
else-> throw IllegalArgumentException("heap data type mismatch")
|
||||
}
|
||||
fun update(heapId: Int, heapval: HeapValue) {
|
||||
heap[heapId] = heapval
|
||||
}
|
||||
|
||||
fun get(heapId: Int): HeapValue = heap[heapId]
|
||||
|
||||
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
|
||||
fun allArrays() = heap.asSequence().withIndex().filter { it.value.array!=null }.toList()
|
||||
fun allDoubleArrays() = heap.asSequence().withIndex().filter { it.value.doubleArray!=null }.toList()
|
||||
}
|
||||
|
||||
|
||||
|
@ -146,7 +147,7 @@ class StackVmProgram(val name: String, val heap: HeapValues) {
|
|||
throw CompilerException("string should already be in the heap")
|
||||
Value(decl.datatype, litval.heapId)
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||
val litval = (decl.value as LiteralValue)
|
||||
if(litval.heapId==null)
|
||||
throw CompilerException("array/matrix should already be in the heap")
|
||||
|
@ -458,7 +459,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||
throw CompilerException("string should have been moved into heap ${lv.position}")
|
||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||
}
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> {
|
||||
if(lv.heapId==null)
|
||||
throw CompilerException("array/matrix should have been moved into heap ${lv.position}")
|
||||
stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId))
|
||||
|
@ -688,7 +689,7 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||
}
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> throw CompilerException("incompatible data types valueDt=$valueDt targetDt=$targetDt at $stmt")
|
||||
// todo: maybe if you assign byte or word to array/matrix, clear it with that value?
|
||||
}
|
||||
}
|
||||
|
@ -799,18 +800,21 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
val litVal = loop.iterable as? LiteralValue
|
||||
val ident = loop.iterable as? IdentifierReference
|
||||
when {
|
||||
litVal?.strvalue != null -> {
|
||||
TODO("loop over string $litVal")
|
||||
}
|
||||
ident!=null -> {
|
||||
val symbol = ident.targetStatement(namespace)
|
||||
TODO("loop over symbol: ${ident.nameInSource} -> $symbol")
|
||||
}
|
||||
else -> throw CompilerException("loopvar is something strange ${loop.iterable}")
|
||||
val iterableValue: LiteralValue?
|
||||
if(loop.iterable is LiteralValue) {
|
||||
if (!loop.iterable.isIterable(namespace, heap))
|
||||
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||
iterableValue = loop.iterable as LiteralValue
|
||||
} else if(loop.iterable is IdentifierReference) {
|
||||
val idRef = loop.iterable as IdentifierReference
|
||||
iterableValue = ((idRef.targetStatement(namespace) as? VarDecl)?.value as? LiteralValue)
|
||||
if(iterableValue!=null && !iterableValue.isIterable(namespace, heap))
|
||||
throw CompilerException("loop over something that isn't iterable ${loop.iterable}")
|
||||
} else {
|
||||
throw CompilerException("loopvar is something strange ${loop.iterable}")
|
||||
}
|
||||
|
||||
TODO("LOOP OVER ITERABLE VALUE (array/matrix/string) $iterableValue")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
|
|||
data class Mflpt5(val b0: Short, val b1: Short, val b2: Short, val b3: Short, val b4: Short) {
|
||||
|
||||
companion object {
|
||||
const val MemorySize = 5
|
||||
|
||||
val zero = Mflpt5(0, 0,0,0,0)
|
||||
fun fromNumber(num: Number): Mflpt5 {
|
||||
// see https://en.wikipedia.org/wiki/Microsoft_Binary_Format
|
||||
|
|
|
@ -33,17 +33,17 @@ val BuiltinFunctions = mapOf(
|
|||
"sqrt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::sqrt) },
|
||||
"rad" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toRadians) },
|
||||
"deg" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT) { a, p, n, h -> oneDoubleArg(a, p, n, h, Math::toDegrees) },
|
||||
"avg" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), DataType.FLOAT, ::builtinAvg),
|
||||
"avg" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), DataType.FLOAT, ::builtinAvg),
|
||||
"abs" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), DataType.FLOAT, ::builtinAbs),
|
||||
"round" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::round) }, // type depends on arg
|
||||
"floor" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::floor) }, // type depends on arg
|
||||
"ceil" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.FLOAT))), null) { a, p, n, h -> oneDoubleArgOutputInt(a, p, n, h, Math::ceil) }, // type depends on arg
|
||||
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args
|
||||
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args
|
||||
"sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args
|
||||
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), null, ::builtinLen), // type depends on args
|
||||
"any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }},
|
||||
"all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }},
|
||||
"max" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.max()!! }}, // type depends on args
|
||||
"min" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.min()!! }}, // type depends on args
|
||||
"sum" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null) { a, p, n, h -> collectionArgOutputNumber(a, p, n, h) { it.sum() }}, // type depends on args
|
||||
"len" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), null, ::builtinLen), // type depends on args
|
||||
"any" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.any { v -> v != 0.0} }},
|
||||
"all" to FunctionSignature(true, listOf(BuiltinFunctionParam("values", listOf(DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX))), DataType.BYTE) { a, p, n, h -> collectionArgOutputBoolean(a, p, n, h) { it.all { v -> v != 0.0} }},
|
||||
"lsb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x and 255 }},
|
||||
"msb" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.WORD))), DataType.BYTE) { a, p, n, h -> oneIntArgOutputInt(a, p, n, h) { x: Int -> x ushr 8 and 255}},
|
||||
"flt" to FunctionSignature(true, listOf(BuiltinFunctionParam("value", listOf(DataType.BYTE, DataType.WORD))), DataType.FLOAT, ::builtinFlt),
|
||||
|
@ -87,7 +87,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||
|
||||
fun datatypeFromListArg(arglist: IExpression): DataType {
|
||||
if(arglist is LiteralValue) {
|
||||
if(arglist.type==DataType.ARRAY || arglist.type==DataType.ARRAY_W || arglist.type==DataType.MATRIX) {
|
||||
if(arglist.type==DataType.ARRAY || arglist.type==DataType.ARRAY_W || arglist.type==DataType.ARRAY_F || arglist.type==DataType.MATRIX) {
|
||||
val dt = arglist.arrayvalue!!.map {it.resultingDatatype(namespace, heap)}
|
||||
if(dt.any { it!=DataType.BYTE && it!=DataType.WORD && it!=DataType.FLOAT}) {
|
||||
throw FatalAstException("fuction $function only accepts array of numeric values")
|
||||
|
@ -104,6 +104,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt
|
||||
DataType.ARRAY -> DataType.BYTE
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
DataType.MATRIX -> DataType.BYTE
|
||||
null -> throw FatalAstException("function requires one argument which is an array $function")
|
||||
}
|
||||
|
@ -124,6 +125,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||
DataType.ARRAY -> DataType.BYTE
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
DataType.MATRIX -> DataType.BYTE
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +144,7 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||
DataType.BYTE, DataType.WORD -> DataType.WORD
|
||||
DataType.FLOAT -> DataType.FLOAT
|
||||
DataType.ARRAY, DataType.ARRAY_W -> DataType.WORD
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
DataType.MATRIX -> DataType.WORD
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.WORD
|
||||
}
|
||||
|
@ -306,15 +309,21 @@ private fun builtinLen(args: List<IExpression>, position: Position, namespace:IN
|
|||
?: throw SyntaxError("len over weird argument ${args[0]}", position)
|
||||
}
|
||||
return when(argument.type) {
|
||||
DataType.ARRAY, DataType.ARRAY_W -> {
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).array!!.size
|
||||
numericLiteral(arraySize, args[0].position)
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val arraySize = argument.arrayvalue?.size ?: heap.get(argument.heapId!!).doubleArray!!.size
|
||||
numericLiteral(arraySize, args[0].position)
|
||||
}
|
||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> {
|
||||
val str = argument.strvalue ?: heap.get(argument.heapId!!).str!!
|
||||
numericLiteral(str.length, args[0].position)
|
||||
}
|
||||
else -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
||||
DataType.BYTE,
|
||||
DataType.WORD,
|
||||
DataType.FLOAT -> throw SyntaxError("len of weird argument ${args[0]}", position)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@ package prog8.optimizing
|
|||
|
||||
import prog8.ast.*
|
||||
import prog8.compiler.HeapValues
|
||||
import prog8.compiler.target.c64.FLOAT_MAX_NEGATIVE
|
||||
import prog8.compiler.target.c64.FLOAT_MAX_POSITIVE
|
||||
import prog8.compiler.target.c64.Petscii
|
||||
|
||||
|
||||
|
@ -52,12 +54,41 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||
DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> {
|
||||
val litval = decl.value as? LiteralValue
|
||||
val size = decl.arrayspec!!.size()
|
||||
if (size != null) {
|
||||
if(litval!=null && litval.isArray) {
|
||||
// array initializer value is an array already, keep as-is
|
||||
if(litval.heapId!=null) {
|
||||
if (decl.datatype == DataType.MATRIX && litval.type != DataType.MATRIX) {
|
||||
val array = heap.get(litval.heapId).copy(type = DataType.MATRIX)
|
||||
heap.update(litval.heapId, array)
|
||||
}
|
||||
}
|
||||
} else if (size != null) {
|
||||
// array initializer is empty or a single int, and we know the size; create the array.
|
||||
val fillvalue = if (litval == null) 0 else litval.asIntegerValue ?: 0
|
||||
val fillArray = IntArray(size) { _ -> fillvalue }
|
||||
val heapId = heap.add(decl.datatype, fillArray)
|
||||
val valType = if(decl.datatype==DataType.MATRIX) DataType.ARRAY else decl.datatype
|
||||
decl.value = LiteralValue(valType, heapId = heapId, position = litval?.position ?: decl.position)
|
||||
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
|
||||
}
|
||||
}
|
||||
DataType.ARRAY_F -> {
|
||||
val litval = decl.value as? LiteralValue
|
||||
val size = decl.arrayspec!!.size()
|
||||
if(litval!=null && litval.isArray) {
|
||||
// array initializer value is an array already, make sure to convert to floats
|
||||
if(litval.heapId!=null) {
|
||||
val array = heap.get(litval.heapId)
|
||||
if (array.doubleArray == null) {
|
||||
val doubleArray = array.array!!.map { it.toDouble() }.toDoubleArray()
|
||||
heap.update(litval.heapId, HeapValues.HeapValue(DataType.ARRAY_F, null, null, doubleArray))
|
||||
decl.value = LiteralValue(decl.datatype, heapId = litval.heapId, position = litval.position)
|
||||
}
|
||||
}
|
||||
} else if (size != null) {
|
||||
// array initializer is empty or a single int, and we know the size; create the array.
|
||||
val fillvalue = if (litval == null) 0.0 else litval.asNumericValue?.toDouble() ?: 0.0
|
||||
val fillArray = DoubleArray(size) { _ -> fillvalue }
|
||||
val heapId = heap.add(decl.datatype, fillArray)
|
||||
decl.value = LiteralValue(decl.datatype, heapId = heapId, position = litval?.position ?: decl.position)
|
||||
}
|
||||
}
|
||||
else -> return result
|
||||
|
@ -66,21 +97,6 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||
return result
|
||||
}
|
||||
|
||||
private fun createArrayInitValue(decl: VarDecl, intvalue: Int, position: Position) {
|
||||
val size = decl.arrayspec!!.size()
|
||||
if (size != null) {
|
||||
val newArray = Array<IExpression>(size) { _ ->
|
||||
if (decl.datatype == DataType.ARRAY)
|
||||
LiteralValue(DataType.BYTE, bytevalue = intvalue.toShort(), position = position)
|
||||
else
|
||||
LiteralValue(DataType.WORD, wordvalue = intvalue, position = position)
|
||||
}
|
||||
decl.value = LiteralValue(decl.datatype, arrayvalue = newArray, position = position)
|
||||
} else {
|
||||
addError(SyntaxError("array size must be a constant integer value", position))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* replace identifiers that refer to const value, with the value itself
|
||||
*/
|
||||
|
@ -289,48 +305,54 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||
}
|
||||
} else if(literalValue.arrayvalue!=null) {
|
||||
val newArray = literalValue.arrayvalue.map { it.process(this) }.toTypedArray()
|
||||
// determine if the values are all bytes or that we need a word array instead
|
||||
var arrayDt = DataType.ARRAY
|
||||
var allElementsAreConstant = true
|
||||
for (expr in newArray) {
|
||||
allElementsAreConstant = allElementsAreConstant and (expr is LiteralValue)
|
||||
val valueDt = expr.resultingDatatype(namespace, heap)
|
||||
if(valueDt==DataType.BYTE)
|
||||
continue
|
||||
else {
|
||||
arrayDt = DataType.ARRAY_W
|
||||
break
|
||||
}
|
||||
}
|
||||
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.WORD })
|
||||
arrayDt = DataType.ARRAY_W
|
||||
if(newArray.any { it.resultingDatatype(namespace, heap) == DataType.FLOAT })
|
||||
arrayDt = DataType.ARRAY_F
|
||||
|
||||
// if the values are all constants, the array is moved to the heap
|
||||
val allElementsAreConstant = newArray.fold(true) { c, expr-> c and (expr is LiteralValue)}
|
||||
if(allElementsAreConstant) {
|
||||
val array = newArray.map {
|
||||
val litval = it as? LiteralValue
|
||||
if(litval==null) {
|
||||
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
if(litval.bytevalue==null && litval.wordvalue==null) {
|
||||
if(arrayDt==DataType.ARRAY)
|
||||
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
||||
else
|
||||
addError(ExpressionError("word array elements must all be integers 0..65535", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
val integer = litval.asIntegerValue!!
|
||||
if(arrayDt==DataType.ARRAY && integer !in 0..255) {
|
||||
val litArray = newArray.map{ it as? LiteralValue }
|
||||
if(null in litArray) {
|
||||
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
if(arrayDt==DataType.ARRAY || arrayDt==DataType.MATRIX) {
|
||||
// all values should be bytes
|
||||
val integerArray = litArray.map { (it as LiteralValue).bytevalue }
|
||||
if(integerArray.any { it==null || it.toInt() !in 0..255 }) {
|
||||
addError(ExpressionError("byte array elements must all be integers 0..255", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
} else if(arrayDt==DataType.ARRAY_W && integer !in 0..65535) {
|
||||
}
|
||||
val array = integerArray.mapNotNull { it?.toInt() }.toIntArray()
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
} else if(arrayDt==DataType.ARRAY_W) {
|
||||
// all values should be bytes or words
|
||||
val integerArray = litArray.map { (it as LiteralValue).asIntegerValue }
|
||||
if(integerArray.any {it==null || it !in 0..65535 }) {
|
||||
addError(ExpressionError("word array elements must all be integers 0..65535", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
integer
|
||||
}.toIntArray()
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
val array = integerArray.filterNotNull().toIntArray()
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(DataType.ARRAY_W, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
} else if(arrayDt==DataType.ARRAY_F) {
|
||||
// all values should be bytes, words or floats
|
||||
val doubleArray = litArray.map { (it as LiteralValue).asNumericValue?.toDouble() }
|
||||
if(doubleArray.any { it==null || it !in FLOAT_MAX_NEGATIVE..FLOAT_MAX_POSITIVE }) {
|
||||
addError(ExpressionError("float array elements must all be floats in the acceptable range", literalValue.position))
|
||||
return super.process(literalValue)
|
||||
}
|
||||
val array = doubleArray.filterNotNull().toDoubleArray()
|
||||
val heapId = heap.add(arrayDt, array)
|
||||
val newValue = LiteralValue(DataType.ARRAY_F, heapId=heapId, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
}
|
||||
} else {
|
||||
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||
}
|
||||
|
@ -338,6 +360,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||
val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position)
|
||||
return super.process(newValue)
|
||||
}
|
||||
|
||||
return super.process(literalValue)
|
||||
}
|
||||
|
||||
|
@ -349,9 +372,11 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||
if(arrayIndexedExpression.identifier!=null) {
|
||||
val x = (arrayIndexedExpression.array.x as LiteralValue).asIntegerValue!!
|
||||
val y = (arrayIndexedExpression.array.y as LiteralValue).asIntegerValue!!
|
||||
val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as VarDecl
|
||||
val index = x + y*(variable.arrayspec!!.x as LiteralValue).asIntegerValue!!
|
||||
arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position)
|
||||
val variable = arrayIndexedExpression.identifier.targetStatement(namespace) as? VarDecl
|
||||
if(variable!=null) {
|
||||
val index = x + y * (variable.arrayspec!!.x as LiteralValue).asIntegerValue!!
|
||||
arrayIndexedExpression.array = ArraySpec(LiteralValue.optimalInteger(index, arrayIndexedExpression.array.position), null, arrayIndexedExpression.array.position)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,7 +67,12 @@ class Program (val name: String,
|
|||
val intarray = numbers.map{number->number.trim().toInt()}.toIntArray()
|
||||
heap.add(it.second, intarray)
|
||||
}
|
||||
else -> throw VmExecutionException("invalid heap value type $it.second")
|
||||
DataType.ARRAY_F -> {
|
||||
val numbers = it.third.substring(1, it.third.length-1).split(',')
|
||||
val doublearray = numbers.map{number->number.trim().toDouble()}.toDoubleArray()
|
||||
heap.add(it.second, doublearray)
|
||||
}
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("invalid heap value type ${it.second}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,6 +177,7 @@ class Program (val name: String,
|
|||
}
|
||||
DataType.ARRAY,
|
||||
DataType.ARRAY_W,
|
||||
DataType.ARRAY_F,
|
||||
DataType.MATRIX -> {
|
||||
if(!valueStr.startsWith("heap:"))
|
||||
throw VmExecutionException("invalid array/matrix value, should be a heap reference")
|
||||
|
@ -281,6 +287,9 @@ class Program (val name: String,
|
|||
heap.allArrays().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.array!!.toList()}")
|
||||
}
|
||||
heap.allDoubleArrays().forEach {
|
||||
out.println("${it.index} ${it.value.type.toString().toLowerCase()} ${it.value.doubleArray!!.toList()}")
|
||||
}
|
||||
out.println("%end_heap")
|
||||
out.println("%variables")
|
||||
// just flatten all block vars into one global list for now...
|
||||
|
|
|
@ -483,6 +483,7 @@ class StackVm(private var traceOutputFile: String?) {
|
|||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> print(heap.get(value.heapId).str)
|
||||
DataType.ARRAY, DataType.ARRAY_W -> print(heap.get(value.heapId).array!!.toList())
|
||||
DataType.MATRIX -> print(heap.get(value.heapId).array!!.toList())
|
||||
DataType.ARRAY_F -> print(heap.get(value.heapId).doubleArray!!.toList())
|
||||
}
|
||||
}
|
||||
Syscall.INPUT_STR -> {
|
||||
|
@ -573,7 +574,8 @@ class StackVm(private var traceOutputFile: String?) {
|
|||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
else -> throw VmExecutionException("uniterable value $iterable")
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("uniterable value $iterable")
|
||||
}
|
||||
if(value.str!=null) {
|
||||
val result = Petscii.encodePetscii(value.str.max().toString(), true)[0]
|
||||
|
@ -590,7 +592,8 @@ class StackVm(private var traceOutputFile: String?) {
|
|||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||
DataType.ARRAY_W -> DataType.WORD
|
||||
else -> throw VmExecutionException("uniterable value $iterable")
|
||||
DataType.ARRAY_F -> DataType.FLOAT
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> throw VmExecutionException("uniterable value $iterable")
|
||||
}
|
||||
if(value.str!=null) {
|
||||
val result = Petscii.encodePetscii(value.str.min().toString(), true)[0]
|
||||
|
@ -917,11 +920,17 @@ class StackVm(private var traceOutputFile: String?) {
|
|||
} else {
|
||||
// get indexed element from the array
|
||||
val array = heap.get(variable.heapId)
|
||||
val result = array.array!![index]
|
||||
when(array.type) {
|
||||
DataType.ARRAY, DataType.MATRIX -> evalstack.push(Value(DataType.BYTE, result))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, result))
|
||||
else -> throw VmExecutionException("not a proper array/matrix var")
|
||||
DataType.ARRAY, DataType.MATRIX -> evalstack.push(Value(DataType.BYTE, array.array!![index]))
|
||||
DataType.ARRAY_W -> evalstack.push(Value(DataType.WORD, array.array!![index]))
|
||||
DataType.ARRAY_F -> evalstack.push(Value(DataType.FLOAT, array.doubleArray!![index]))
|
||||
DataType.BYTE,
|
||||
DataType.WORD,
|
||||
DataType.FLOAT,
|
||||
DataType.STR,
|
||||
DataType.STR_P,
|
||||
DataType.STR_S,
|
||||
DataType.STR_PS -> throw VmExecutionException("not a proper array/matrix var")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ class Value(val type: DataType, numericvalueOrHeapId: Number) {
|
|||
return false
|
||||
if(type==other.type) {
|
||||
return when (type) {
|
||||
DataType.STR, DataType.STR_S, DataType.STR_P, DataType.STR_PS, DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> heapId==other.heapId
|
||||
DataType.STR, DataType.STR_S, DataType.STR_P, DataType.STR_PS,
|
||||
DataType.ARRAY, DataType.ARRAY_W, DataType.ARRAY_F, DataType.MATRIX -> heapId==other.heapId
|
||||
DataType.BYTE, DataType.WORD, DataType.FLOAT -> compareTo(other)==0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,9 +86,17 @@ class TestStackVmValue {
|
|||
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR_P, 999)))
|
||||
assertFalse(sameValueAndType(Value(DataType.STR, 999), Value(DataType.STR, 222)))
|
||||
|
||||
assertTrue(sameValueAndType(Value(DataType.ARRAY, 99), Value(DataType.ARRAY, 99)))
|
||||
assertFalse(sameValueAndType(Value(DataType.ARRAY, 99), Value(DataType.MATRIX, 99)))
|
||||
assertFalse(sameValueAndType(Value(DataType.ARRAY, 99), Value(DataType.ARRAY, 22)))
|
||||
|
||||
assertTrue(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.ARRAY_W, 999)))
|
||||
assertFalse(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.MATRIX, 999)))
|
||||
assertFalse(sameValueAndType(Value(DataType.ARRAY_W, 999), Value(DataType.ARRAY_W, 222)))
|
||||
|
||||
assertTrue(sameValueAndType(Value(DataType.ARRAY_F, 999), Value(DataType.ARRAY_F, 999)))
|
||||
assertFalse(sameValueAndType(Value(DataType.ARRAY_F, 999), Value(DataType.ARRAY_W, 999)))
|
||||
assertFalse(sameValueAndType(Value(DataType.ARRAY_F, 999), Value(DataType.ARRAY_F, 222)))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -180,7 +180,8 @@ Values will usually be part of an expression or assignment statement::
|
|||
byte counter = 42 ; variable of size 8 bits, with initial value 42
|
||||
|
||||
|
||||
Array and Matrix (2-dimensional array) types are also supported like this::
|
||||
Array and Matrix (2-dimensional array) types are also supported.
|
||||
Arrays can be made of bytes, words and floats. Matrixes can oly be made of bytes::
|
||||
|
||||
byte[4] array = [1, 2, 3, 4] ; initialize the array
|
||||
byte[99] array = 255 ; initialize array with all 255's [255, 255, 255, 255, ...]
|
||||
|
@ -313,7 +314,8 @@ Loops
|
|||
-----
|
||||
|
||||
The *for*-loop is used to let a variable (or register) iterate over a range of values. Iteration is done in steps of 1, but you can change this.
|
||||
The loop variable must be declared as byte or word earlier. Floating point iteration is not supported.
|
||||
The loop variable must be declared as byte or word earlier. Floating point iteration is not supported,
|
||||
if you want to loop over a floating-point array, use a loop with an integer index variable instead.
|
||||
|
||||
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
||||
The *repeat--until* loop is used to repeat a piece of code until a certain condition is true.
|
||||
|
|
|
@ -235,6 +235,7 @@ type identifier type storage size example var declara
|
|||
stored in 5-byte cbm MFLPT format
|
||||
``byte[x]`` unsigned byte array x bytes ``byte[4] myvar = [1, 2, 3, 4]``
|
||||
``word[x]`` unsigned word array 2*x bytes ``word[4] myvar = [1, 2, 3, 4]``
|
||||
``float[x]`` floating-point array 5*x bytes ``float[4] myvar = [1.1, 2.2, 3.3, 4.4]``
|
||||
``byte[x,y]`` unsigned byte matrix x*y bytes ``byte[40,25] myvar = @todo``
|
||||
word-matrix not supported
|
||||
``str`` string (petscii) varies ``str myvar = "hello."``
|
||||
|
@ -450,9 +451,9 @@ Loops
|
|||
for loop
|
||||
^^^^^^^^
|
||||
|
||||
The loop variable must be a register or a variable defined in the local scope.
|
||||
The loop variable must be a register or a byte/word variable defined in the local scope.
|
||||
The expression that you loop over can be anything that supports iteration (such as ranges like ``0 to 100``,
|
||||
array variables and strings).
|
||||
array variables and strings) *except* floating-point arrays (because a floating-point loop variable is not supported).
|
||||
|
||||
You can use a single statement, or a statement block like in the example below::
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user