mirror of
https://github.com/irmen/prog8.git
synced 2024-09-08 10:55:08 +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 {
|
for X in 3 to 100 step 3/3 {
|
||||||
A=44
|
A=44
|
||||||
continue
|
continue
|
||||||
continue
|
|
||||||
continue
|
|
||||||
break
|
|
||||||
break
|
|
||||||
break
|
break
|
||||||
A=99
|
A=99
|
||||||
}
|
}
|
||||||
|
|
||||||
for X in AX {
|
|
||||||
A=44
|
|
||||||
break
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
tx = round(sin(time*1.01)*150 + 160)
|
tx = round(sin(time*1.01)*150 + 160)
|
||||||
ty = round((cos(time)+sin(time/44.1))*60 + 128)
|
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 {
|
interface IExpression: Node {
|
||||||
|
val isIterable: Boolean
|
||||||
fun constValue(namespace: INameScope): LiteralValue?
|
fun constValue(namespace: INameScope): LiteralValue?
|
||||||
fun process(processor: IAstProcessor): IExpression
|
fun process(processor: IAstProcessor): IExpression
|
||||||
fun referencesIdentifier(name: String): Boolean
|
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 process(processor: IAstProcessor) = processor.process(this)
|
||||||
override fun referencesIdentifier(name: String) = expression.referencesIdentifier(name)
|
override fun referencesIdentifier(name: String) = expression.referencesIdentifier(name)
|
||||||
override fun resultingDatatype(namespace: INameScope): DataType? = expression.resultingDatatype(namespace)
|
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")
|
else -> throw FatalAstException("resulting datatype check for invalid operator $operator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
override val isIterable = false
|
||||||
|
|
||||||
private fun arithmeticOpDt(leftDt: DataType, rightDt: DataType): DataType {
|
private fun arithmeticOpDt(leftDt: DataType, rightDt: DataType): DataType {
|
||||||
return when(leftDt) {
|
return when(leftDt) {
|
||||||
@ -827,6 +830,11 @@ class LiteralValue(val type: DataType,
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun resultingDatatype(namespace: INameScope) = type
|
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 {
|
override fun toString(): String {
|
||||||
return "RangeExpr(from $from, to $to, step $step, pos=$position)"
|
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 constValue(namespace: INameScope): LiteralValue? = null
|
||||||
override fun process(processor: IAstProcessor) = this
|
override fun process(processor: IAstProcessor) = this
|
||||||
override fun referencesIdentifier(name: String): Boolean = false
|
override fun referencesIdentifier(name: String): Boolean = false
|
||||||
|
override val isIterable = false
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "RegisterExpr(register=$register, pos=$position)"
|
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")
|
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")
|
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 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 {
|
override fun process(jump: Jump): IStatement {
|
||||||
if(jump.identifier!=null) {
|
if(jump.identifier!=null) {
|
||||||
val targetStatement = checkFunctionOrLabelExists(jump.identifier, jump)
|
val targetStatement = checkFunctionOrLabelExists(jump.identifier, jump)
|
||||||
|
@ -478,7 +478,7 @@ class Compiler(private val options: CompilationOptions) {
|
|||||||
|
|
||||||
private fun translate(loop: ForLoop) {
|
private fun translate(loop: ForLoop) {
|
||||||
stackvmProg.line(loop.position)
|
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))
|
"byte" -> Value(DataType.BYTE, valueStr.toShort(16))
|
||||||
"word" -> Value(DataType.WORD, valueStr.toInt(16))
|
"word" -> Value(DataType.WORD, valueStr.toInt(16))
|
||||||
"float" -> Value(DataType.FLOAT, valueStr.toDouble())
|
"float" -> Value(DataType.FLOAT, valueStr.toDouble())
|
||||||
"str" -> {
|
"str", "str_p", "str_s", "str_ps" -> {
|
||||||
if(valueStr.startsWith('"') && valueStr.endsWith('"'))
|
if(valueStr.startsWith('"') && valueStr.endsWith('"'))
|
||||||
Value(DataType.STR, null, unescape(valueStr.substring(1, valueStr.length-1)))
|
Value(DataType.STR, null, unescape(valueStr.substring(1, valueStr.length-1)))
|
||||||
else
|
else
|
||||||
|
Loading…
Reference in New Issue
Block a user