diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 7301e0c2e..4860f389e 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -1070,7 +1070,7 @@ data class IdentifierReference(val nameInSource: List, override val posi ?: throw UndefinedSymbolError(this) val vardecl = node as? VarDecl if(vardecl==null) { - throw ExpressionError("name should be a constant, instead of: ${node::class.simpleName}", position) + throw ExpressionError("name must be a constant, instead of: ${node::class.simpleName}", position) } else if(vardecl.type!=VarDeclType.CONST) { return null } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 70a462fc0..223c0e8f2 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -184,14 +184,14 @@ class AstChecker(private val namespace: INameScope, val uniqueNames = subroutine.parameters.asSequence().map { it.name }.toSet() if(uniqueNames.size!=subroutine.parameters.size) - err("parameter names should be unique") + err("parameter names must be unique") val uniqueParamRegs = subroutine.parameters.asSequence().map {it.register}.toSet() if(uniqueParamRegs.size!=subroutine.parameters.size) - err("parameter registers should be unique") + err("parameter registers must be unique") val uniqueResultRegisters = subroutine.returnvalues.asSequence().filter{it.register!=null}.map {it.register.toString()}.toMutableSet() uniqueResultRegisters.addAll(subroutine.returnvalues.asSequence().filter{it.statusflag!=null}.map{it.statusflag.toString()}.toList()) if(uniqueResultRegisters.size!=subroutine.returnvalues.size) - err("return registers should be unique") + err("return registers must be unique") super.process(subroutine) checkSubroutinesPrecededByReturnOrJumpAndFollowedByLabelOrSub(subroutine.statements) @@ -227,7 +227,7 @@ class AstChecker(private val namespace: INameScope, for (stmt in statements) { if(checkNext) { if(stmt !is Label && stmt !is Subroutine) - checkResult.add(SyntaxError("preceding subroutine definition at line ${preceding.position.line} should be followed here by a label, another subroutine statement, or nothing", stmt.position)) + checkResult.add(SyntaxError("preceding subroutine definition at line ${preceding.position.line} must be followed here by a label, another subroutine statement, or nothing", stmt.position)) return } if(stmt is Subroutine) { @@ -236,7 +236,7 @@ class AstChecker(private val namespace: INameScope, && preceding !is Subroutine && preceding !is VarDecl && preceding !is BuiltinFunctionStatementPlaceholder) { - checkResult.add(SyntaxError("subroutine definition should be preceded by a return, jump, vardecl, or another subroutine statement", stmt.position)) + checkResult.add(SyntaxError("subroutine definition must be preceded by a return, jump, vardecl, or another subroutine statement", stmt.position)) } checkNext=true } @@ -437,7 +437,20 @@ class AstChecker(private val namespace: INameScope, checkResult.add(SyntaxError("floating point value used, but floating point is not enabled via options", literalValue.position)) } checkValueTypeAndRange(literalValue.type, null, literalValue, heap) - return super.process(literalValue) + + val lv = super.process(literalValue) + when(lv.type) { + DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { + if(lv.heapId==null) + throw FatalAstException("string should have been moved to heap at ${lv.position}") + } + DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> { + if(lv.heapId==null) + throw FatalAstException("array/matrix should have been moved to heap at ${lv.position}") + } + else -> {} + } + return lv } override fun process(expr: BinaryExpression): IExpression { @@ -639,14 +652,14 @@ class AstChecker(private val namespace: INameScope, DataType.ARRAY -> { // value may be either a single byte, or a byte array (of all constant values) if(value.type==DataType.ARRAY) { - val array = heap.get(value.heapId!!).array!! + val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.size if(arrayspec!=null) { 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 (array.size != expectedSize) - return err("initializer array size mismatch (expecting $expectedSize, got ${array.size})") + if (arraySize != expectedSize) + return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") } } else if(value.type==DataType.ARRAY_W) { return err("initialization value must be an array of bytes") @@ -662,15 +675,15 @@ class AstChecker(private val namespace: INameScope, DataType.ARRAY_W -> { // value may be either a single word, or a word array if(value.type==DataType.ARRAY || value.type==DataType.ARRAY_W) { - val array = heap.get(value.heapId!!).array!! + val arraySize = value.arrayvalue?.size ?: heap.get(value.heapId!!).array!!.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 (array.size != expectedSize) - return err("initializer array size mismatch (expecting $expectedSize, got ${array.size})") + if (arraySize != expectedSize) + return err("initializer array size mismatch (expecting $expectedSize, got $arraySize)") } } else { val number = value.asIntegerValue ?: return if (value.floatvalue!=null) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 416212539..d7f850c59 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -415,8 +415,16 @@ private class StatementTranslator(private val stackvmProg: StackVmProgram, DataType.BYTE -> stackvmProg.instr(Opcode.PUSH, Value(DataType.BYTE, lv.bytevalue!!)) DataType.WORD -> stackvmProg.instr(Opcode.PUSH, Value(DataType.WORD, lv.wordvalue!!)) DataType.FLOAT -> stackvmProg.instr(Opcode.PUSH, Value(DataType.FLOAT, lv.floatvalue!!)) - DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS, - DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> stackvmProg.instr(Opcode.PUSH, Value(lv.type, lv.heapId!!)) + DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { + if(lv.heapId==null) + 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 -> { + 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)) + } } } } diff --git a/compiler/src/prog8/optimizing/ConstantFolding.kt b/compiler/src/prog8/optimizing/ConstantFolding.kt index 9a109e70c..4dac81d73 100644 --- a/compiler/src/prog8/optimizing/ConstantFolding.kt +++ b/compiler/src/prog8/optimizing/ConstantFolding.kt @@ -59,7 +59,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV val newArray = Array(size) { _ -> LiteralValue(DataType.BYTE, bytevalue = intvalue.toShort(), position = it.position) } decl.value = LiteralValue(DataType.ARRAY, arrayvalue = newArray, position = it.position) } else { - addError(SyntaxError("matrix size spec should be constant integer values", it.position)) + addError(SyntaxError("matrix size spec must be constant integer values", it.position)) } } } @@ -79,7 +79,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV } decl.value = LiteralValue(decl.datatype, arrayvalue = newArray, position=it.position) } else { - addError(SyntaxError("array size should be a constant integer value", it.position)) + addError(SyntaxError("array size must be a constant integer value", it.position)) } } } @@ -317,7 +317,7 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV val array = newArray.map { val litval = it as? LiteralValue if(litval==null) { - addError(ExpressionError("array elements must all be constants", literalValue.position)) + addError(ExpressionError("array/matrix can contain only constant values", literalValue.position)) return super.process(literalValue) } if(litval.bytevalue==null && litval.wordvalue==null) { @@ -340,6 +340,8 @@ class ConstantFolding(private val namespace: INameScope, private val heap: HeapV val heapId = heap.add(arrayDt, array) val newValue = LiteralValue(arrayDt, heapId=heapId, position = literalValue.position) return super.process(newValue) + } else { + addError(ExpressionError("array/matrix can contain only constant values", literalValue.position)) } val newValue = LiteralValue(arrayDt, arrayvalue = newArray, position = literalValue.position) diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 4054e0ce1..06afbab32 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -477,15 +477,9 @@ class StackVm(private var traceOutputFile: String?) { val value = evalstack.pop() when(value.type){ DataType.BYTE, DataType.WORD, DataType.FLOAT -> print(value.numericValue()) - DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> { - TODO("print stringvalue") - } - DataType.ARRAY, DataType.ARRAY_W -> { - TODO("print array value") - } - DataType.MATRIX -> { - TODO("print matrix value") - } + 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()) } } Syscall.INPUT_STR -> { @@ -513,17 +507,7 @@ class StackVm(private var traceOutputFile: String?) { Syscall.FUNC_RND -> evalstack.push(Value(DataType.BYTE, rnd.nextInt() and 255)) Syscall.FUNC_RNDW -> evalstack.push(Value(DataType.WORD, rnd.nextInt() and 65535)) Syscall.FUNC_RNDF -> evalstack.push(Value(DataType.FLOAT, rnd.nextDouble())) - Syscall.FUNC_LEN -> { - val value = evalstack.pop() - TODO("func_len") -// when(value.type) { -// DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> -// evalstack.push(Value(DataType.WORD, value.stringvalue!!.length)) -// DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> -// evalstack.push(Value(DataType.WORD, value.arrayvalue!!.size)) -// else -> throw VmExecutionException("cannot get length of $value") -// } - } + Syscall.FUNC_LEN -> throw VmExecutionException("len() should have been const-folded away everywhere (it's not possible on non-const values)") Syscall.FUNC_SIN -> evalstack.push(Value(DataType.FLOAT, sin(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_COS -> evalstack.push(Value(DataType.FLOAT, cos(evalstack.pop().numericValue().toDouble()))) Syscall.FUNC_ROUND -> evalstack.push(Value(DataType.WORD, evalstack.pop().numericValue().toDouble().roundToInt()))