mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
syntaxcheck for loop
This commit is contained in:
parent
004776d0d8
commit
719a446d19
@ -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)
|
||||
|
@ -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)"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user