From 719a446d197100fd907382d843f9680fa0403494 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Sun, 16 Sep 2018 16:37:28 +0200 Subject: [PATCH] syntaxcheck for loop --- compiler/examples/test.p8 | 10 ------ compiler/src/prog8/ast/AST.kt | 25 +++++++++++++++ compiler/src/prog8/ast/AstChecker.kt | 41 +++++++++++++++++++++++++ compiler/src/prog8/compiler/Compiler.kt | 2 +- compiler/src/prog8/stackvm/StackVm.kt | 2 +- 5 files changed, 68 insertions(+), 12 deletions(-) diff --git a/compiler/examples/test.p8 b/compiler/examples/test.p8 index aba07244a..d10d436d7 100644 --- a/compiler/examples/test.p8 +++ b/compiler/examples/test.p8 @@ -42,20 +42,10 @@ sub start() -> () { for X in 3 to 100 step 3/3 { A=44 continue - continue - continue - break - break break A=99 } - for X in AX { - A=44 - break - continue - } - loop: tx = round(sin(time*1.01)*150 + 160) ty = round((cos(time)+sin(time/44.1))*60 + 128) diff --git a/compiler/src/prog8/ast/AST.kt b/compiler/src/prog8/ast/AST.kt index 31339ef7e..d1a6489c3 100644 --- a/compiler/src/prog8/ast/AST.kt +++ b/compiler/src/prog8/ast/AST.kt @@ -663,6 +663,7 @@ data class AssignTarget(val register: Register?, val identifier: IdentifierRefer interface IExpression: Node { + val isIterable: Boolean fun constValue(namespace: INameScope): LiteralValue? fun process(processor: IAstProcessor): IExpression fun referencesIdentifier(name: String): Boolean @@ -684,6 +685,7 @@ class PrefixExpression(val operator: String, var expression: IExpression, overri override fun process(processor: IAstProcessor) = processor.process(this) override fun referencesIdentifier(name: String) = expression.referencesIdentifier(name) override fun resultingDatatype(namespace: INameScope): DataType? = expression.resultingDatatype(namespace) + override val isIterable = false } @@ -716,6 +718,7 @@ class BinaryExpression(var left: IExpression, val operator: String, var right: I else -> throw FatalAstException("resulting datatype check for invalid operator $operator") } } + override val isIterable = false private fun arithmeticOpDt(leftDt: DataType, rightDt: DataType): DataType { return when(leftDt) { @@ -827,6 +830,11 @@ class LiteralValue(val type: DataType, } override fun resultingDatatype(namespace: INameScope) = type + override val isIterable = when(type) { + DataType.BYTE, DataType.WORD, DataType.FLOAT -> false + DataType.STR, DataType.STR_P, DataType.STR_S, DataType.STR_PS -> true + DataType.ARRAY, DataType.ARRAY_W, DataType.MATRIX -> true + } } @@ -860,6 +868,8 @@ class RangeExpr(var from: IExpression, } } + override val isIterable = true + override fun toString(): String { return "RangeExpr(from $from, to $to, step $step, pos=$position)" } @@ -913,6 +923,7 @@ class RegisterExpr(val register: Register, override val position: Position) : IE override fun constValue(namespace: INameScope): LiteralValue? = null override fun process(processor: IAstProcessor) = this override fun referencesIdentifier(name: String): Boolean = false + override val isIterable = false override fun toString(): String { return "RegisterExpr(register=$register, pos=$position)" @@ -967,6 +978,11 @@ data class IdentifierReference(val nameInSource: List, override val posi throw FatalAstException("cannot get datatype from identifier reference ${this}, pos=$position") } } + + override val isIterable: Boolean + get() { + TODO("iterable identifierref?") + } } @@ -1102,6 +1118,11 @@ class FunctionCall(override var target: IdentifierReference, } TODO("datatype of functioncall to $stmt") } + + override val isIterable: Boolean + get() { + TODO("iterable function call result?") + } } @@ -1605,6 +1626,10 @@ class ForLoop(val loopRegister: Register?, } override fun process(processor: IAstProcessor) = processor.process(this) + + override fun toString(): String { + return "ForLoop(loopVar: $loopVar, loopReg: $loopRegister, iterable: $iterable, pos=$position)" + } } diff --git a/compiler/src/prog8/ast/AstChecker.kt b/compiler/src/prog8/ast/AstChecker.kt index 1914fd91c..21644281c 100644 --- a/compiler/src/prog8/ast/AstChecker.kt +++ b/compiler/src/prog8/ast/AstChecker.kt @@ -68,6 +68,47 @@ class AstChecker(private val namespace: INameScope, private val compilerOptions: } } + override fun process(forLoop: ForLoop): IStatement { + if(!forLoop.iterable.isIterable) { + checkResult.add(ExpressionError("can only loop over an iterable type", forLoop.position)) + } else { + val iterableDt = forLoop.iterable.resultingDatatype(namespace) + if (forLoop.loopRegister != null) { + // loop register + when (forLoop.loopRegister) { + Register.A, Register.X, Register.Y -> { + if (iterableDt != DataType.BYTE) + checkResult.add(ExpressionError("register can only loop over bytes", forLoop.position)) + } + Register.AX, Register.AY, Register.XY -> { + if (iterableDt != DataType.BYTE) + checkResult.add(ExpressionError("register pair can only loop over words", forLoop.position)) + } + } + } else { + // loop variable + val loopvar = forLoop.loopVar!!.targetStatement(namespace) as? VarDecl + if(loopvar==null || loopvar.type==VarDeclType.CONST) { + checkResult.add(SyntaxError("for loop requires a variable to loop with", forLoop.position)) + + } else { + when (loopvar.datatype) { + DataType.BYTE -> { + if(iterableDt!=DataType.BYTE) + checkResult.add(ExpressionError("can only loop over bytes", forLoop.position)) + } + DataType.WORD -> { + if(iterableDt!=DataType.BYTE && iterableDt!=DataType.WORD) + checkResult.add(ExpressionError("can only loop over bytes or words", forLoop.position)) + } + else -> checkResult.add(ExpressionError("loop variable must be byte or word type", forLoop.position)) + } + } + } + } + return super.process(forLoop) + } + override fun process(jump: Jump): IStatement { if(jump.identifier!=null) { val targetStatement = checkFunctionOrLabelExists(jump.identifier, jump) diff --git a/compiler/src/prog8/compiler/Compiler.kt b/compiler/src/prog8/compiler/Compiler.kt index 4b6f7cbea..c228adc8b 100644 --- a/compiler/src/prog8/compiler/Compiler.kt +++ b/compiler/src/prog8/compiler/Compiler.kt @@ -478,7 +478,7 @@ class Compiler(private val options: CompilationOptions) { private fun translate(loop: ForLoop) { stackvmProg.line(loop.position) - println("@TODO: translate FOR LOOP") // @todo FOR LOOP + println("@TODO: translate FOR LOOP $loop") // @todo FOR LOOP } } } diff --git a/compiler/src/prog8/stackvm/StackVm.kt b/compiler/src/prog8/stackvm/StackVm.kt index 3ddb0835e..e5627a699 100644 --- a/compiler/src/prog8/stackvm/StackVm.kt +++ b/compiler/src/prog8/stackvm/StackVm.kt @@ -637,7 +637,7 @@ class Program (prog: MutableList, "byte" -> Value(DataType.BYTE, valueStr.toShort(16)) "word" -> Value(DataType.WORD, valueStr.toInt(16)) "float" -> Value(DataType.FLOAT, valueStr.toDouble()) - "str" -> { + "str", "str_p", "str_s", "str_ps" -> { if(valueStr.startsWith('"') && valueStr.endsWith('"')) Value(DataType.STR, null, unescape(valueStr.substring(1, valueStr.length-1))) else