syntaxcheck for loop

This commit is contained in:
Irmen de Jong 2018-09-16 16:37:28 +02:00
parent 004776d0d8
commit 719a446d19
5 changed files with 68 additions and 12 deletions

View File

@ -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)

View File

@ -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<String>, 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)"
}
}

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -637,7 +637,7 @@ class Program (prog: MutableList<Instruction>,
"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