mirror of
https://github.com/irmen/prog8.git
synced 2025-03-01 00:30:03 +00:00
fix builtin functions over non-const arrays/strings
This commit is contained in:
parent
5ee427b72b
commit
34dec55eb2
@ -16,31 +16,59 @@ sub start() -> () {
|
|||||||
byte[2,3] matrix1 = [1,2, 3,4, 5,6]
|
byte[2,3] matrix1 = [1,2, 3,4, 5,6]
|
||||||
byte[2,3] matrix2 = [1,2, 3,4, 5,6]
|
byte[2,3] matrix2 = [1,2, 3,4, 5,6]
|
||||||
byte[2,3] matrix3 = [11,22, 33,44, 55,66]
|
byte[2,3] matrix3 = [11,22, 33,44, 55,66]
|
||||||
str message = "Calculating Mandelbrot Fractal..."
|
byte num1 = 99
|
||||||
_vm_gfx_text(5, 5, 7, message)
|
word num2 = 12345
|
||||||
_vm_gfx_text(5, 5, 7, "Calculating Mandelbrot Fractal...")
|
float num3 = 98.555
|
||||||
|
|
||||||
A= len("abcdef")
|
|
||||||
|
|
||||||
A= len([4,5,99/X])
|
num1 = max(msg3)
|
||||||
A= max([4,5,99])
|
_vm_write_str(num1)
|
||||||
A= min([4,5,99])
|
_vm_write_char($8d)
|
||||||
A= avg([4,5,99])
|
num1 = min(msg3)
|
||||||
A= sum([4,5,99])
|
_vm_write_str(num1)
|
||||||
A= any([4,5,99])
|
_vm_write_char($8d)
|
||||||
A= all([4,5,99])
|
|
||||||
|
|
||||||
A= len(msg3)
|
num3 = avg(array3)
|
||||||
|
_vm_write_str(num3)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num1 = all(array3)
|
||||||
|
_vm_write_str(num1)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num1 = any(array3)
|
||||||
|
_vm_write_str(num1)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
|
||||||
float xx
|
num1 = max(array3)
|
||||||
|
_vm_write_str(num1)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num1 = min(array3)
|
||||||
|
_vm_write_str(num1)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num2 = max(array5)
|
||||||
|
_vm_write_str(num2)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num2 = min(array5)
|
||||||
|
_vm_write_str(num2)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num2 = sum(array3)
|
||||||
|
_vm_write_str(num2)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num2 = sum(array5)
|
||||||
|
_vm_write_str(num2)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
|
||||||
A= len(array3)
|
num3 = avg(msg3)
|
||||||
A= max(array3)
|
_vm_write_str(num3)
|
||||||
A= min(array3)
|
_vm_write_char($8d)
|
||||||
xx= avg(array3)
|
num2 = sum(msg3)
|
||||||
A= sum(array3)
|
_vm_write_str(num2)
|
||||||
A= any(array3)
|
_vm_write_char($8d)
|
||||||
A= all(array3)
|
num1 = all(msg3)
|
||||||
|
_vm_write_str(num1)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
num1 = any(msg3)
|
||||||
|
_vm_write_str(num1)
|
||||||
|
_vm_write_char($8d)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ fun Number.toHex(): String {
|
|||||||
|
|
||||||
|
|
||||||
class HeapValues {
|
class HeapValues {
|
||||||
class HeapValue(val type: DataType, val str: String?, val array: IntArray?) {
|
data class HeapValue(val type: DataType, val str: String?, val array: IntArray?) {
|
||||||
override fun equals(other: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === other) return true
|
if (this === other) return true
|
||||||
if (javaClass != other?.javaClass) return false
|
if (javaClass != other?.javaClass) return false
|
||||||
@ -62,6 +62,31 @@ class HeapValues {
|
|||||||
return heap.size-1
|
return heap.size-1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun update(heapId: Int, str: String) {
|
||||||
|
when(heap[heapId].type){
|
||||||
|
DataType.STR,
|
||||||
|
DataType.STR_P,
|
||||||
|
DataType.STR_S,
|
||||||
|
DataType.STR_PS -> {
|
||||||
|
if(heap[heapId].str!!.length!=str.length)
|
||||||
|
throw IllegalArgumentException("heap string length mismatch")
|
||||||
|
heap[heapId] = heap[heapId].copy(str=str)
|
||||||
|
}
|
||||||
|
else-> throw IllegalArgumentException("heap data type mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 get(heapId: Int): HeapValue = heap[heapId]
|
fun get(heapId: Int): HeapValue = heap[heapId]
|
||||||
|
|
||||||
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
|
fun allStrings() = heap.asSequence().withIndex().filter { it.value.str!=null }.toList()
|
||||||
|
@ -43,6 +43,17 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
return DataType.BYTE
|
return DataType.BYTE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(arglist is IdentifierReference) {
|
||||||
|
val dt = arglist.resultingDatatype(namespace, heap)
|
||||||
|
return when(dt) {
|
||||||
|
DataType.BYTE, DataType.WORD, DataType.FLOAT,
|
||||||
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> dt
|
||||||
|
DataType.ARRAY -> DataType.BYTE
|
||||||
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
|
DataType.MATRIX -> DataType.BYTE
|
||||||
|
null -> throw FatalAstException("function requires one argument which is an array $function")
|
||||||
|
}
|
||||||
|
}
|
||||||
throw FatalAstException("function requires one argument which is an array $function")
|
throw FatalAstException("function requires one argument which is an array $function")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +64,16 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
"rndw" -> DataType.WORD
|
"rndw" -> DataType.WORD
|
||||||
"rol", "rol2", "ror", "ror2", "lsl", "lsr", "set_carry", "clear_carry", "set_irqd", "clear_irqd" -> null // no return value so no datatype
|
"rol", "rol2", "ror", "ror2", "lsl", "lsr", "set_carry", "clear_carry", "set_irqd", "clear_irqd" -> null // no return value so no datatype
|
||||||
"abs" -> args.single().resultingDatatype(namespace, heap)
|
"abs" -> args.single().resultingDatatype(namespace, heap)
|
||||||
"max", "min" -> datatypeFromListArg(args.single())
|
"max", "min" -> {
|
||||||
|
val dt = datatypeFromListArg(args.single())
|
||||||
|
when(dt) {
|
||||||
|
DataType.BYTE, DataType.WORD, DataType.FLOAT -> dt
|
||||||
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
|
DataType.ARRAY -> DataType.BYTE
|
||||||
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
|
DataType.MATRIX -> DataType.BYTE
|
||||||
|
}
|
||||||
|
}
|
||||||
"round", "floor", "ceil" -> integerDatatypeFromArg(args.single())
|
"round", "floor", "ceil" -> integerDatatypeFromArg(args.single())
|
||||||
"sum" -> {
|
"sum" -> {
|
||||||
val dt=datatypeFromListArg(args.single())
|
val dt=datatypeFromListArg(args.single())
|
||||||
@ -61,8 +81,8 @@ fun builtinFunctionReturnType(function: String, args: List<IExpression>, namespa
|
|||||||
DataType.BYTE, DataType.WORD -> DataType.WORD
|
DataType.BYTE, DataType.WORD -> DataType.WORD
|
||||||
DataType.FLOAT -> DataType.FLOAT
|
DataType.FLOAT -> DataType.FLOAT
|
||||||
DataType.ARRAY, DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY, DataType.ARRAY_W -> DataType.WORD
|
||||||
DataType.MATRIX -> DataType.BYTE
|
DataType.MATRIX -> DataType.WORD
|
||||||
else -> throw FatalAstException("cannot sum over type $dt")
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.WORD
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"len" -> {
|
"len" -> {
|
||||||
@ -135,13 +155,7 @@ private fun collectionArgOutputNumber(args: List<IExpression>, position: Positio
|
|||||||
function: (arg: Collection<Double>)->Number): LiteralValue {
|
function: (arg: Collection<Double>)->Number): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
||||||
var iterable = args[0].constValue(namespace, heap)
|
var iterable = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
|
||||||
if(iterable==null) {
|
|
||||||
if(args[0] !is IdentifierReference)
|
|
||||||
throw SyntaxError("function over weird argument ${args[0]}", position)
|
|
||||||
iterable = ((args[0] as IdentifierReference).targetStatement(namespace) as? VarDecl)?.value?.constValue(namespace, heap)
|
|
||||||
?: throw SyntaxError("function over weird argument ${args[0]}", position)
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = if(iterable.arrayvalue != null) {
|
val result = if(iterable.arrayvalue != null) {
|
||||||
val constants = iterable.arrayvalue!!.map { it.constValue(namespace, heap)?.asNumericValue }
|
val constants = iterable.arrayvalue!!.map { it.constValue(namespace, heap)?.asNumericValue }
|
||||||
@ -160,13 +174,7 @@ private fun collectionArgOutputBoolean(args: List<IExpression>, position: Positi
|
|||||||
function: (arg: Collection<Double>)->Boolean): LiteralValue {
|
function: (arg: Collection<Double>)->Boolean): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
throw SyntaxError("builtin function requires one non-scalar argument", position)
|
||||||
var iterable = args[0].constValue(namespace, heap)
|
var iterable = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
|
||||||
if(iterable==null) {
|
|
||||||
if(args[0] !is IdentifierReference)
|
|
||||||
throw SyntaxError("function over weird argument ${args[0]}", position)
|
|
||||||
iterable = ((args[0] as IdentifierReference).targetStatement(namespace) as? VarDecl)?.value?.constValue(namespace, heap)
|
|
||||||
?: throw SyntaxError("function over weird argument ${args[0]}", position)
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = if(iterable.arrayvalue != null) {
|
val result = if(iterable.arrayvalue != null) {
|
||||||
val constants = iterable.arrayvalue!!.map { it.constValue(namespace, heap)?.asNumericValue }
|
val constants = iterable.arrayvalue!!.map { it.constValue(namespace, heap)?.asNumericValue }
|
||||||
@ -268,13 +276,7 @@ fun builtinSum(args: List<IExpression>, position: Position, namespace:INameScope
|
|||||||
fun builtinAvg(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue {
|
fun builtinAvg(args: List<IExpression>, position: Position, namespace:INameScope, heap: HeapValues): LiteralValue {
|
||||||
if(args.size!=1)
|
if(args.size!=1)
|
||||||
throw SyntaxError("avg requires array/matrix argument", position)
|
throw SyntaxError("avg requires array/matrix argument", position)
|
||||||
var iterable = args[0].constValue(namespace, heap)
|
var iterable = args[0].constValue(namespace, heap) ?: throw NotConstArgumentException()
|
||||||
if(iterable==null) {
|
|
||||||
if(args[0] !is IdentifierReference)
|
|
||||||
throw SyntaxError("avg over weird argument ${args[0]}", position)
|
|
||||||
iterable = ((args[0] as IdentifierReference).targetStatement(namespace) as? VarDecl)?.value?.constValue(namespace, heap)
|
|
||||||
?: throw SyntaxError("avg over weird argument ${args[0]}", position)
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = if(iterable.arrayvalue!=null) {
|
val result = if(iterable.arrayvalue!=null) {
|
||||||
val constants = iterable.arrayvalue!!.map { it.constValue(namespace, heap)?.asNumericValue }
|
val constants = iterable.arrayvalue!!.map { it.constValue(namespace, heap)?.asNumericValue }
|
||||||
|
@ -317,7 +317,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
val array = newArray.map {
|
val array = newArray.map {
|
||||||
val litval = it as? LiteralValue
|
val litval = it as? LiteralValue
|
||||||
if(litval==null) {
|
if(litval==null) {
|
||||||
addError(ExpressionError("array/matrix can contain only constant values", literalValue.position))
|
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||||
return super.process(literalValue)
|
return super.process(literalValue)
|
||||||
}
|
}
|
||||||
if(litval.bytevalue==null && litval.wordvalue==null) {
|
if(litval.bytevalue==null && litval.wordvalue==null) {
|
||||||
@ -341,7 +341,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV
|
|||||||
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position)
|
||||||
return super.process(newValue)
|
return super.process(newValue)
|
||||||
} else {
|
} else {
|
||||||
addError(ExpressionError("array/matrix can contain only constant values", literalValue.position))
|
addError(ExpressionError("array/matrix literal can contain only constant values", literalValue.position))
|
||||||
}
|
}
|
||||||
|
|
||||||
val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position)
|
val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position)
|
||||||
|
@ -483,9 +483,11 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Syscall.INPUT_STR -> {
|
Syscall.INPUT_STR -> {
|
||||||
val maxlen = evalstack.pop().integerValue()
|
val variable = evalstack.pop()
|
||||||
val input = readLine()?.substring(0, maxlen) ?: ""
|
val value = heap.get(variable.heapId)
|
||||||
TODO("input_str opcode should put the string in a given heap location (overwriting old string)")
|
val maxlen = value.str!!.length
|
||||||
|
val input = readLine() ?: ""
|
||||||
|
heap.update(variable.heapId, input.padEnd(maxlen, '\u0000').substring(0, maxlen))
|
||||||
}
|
}
|
||||||
Syscall.GFX_PIXEL -> {
|
Syscall.GFX_PIXEL -> {
|
||||||
// plot pixel at (x, y, color) from stack
|
// plot pixel at (x, y, color) from stack
|
||||||
@ -556,45 +558,69 @@ class StackVm(private var traceOutputFile: String?) {
|
|||||||
}
|
}
|
||||||
Syscall.FUNC_MAX -> {
|
Syscall.FUNC_MAX -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
val dt =
|
val value = heap.get(iterable.heapId)
|
||||||
when(iterable.type) {
|
val resultDt = when(iterable.type) {
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
else -> throw VmExecutionException("uniterable value $iterable")
|
else -> throw VmExecutionException("uniterable value $iterable")
|
||||||
}
|
}
|
||||||
TODO("func_max on array/matrix/string")
|
if(value.str!=null) {
|
||||||
|
val result = Petscii.encodePetscii(value.str.max().toString(), true)[0]
|
||||||
|
evalstack.push(Value(DataType.BYTE, result))
|
||||||
|
} else {
|
||||||
|
val result = value.array!!.max() ?: 0
|
||||||
|
evalstack.push(Value(resultDt, result))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Syscall.FUNC_MIN -> {
|
Syscall.FUNC_MIN -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
val dt =
|
val value = heap.get(iterable.heapId)
|
||||||
when(iterable.type) {
|
val resultDt = when(iterable.type) {
|
||||||
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS,
|
DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> DataType.BYTE
|
||||||
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
DataType.ARRAY, DataType.MATRIX -> DataType.BYTE
|
||||||
DataType.ARRAY_W -> DataType.WORD
|
DataType.ARRAY_W -> DataType.WORD
|
||||||
else -> throw VmExecutionException("uniterable value $iterable")
|
else -> throw VmExecutionException("uniterable value $iterable")
|
||||||
}
|
}
|
||||||
TODO("func_min on array/matrix/string")
|
if(value.str!=null) {
|
||||||
|
val result = Petscii.encodePetscii(value.str.min().toString(), true)[0]
|
||||||
|
evalstack.push(Value(DataType.BYTE, result))
|
||||||
|
} else {
|
||||||
|
val result = value.array!!.min() ?: 0
|
||||||
|
evalstack.push(Value(resultDt, result))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Syscall.FUNC_AVG -> {
|
Syscall.FUNC_AVG -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
TODO("func_avg")
|
val value = heap.get(iterable.heapId)
|
||||||
// evalstack.push(Value(DataType.FLOAT, array.arrayvalue!!.average()))
|
if(value.str!=null)
|
||||||
|
evalstack.push(Value(DataType.FLOAT, Petscii.encodePetscii(value.str, true).average()))
|
||||||
|
else
|
||||||
|
evalstack.push(Value(DataType.FLOAT, value.array!!.average()))
|
||||||
}
|
}
|
||||||
Syscall.FUNC_SUM -> {
|
Syscall.FUNC_SUM -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
TODO("func_sum")
|
val value = heap.get(iterable.heapId)
|
||||||
// evalstack.push(Value(DataType.WORD, array.arrayvalue!!.sum()))
|
if(value.str!=null)
|
||||||
|
evalstack.push(Value(DataType.WORD, Petscii.encodePetscii(value.str, true).sum()))
|
||||||
|
else
|
||||||
|
evalstack.push(Value(DataType.WORD, value.array!!.sum()))
|
||||||
}
|
}
|
||||||
Syscall.FUNC_ANY -> {
|
Syscall.FUNC_ANY -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
TODO("func_any")
|
val value = heap.get(iterable.heapId)
|
||||||
// evalstack.push(Value(DataType.BYTE, if(array.arrayvalue!!.any{ v -> v != 0}) 1 else 0))
|
if (value.str != null)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if (Petscii.encodePetscii(value.str, true).any { c -> c != 0.toShort() }) 1 else 0))
|
||||||
|
else
|
||||||
|
evalstack.push(Value(DataType.BYTE, if (value.array!!.any{v->v!=0}) 1 else 0))
|
||||||
}
|
}
|
||||||
Syscall.FUNC_ALL -> {
|
Syscall.FUNC_ALL -> {
|
||||||
val iterable = evalstack.pop()
|
val iterable = evalstack.pop()
|
||||||
TODO("func_all")
|
val value = heap.get(iterable.heapId)
|
||||||
// evalstack.push(Value(DataType.BYTE, if(array.arrayvalue!!.all{ v -> v != 0}) 1 else 0))
|
if (value.str != null)
|
||||||
|
evalstack.push(Value(DataType.BYTE, if (Petscii.encodePetscii(value.str, true).all { c -> c != 0.toShort() }) 1 else 0))
|
||||||
|
else
|
||||||
|
evalstack.push(Value(DataType.BYTE, if (value.array!!.all{v->v!=0}) 1 else 0))
|
||||||
}
|
}
|
||||||
else -> throw VmExecutionException("unimplemented syscall $syscall")
|
else -> throw VmExecutionException("unimplemented syscall $syscall")
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user