mirror of
https://github.com/irmen/prog8.git
synced 2024-11-26 11:49:22 +00:00
introduced repeat loop. repeat-until changed to do-util.
forever loop is gone (use repeat without iteration count). struct literal is now same as array literal [...] to avoid parsing ambiguity with scope blocks.
This commit is contained in:
parent
b0e8738ab8
commit
c38508c262
@ -324,16 +324,18 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
|||||||
whileLoop.body.accept(this)
|
whileLoop.body.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(foreverLoop: ForeverLoop) {
|
|
||||||
output("forever ")
|
|
||||||
foreverLoop.body.accept(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visit(repeatLoop: RepeatLoop) {
|
override fun visit(repeatLoop: RepeatLoop) {
|
||||||
output("repeat ")
|
output("repeat ")
|
||||||
|
repeatLoop.iterations?.accept(this)
|
||||||
|
output(" ")
|
||||||
repeatLoop.body.accept(this)
|
repeatLoop.body.accept(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visit(untilLoop: UntilLoop) {
|
||||||
|
output("do ")
|
||||||
|
untilLoop.body.accept(this)
|
||||||
output(" until ")
|
output(" until ")
|
||||||
repeatLoop.untilCondition.accept(this)
|
untilLoop.untilCondition.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(returnStmt: Return) {
|
override fun visit(returnStmt: Return) {
|
||||||
@ -425,10 +427,6 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
|||||||
outputln("")
|
outputln("")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(structLv: StructLiteralValue) {
|
|
||||||
outputListMembers(structLv.values.asSequence(), '{', '}')
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visit(nopStatement: NopStatement) {
|
override fun visit(nopStatement: NopStatement) {
|
||||||
output("; NOP @ ${nopStatement.position} $nopStatement")
|
output("; NOP @ ${nopStatement.position} $nopStatement")
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ interface INameScope {
|
|||||||
when(stmt) {
|
when(stmt) {
|
||||||
// NOTE: if other nodes are introduced that are a scope, or contain subscopes, they must be added here!
|
// NOTE: if other nodes are introduced that are a scope, or contain subscopes, they must be added here!
|
||||||
is ForLoop -> if(stmt.body.name==name) return stmt.body
|
is ForLoop -> if(stmt.body.name==name) return stmt.body
|
||||||
is RepeatLoop -> if(stmt.body.name==name) return stmt.body
|
is UntilLoop -> if(stmt.body.name==name) return stmt.body
|
||||||
is WhileLoop -> if(stmt.body.name==name) return stmt.body
|
is WhileLoop -> if(stmt.body.name==name) return stmt.body
|
||||||
is BranchStatement -> {
|
is BranchStatement -> {
|
||||||
if(stmt.truepart.name==name) return stmt.truepart
|
if(stmt.truepart.name==name) return stmt.truepart
|
||||||
@ -175,8 +175,8 @@ interface INameScope {
|
|||||||
find(it.truepart)
|
find(it.truepart)
|
||||||
find(it.elsepart)
|
find(it.elsepart)
|
||||||
}
|
}
|
||||||
|
is UntilLoop -> find(it.body)
|
||||||
is RepeatLoop -> find(it.body)
|
is RepeatLoop -> find(it.body)
|
||||||
is ForeverLoop -> find(it.body)
|
|
||||||
is WhileLoop -> find(it.body)
|
is WhileLoop -> find(it.body)
|
||||||
is WhenStatement -> it.choices.forEach { choice->find(choice.statements) }
|
is WhenStatement -> it.choices.forEach { choice->find(choice.statements) }
|
||||||
else -> { /* do nothing */ }
|
else -> { /* do nothing */ }
|
||||||
|
@ -205,14 +205,14 @@ private fun prog8Parser.StatementContext.toAst() : Statement {
|
|||||||
val forloop = forloop()?.toAst()
|
val forloop = forloop()?.toAst()
|
||||||
if(forloop!=null) return forloop
|
if(forloop!=null) return forloop
|
||||||
|
|
||||||
val repeatloop = repeatloop()?.toAst()
|
val untilloop = untilloop()?.toAst()
|
||||||
if(repeatloop!=null) return repeatloop
|
if(untilloop!=null) return untilloop
|
||||||
|
|
||||||
val whileloop = whileloop()?.toAst()
|
val whileloop = whileloop()?.toAst()
|
||||||
if(whileloop!=null) return whileloop
|
if(whileloop!=null) return whileloop
|
||||||
|
|
||||||
val foreverloop = foreverloop()?.toAst()
|
val repeatloop = repeatloop()?.toAst()
|
||||||
if(foreverloop!=null) return foreverloop
|
if(repeatloop!=null) return repeatloop
|
||||||
|
|
||||||
val breakstmt = breakstmt()?.toAst()
|
val breakstmt = breakstmt()?.toAst()
|
||||||
if(breakstmt!=null) return breakstmt
|
if(breakstmt!=null) return breakstmt
|
||||||
@ -487,10 +487,6 @@ private fun prog8Parser.ExpressionContext.toAst() : Expression {
|
|||||||
// the ConstantFold takes care of that and converts the type if needed.
|
// the ConstantFold takes care of that and converts the type if needed.
|
||||||
ArrayLiteralValue(InferredTypes.InferredType.unknown(), array, position = litval.toPosition())
|
ArrayLiteralValue(InferredTypes.InferredType.unknown(), array, position = litval.toPosition())
|
||||||
}
|
}
|
||||||
litval.structliteral()!=null -> {
|
|
||||||
val values = litval.structliteral().expression().map { it.toAst() }
|
|
||||||
StructLiteralValue(values, litval.toPosition())
|
|
||||||
}
|
|
||||||
else -> throw FatalAstException("invalid parsed literal")
|
else -> throw FatalAstException("invalid parsed literal")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -609,19 +605,20 @@ private fun prog8Parser.WhileloopContext.toAst(): WhileLoop {
|
|||||||
return WhileLoop(condition, scope, toPosition())
|
return WhileLoop(condition, scope, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prog8Parser.ForeverloopContext.toAst(): ForeverLoop {
|
private fun prog8Parser.RepeatloopContext.toAst(): RepeatLoop {
|
||||||
|
val iterations = expression()?.toAst()
|
||||||
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
|
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
|
||||||
val scope = AnonymousScope(statements, statement_block()?.toPosition()
|
val scope = AnonymousScope(statements, statement_block()?.toPosition()
|
||||||
?: statement().toPosition())
|
?: statement().toPosition())
|
||||||
return ForeverLoop(scope, toPosition())
|
return RepeatLoop(iterations, scope, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prog8Parser.RepeatloopContext.toAst(): RepeatLoop {
|
private fun prog8Parser.UntilloopContext.toAst(): UntilLoop {
|
||||||
val untilCondition = expression().toAst()
|
val untilCondition = expression().toAst()
|
||||||
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
|
val statements = statement_block()?.toAst() ?: mutableListOf(statement().toAst())
|
||||||
val scope = AnonymousScope(statements, statement_block()?.toPosition()
|
val scope = AnonymousScope(statements, statement_block()?.toPosition()
|
||||||
?: statement().toPosition())
|
?: statement().toPosition())
|
||||||
return RepeatLoop(scope, untilCondition, toPosition())
|
return UntilLoop(scope, untilCondition, toPosition())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun prog8Parser.WhenstmtContext.toAst(): WhenStatement {
|
private fun prog8Parser.WhenstmtContext.toAst(): WhenStatement {
|
||||||
|
@ -455,31 +455,6 @@ class NumericLiteralValue(val type: DataType, // only numerical types allowed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StructLiteralValue(var values: List<Expression>,
|
|
||||||
override val position: Position): Expression() {
|
|
||||||
override lateinit var parent: Node
|
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
|
||||||
this.parent=parent
|
|
||||||
values.forEach { it.linkParents(this) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
|
||||||
throw FatalAstException("can't replace here")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun constValue(program: Program): NumericLiteralValue? = null
|
|
||||||
override fun accept(visitor: IAstVisitor) = visitor.visit(this)
|
|
||||||
override fun accept(visitor: AstWalker, parent: Node)= visitor.visit(this, parent)
|
|
||||||
|
|
||||||
override fun referencesIdentifiers(vararg name: String) = values.any { it.referencesIdentifiers(*name) }
|
|
||||||
override fun inferType(program: Program): InferredTypes.InferredType = InferredTypes.knownFor(DataType.STRUCT)
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "struct{ ${values.joinToString(", ")} }"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var heapIdSequence = 0 // unique ids for strings and arrays "on the heap"
|
private var heapIdSequence = 0 // unique ids for strings and arrays "on the heap"
|
||||||
|
|
||||||
class StringLiteralValue(val value: String,
|
class StringLiteralValue(val value: String,
|
||||||
|
@ -316,10 +316,10 @@ internal class AstChecker(private val program: Program,
|
|||||||
visitStatements(subroutine.statements)
|
visitStatements(subroutine.statements)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(repeatLoop: RepeatLoop) {
|
override fun visit(untilLoop: UntilLoop) {
|
||||||
if(repeatLoop.untilCondition.inferType(program).typeOrElse(DataType.STRUCT) !in IntegerDatatypes)
|
if(untilLoop.untilCondition.inferType(program).typeOrElse(DataType.STRUCT) !in IntegerDatatypes)
|
||||||
errors.err("condition value should be an integer type", repeatLoop.untilCondition.position)
|
errors.err("condition value should be an integer type", untilLoop.untilCondition.position)
|
||||||
super.visit(repeatLoop)
|
super.visit(untilLoop)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visit(whileLoop: WhileLoop) {
|
override fun visit(whileLoop: WhileLoop) {
|
||||||
@ -348,9 +348,9 @@ internal class AstChecker(private val program: Program,
|
|||||||
if(targetIdent!=null) {
|
if(targetIdent!=null) {
|
||||||
val targetVar = targetIdent.targetVarDecl(program.namespace)
|
val targetVar = targetIdent.targetVarDecl(program.namespace)
|
||||||
if(targetVar?.struct != null) {
|
if(targetVar?.struct != null) {
|
||||||
val sourceStructLv = assignment.value as? StructLiteralValue
|
val sourceStructLv = assignment.value as? ArrayLiteralValue
|
||||||
if (sourceStructLv != null) {
|
if (sourceStructLv != null) {
|
||||||
if (sourceStructLv.values.size != targetVar.struct?.numberOfElements)
|
if (sourceStructLv.value.size != targetVar.struct?.numberOfElements)
|
||||||
errors.err("number of elements doesn't match struct definition", sourceStructLv.position)
|
errors.err("number of elements doesn't match struct definition", sourceStructLv.position)
|
||||||
} else {
|
} else {
|
||||||
val sourceIdent = assignment.value as? IdentifierReference
|
val sourceIdent = assignment.value as? IdentifierReference
|
||||||
@ -503,21 +503,14 @@ internal class AstChecker(private val program: Program,
|
|||||||
checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue)
|
checkValueTypeAndRangeString(decl.datatype, decl.value as StringLiteralValue)
|
||||||
}
|
}
|
||||||
is ArrayLiteralValue -> {
|
is ArrayLiteralValue -> {
|
||||||
val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
|
|
||||||
checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue)
|
|
||||||
}
|
|
||||||
is NumericLiteralValue -> {
|
|
||||||
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
|
|
||||||
}
|
|
||||||
is StructLiteralValue -> {
|
|
||||||
if(decl.datatype==DataType.STRUCT) {
|
if(decl.datatype==DataType.STRUCT) {
|
||||||
val struct = decl.struct!!
|
val struct = decl.struct!!
|
||||||
val structLv = decl.value as StructLiteralValue
|
val structLv = decl.value as ArrayLiteralValue
|
||||||
if(struct.numberOfElements != structLv.values.size) {
|
if(struct.numberOfElements != structLv.value.size) {
|
||||||
errors.err("struct value has incorrect number of elements", structLv.position)
|
errors.err("struct value has incorrect number of elements", structLv.position)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for(value in structLv.values.zip(struct.statements)) {
|
for(value in structLv.value.zip(struct.statements)) {
|
||||||
val memberdecl = value.second as VarDecl
|
val memberdecl = value.second as VarDecl
|
||||||
val constValue = value.first.constValue(program)
|
val constValue = value.first.constValue(program)
|
||||||
if(constValue==null) {
|
if(constValue==null) {
|
||||||
@ -531,9 +524,13 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
errors.err("struct literal is wrong type to initialize this variable", decl.value!!.position)
|
val arraySpec = decl.arraysize ?: ArrayIndex.forArray(decl.value as ArrayLiteralValue)
|
||||||
|
checkValueTypeAndRangeArray(decl.datatype, decl.struct, arraySpec, decl.value as ArrayLiteralValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
is NumericLiteralValue -> {
|
||||||
|
checkValueTypeAndRange(decl.datatype, decl.value as NumericLiteralValue)
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
|
err("var/const declaration needs a compile-time constant initializer value, or range, instead found: ${decl.value!!.javaClass.simpleName}")
|
||||||
super.visit(decl)
|
super.visit(decl)
|
||||||
@ -570,8 +567,18 @@ internal class AstChecker(private val program: Program,
|
|||||||
}
|
}
|
||||||
|
|
||||||
val declValue = decl.value
|
val declValue = decl.value
|
||||||
if(declValue!=null && decl.type==VarDeclType.VAR && !declValue.inferType(program).istype(decl.datatype))
|
if(declValue!=null && decl.type==VarDeclType.VAR) {
|
||||||
|
if(decl.datatype==DataType.STRUCT) {
|
||||||
|
val valueIdt = declValue.inferType(program)
|
||||||
|
if(valueIdt.isUnknown)
|
||||||
|
throw AstException("invalid value type")
|
||||||
|
val valueDt = valueIdt.typeOrElse(DataType.STRUCT)
|
||||||
|
if(valueDt !in ArrayDatatypes)
|
||||||
|
err("initialisation of struct should be with array value", declValue.position)
|
||||||
|
} else if (!declValue.inferType(program).istype(decl.datatype)) {
|
||||||
err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})", declValue.position)
|
err("initialisation value has incompatible type (${declValue.inferType(program)}) for the variable (${decl.datatype})", declValue.position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
super.visit(decl)
|
super.visit(decl)
|
||||||
}
|
}
|
||||||
@ -1278,8 +1285,8 @@ internal class AstChecker(private val program: Program,
|
|||||||
DataType.STR -> sourceDatatype== DataType.STR
|
DataType.STR -> sourceDatatype== DataType.STR
|
||||||
DataType.STRUCT -> {
|
DataType.STRUCT -> {
|
||||||
if(sourceDatatype==DataType.STRUCT) {
|
if(sourceDatatype==DataType.STRUCT) {
|
||||||
val structLv = sourceValue as StructLiteralValue
|
val structLv = sourceValue as ArrayLiteralValue
|
||||||
val numValues = structLv.values.size
|
val numValues = structLv.value.size
|
||||||
val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!!
|
val targetstruct = target.identifier!!.targetVarDecl(program.namespace)!!.struct!!
|
||||||
return targetstruct.numberOfElements == numValues
|
return targetstruct.numberOfElements == numValues
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,8 @@ internal class AstIdentifiersChecker(private val program: Program, private val e
|
|||||||
return super.visit(decl)
|
return super.visit(decl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decl.value != null && decl.value !is StructLiteralValue) {
|
if (decl.value != null && decl.value !is ArrayLiteralValue) {
|
||||||
errors.err("initializing requires struct literal value", decl.value?.position ?: decl.position)
|
errors.err("initializing a struct requires array literal value", decl.value?.position ?: decl.position)
|
||||||
return super.visit(decl)
|
return super.visit(decl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ abstract class AstWalker {
|
|||||||
open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(foreverLoop: ForeverLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
@ -110,12 +110,11 @@ abstract class AstWalker {
|
|||||||
open fun before(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(program: Program, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(program: Program, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(structLv: StructLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
|
|
||||||
open fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun before(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun before(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
@ -137,7 +136,7 @@ abstract class AstWalker {
|
|||||||
open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(expr: PrefixExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(forLoop: ForLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(foreverLoop: ForeverLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(functionCall: FunctionCall, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(functionCallStatement: FunctionCallStatement, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(identifier: IdentifierReference, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
@ -153,12 +152,11 @@ abstract class AstWalker {
|
|||||||
open fun after(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(postIncrDecr: PostIncrDecr, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(program: Program, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(program: Program, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(range: RangeExpr, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(scope: AnonymousScope, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(string: StringLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(structDecl: StructDecl, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(structLv: StructLiteralValue, parent: Node): Iterable<IAstModification> = emptyList()
|
|
||||||
open fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(subroutine: Subroutine, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(typecast: TypecastExpression, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
open fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList()
|
open fun after(whenChoice: WhenChoice, parent: Node): Iterable<IAstModification> = emptyList()
|
||||||
@ -336,19 +334,20 @@ abstract class AstWalker {
|
|||||||
track(after(whileLoop, parent), whileLoop, parent)
|
track(after(whileLoop, parent), whileLoop, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(foreverLoop: ForeverLoop, parent: Node) {
|
|
||||||
track(before(foreverLoop, parent), foreverLoop, parent)
|
|
||||||
foreverLoop.body.accept(this, foreverLoop)
|
|
||||||
track(after(foreverLoop, parent), foreverLoop, parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun visit(repeatLoop: RepeatLoop, parent: Node) {
|
fun visit(repeatLoop: RepeatLoop, parent: Node) {
|
||||||
track(before(repeatLoop, parent), repeatLoop, parent)
|
track(before(repeatLoop, parent), repeatLoop, parent)
|
||||||
repeatLoop.untilCondition.accept(this, repeatLoop)
|
repeatLoop.iterations?.accept(this, repeatLoop)
|
||||||
repeatLoop.body.accept(this, repeatLoop)
|
repeatLoop.body.accept(this, repeatLoop)
|
||||||
track(after(repeatLoop, parent), repeatLoop, parent)
|
track(after(repeatLoop, parent), repeatLoop, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun visit(untilLoop: UntilLoop, parent: Node) {
|
||||||
|
track(before(untilLoop, parent), untilLoop, parent)
|
||||||
|
untilLoop.untilCondition.accept(this, untilLoop)
|
||||||
|
untilLoop.body.accept(this, untilLoop)
|
||||||
|
track(after(untilLoop, parent), untilLoop, parent)
|
||||||
|
}
|
||||||
|
|
||||||
fun visit(returnStmt: Return, parent: Node) {
|
fun visit(returnStmt: Return, parent: Node) {
|
||||||
track(before(returnStmt, parent), returnStmt, parent)
|
track(before(returnStmt, parent), returnStmt, parent)
|
||||||
returnStmt.value?.accept(this, returnStmt)
|
returnStmt.value?.accept(this, returnStmt)
|
||||||
@ -434,11 +433,5 @@ abstract class AstWalker {
|
|||||||
structDecl.statements.forEach { it.accept(this, structDecl) }
|
structDecl.statements.forEach { it.accept(this, structDecl) }
|
||||||
track(after(structDecl, parent), structDecl, parent)
|
track(after(structDecl, parent), structDecl, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(structLv: StructLiteralValue, parent: Node) {
|
|
||||||
track(before(structLv, parent), structLv, parent)
|
|
||||||
structLv.values.forEach { it.accept(this, structLv) }
|
|
||||||
track(after(structLv, parent), structLv, parent)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,13 +112,14 @@ interface IAstVisitor {
|
|||||||
whileLoop.body.accept(this)
|
whileLoop.body.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(foreverLoop: ForeverLoop) {
|
fun visit(repeatLoop: RepeatLoop) {
|
||||||
foreverLoop.body.accept(this)
|
repeatLoop.iterations?.accept(this)
|
||||||
|
repeatLoop.body.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(repeatLoop: RepeatLoop) {
|
fun visit(untilLoop: UntilLoop) {
|
||||||
repeatLoop.untilCondition.accept(this)
|
untilLoop.untilCondition.accept(this)
|
||||||
repeatLoop.body.accept(this)
|
untilLoop.body.accept(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(returnStmt: Return) {
|
fun visit(returnStmt: Return) {
|
||||||
@ -178,8 +179,4 @@ interface IAstVisitor {
|
|||||||
fun visit(structDecl: StructDecl) {
|
fun visit(structDecl: StructDecl) {
|
||||||
structDecl.statements.forEach { it.accept(this) }
|
structDecl.statements.forEach { it.accept(this) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun visit(structLv: StructLiteralValue) {
|
|
||||||
structLv.values.forEach { it.accept(this) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,8 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
|||||||
val valueType = assignment.value.inferType(program)
|
val valueType = assignment.value.inferType(program)
|
||||||
val targetType = assignment.target.inferType(program, assignment)
|
val targetType = assignment.target.inferType(program, assignment)
|
||||||
if(valueType.istype(DataType.STRUCT) && targetType.istype(DataType.STRUCT)) {
|
if(valueType.istype(DataType.STRUCT) && targetType.istype(DataType.STRUCT)) {
|
||||||
val assignments = if (assignment.value is StructLiteralValue) {
|
val assignments = if (assignment.value is ArrayLiteralValue) {
|
||||||
flattenStructAssignmentFromStructLiteral(assignment, program) // 'structvar = { ..... } '
|
flattenStructAssignmentFromStructLiteral(assignment, program) // 'structvar = [ ..... ] '
|
||||||
} else {
|
} else {
|
||||||
flattenStructAssignmentFromIdentifier(assignment, program) // 'structvar1 = structvar2'
|
flattenStructAssignmentFromIdentifier(assignment, program) // 'structvar1 = structvar2'
|
||||||
}
|
}
|
||||||
@ -128,11 +128,11 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
|||||||
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
val targetVar = identifier.targetVarDecl(program.namespace)!!
|
||||||
val struct = targetVar.struct!!
|
val struct = targetVar.struct!!
|
||||||
|
|
||||||
val slv = structAssignment.value as? StructLiteralValue
|
val slv = structAssignment.value as? ArrayLiteralValue
|
||||||
if(slv==null || slv.values.size != struct.numberOfElements)
|
if(slv==null || slv.value.size != struct.numberOfElements)
|
||||||
throw FatalAstException("element count mismatch")
|
throw FatalAstException("element count mismatch")
|
||||||
|
|
||||||
return struct.statements.zip(slv.values).map { (targetDecl, sourceValue) ->
|
return struct.statements.zip(slv.value).map { (targetDecl, sourceValue) ->
|
||||||
targetDecl as VarDecl
|
targetDecl as VarDecl
|
||||||
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
val mangled = mangledStructMemberName(identifierName, targetDecl.name)
|
||||||
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
val idref = IdentifierReference(listOf(mangled), structAssignment.position)
|
||||||
@ -174,7 +174,7 @@ internal class StatementReorderer(val program: Program) : AstWalker() {
|
|||||||
assign
|
assign
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is StructLiteralValue -> {
|
is ArrayLiteralValue -> {
|
||||||
throw IllegalArgumentException("not going to flatten a structLv assignment here")
|
throw IllegalArgumentException("not going to flatten a structLv assignment here")
|
||||||
}
|
}
|
||||||
else -> throw FatalAstException("strange struct value")
|
else -> throw FatalAstException("strange struct value")
|
||||||
|
@ -179,51 +179,6 @@ class TypecastsAdder(val program: Program, val errors: ErrorReporter) : AstWalke
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun after(structLv: StructLiteralValue, parent: Node): Iterable<IAstModification> {
|
|
||||||
// assignment of a struct literal value, some member values may need proper typecast
|
|
||||||
|
|
||||||
fun addTypecastsIfNeeded(struct: StructDecl): Iterable<IAstModification> {
|
|
||||||
val newValues = struct.statements.zip(structLv.values).map { (structMemberDecl, memberValue) ->
|
|
||||||
val memberDt = (structMemberDecl as VarDecl).datatype
|
|
||||||
val valueDt = memberValue.inferType(program)
|
|
||||||
if (valueDt.typeOrElse(memberDt) != memberDt)
|
|
||||||
TypecastExpression(memberValue, memberDt, true, memberValue.position)
|
|
||||||
else
|
|
||||||
memberValue
|
|
||||||
}
|
|
||||||
|
|
||||||
class StructLvValueReplacer(val targetStructLv: StructLiteralValue, val typecastValues: List<Expression>) : IAstModification {
|
|
||||||
override fun perform() {
|
|
||||||
targetStructLv.values = typecastValues
|
|
||||||
typecastValues.forEach { it.linkParents(targetStructLv) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return if(structLv.values.zip(newValues).any { (v1, v2) -> v1 !== v2})
|
|
||||||
listOf(StructLvValueReplacer(structLv, newValues))
|
|
||||||
else
|
|
||||||
emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
val decl = structLv.parent as? VarDecl
|
|
||||||
if(decl != null) {
|
|
||||||
val struct = decl.struct
|
|
||||||
if(struct != null)
|
|
||||||
return addTypecastsIfNeeded(struct)
|
|
||||||
} else {
|
|
||||||
val assign = structLv.parent as? Assignment
|
|
||||||
if (assign != null) {
|
|
||||||
val decl2 = assign.target.identifier?.targetVarDecl(program.namespace)
|
|
||||||
if(decl2 != null) {
|
|
||||||
val struct = decl2.struct
|
|
||||||
if(struct != null)
|
|
||||||
return addTypecastsIfNeeded(struct)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return noModifications
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> {
|
override fun after(returnStmt: Return, parent: Node): Iterable<IAstModification> {
|
||||||
// add a typecast to the return type if it doesn't match the subroutine's signature
|
// add a typecast to the return type if it doesn't match the subroutine's signature
|
||||||
val returnValue = returnStmt.value
|
val returnValue = returnStmt.value
|
||||||
|
@ -270,7 +270,7 @@ open class VarDecl(val type: VarDeclType,
|
|||||||
fun flattenStructMembers(): MutableList<Statement> {
|
fun flattenStructMembers(): MutableList<Statement> {
|
||||||
val result = struct!!.statements.withIndex().map {
|
val result = struct!!.statements.withIndex().map {
|
||||||
val member = it.value as VarDecl
|
val member = it.value as VarDecl
|
||||||
val initvalue = if(value!=null) (value as StructLiteralValue).values[it.index] else null
|
val initvalue = if(value!=null) (value as ArrayLiteralValue).value[it.index] else null
|
||||||
VarDecl(
|
VarDecl(
|
||||||
VarDeclType.VAR,
|
VarDeclType.VAR,
|
||||||
member.datatype,
|
member.datatype,
|
||||||
@ -780,17 +780,21 @@ class WhileLoop(var condition: Expression,
|
|||||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ForeverLoop(var body: AnonymousScope, override val position: Position) : Statement() {
|
class RepeatLoop(var iterations: Expression?, var body: AnonymousScope, override val position: Position) : Statement() {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
|
||||||
override fun linkParents(parent: Node) {
|
override fun linkParents(parent: Node) {
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
|
iterations?.linkParents(this)
|
||||||
body.linkParents(this)
|
body.linkParents(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun replaceChildNode(node: Node, replacement: Node) {
|
override fun replaceChildNode(node: Node, replacement: Node) {
|
||||||
require(replacement is AnonymousScope && node===body)
|
when {
|
||||||
body = replacement
|
node===iterations -> iterations = replacement as Expression
|
||||||
|
node===body -> body = replacement as AnonymousScope
|
||||||
|
else -> throw FatalAstException("invalid replace")
|
||||||
|
}
|
||||||
replacement.parent = this
|
replacement.parent = this
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -798,7 +802,7 @@ class ForeverLoop(var body: AnonymousScope, override val position: Position) : S
|
|||||||
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
override fun accept(visitor: AstWalker, parent: Node) = visitor.visit(this, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
class RepeatLoop(var body: AnonymousScope,
|
class UntilLoop(var body: AnonymousScope,
|
||||||
var untilCondition: Expression,
|
var untilCondition: Expression,
|
||||||
override val position: Position) : Statement() {
|
override val position: Position) : Statement() {
|
||||||
override lateinit var parent: Node
|
override lateinit var parent: Node
|
||||||
|
@ -641,8 +641,8 @@ internal class AsmGen(private val program: Program,
|
|||||||
is Continue -> out(" jmp ${loopContinueLabels.peek()}")
|
is Continue -> out(" jmp ${loopContinueLabels.peek()}")
|
||||||
is Break -> out(" jmp ${loopEndLabels.peek()}")
|
is Break -> out(" jmp ${loopEndLabels.peek()}")
|
||||||
is WhileLoop -> translate(stmt)
|
is WhileLoop -> translate(stmt)
|
||||||
is ForeverLoop -> translate(stmt)
|
|
||||||
is RepeatLoop -> translate(stmt)
|
is RepeatLoop -> translate(stmt)
|
||||||
|
is UntilLoop -> translate(stmt)
|
||||||
is WhenStatement -> translate(stmt)
|
is WhenStatement -> translate(stmt)
|
||||||
is BuiltinFunctionStatementPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore?")
|
is BuiltinFunctionStatementPlaceholder -> throw AssemblyError("builtin function should not have placeholder anymore?")
|
||||||
is AnonymousScope -> translate(stmt)
|
is AnonymousScope -> translate(stmt)
|
||||||
@ -673,15 +673,72 @@ internal class AsmGen(private val program: Program,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(stmt: ForeverLoop) {
|
private fun translate(stmt: RepeatLoop) {
|
||||||
val foreverLabel = makeLabel("forever")
|
val repeatLabel = makeLabel("repeat")
|
||||||
val endLabel = makeLabel("foreverend")
|
val endLabel = makeLabel("repeatend")
|
||||||
|
val counterLabel = makeLabel("repeatcounter")
|
||||||
loopEndLabels.push(endLabel)
|
loopEndLabels.push(endLabel)
|
||||||
loopContinueLabels.push(foreverLabel)
|
loopContinueLabels.push(repeatLabel)
|
||||||
out(foreverLabel)
|
|
||||||
|
when (stmt.iterations) {
|
||||||
|
null -> {
|
||||||
|
// endless loop
|
||||||
|
out(repeatLabel)
|
||||||
translate(stmt.body)
|
translate(stmt.body)
|
||||||
out(" jmp $foreverLabel")
|
out(" jmp $repeatLabel")
|
||||||
out(endLabel)
|
out(endLabel)
|
||||||
|
}
|
||||||
|
is NumericLiteralValue -> {
|
||||||
|
val iterations = (stmt.iterations as NumericLiteralValue).number.toInt()
|
||||||
|
if(iterations<0 || iterations > 65536)
|
||||||
|
throw AssemblyError("invalid number of iterations")
|
||||||
|
when {
|
||||||
|
iterations == 0 -> {}
|
||||||
|
iterations <= 255 -> {
|
||||||
|
out("""
|
||||||
|
lda #${iterations}
|
||||||
|
sta $counterLabel
|
||||||
|
$repeatLabel lda $counterLabel
|
||||||
|
beq $endLabel
|
||||||
|
dec $counterLabel
|
||||||
|
""")
|
||||||
|
translate(stmt.body)
|
||||||
|
out("""
|
||||||
|
jmp $repeatLabel
|
||||||
|
$counterLabel .byte 0
|
||||||
|
$endLabel""")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
out("""
|
||||||
|
lda #<${iterations}
|
||||||
|
sta $counterLabel
|
||||||
|
lda #>${iterations}
|
||||||
|
sta $counterLabel+1
|
||||||
|
$repeatLabel lda $counterLabel
|
||||||
|
bne +
|
||||||
|
lda $counterLabel+1
|
||||||
|
beq $endLabel
|
||||||
|
+ lda $counterLabel
|
||||||
|
bne +
|
||||||
|
dec $counterLabel+1
|
||||||
|
+ dec $counterLabel
|
||||||
|
""")
|
||||||
|
translate(stmt.body)
|
||||||
|
out("""
|
||||||
|
jmp $repeatLabel
|
||||||
|
$counterLabel .word 0
|
||||||
|
$endLabel""")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is IdentifierReference -> {
|
||||||
|
TODO("iterations ${stmt.iterations}")
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
TODO("repeat loop with iterations ${stmt.iterations}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
loopEndLabels.pop()
|
loopEndLabels.pop()
|
||||||
loopContinueLabels.pop()
|
loopContinueLabels.pop()
|
||||||
}
|
}
|
||||||
@ -714,7 +771,7 @@ internal class AsmGen(private val program: Program,
|
|||||||
loopContinueLabels.pop()
|
loopContinueLabels.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translate(stmt: RepeatLoop) {
|
private fun translate(stmt: UntilLoop) {
|
||||||
val repeatLabel = makeLabel("repeat")
|
val repeatLabel = makeLabel("repeat")
|
||||||
val endLabel = makeLabel("repeatend")
|
val endLabel = makeLabel("repeatend")
|
||||||
loopEndLabels.push(endLabel)
|
loopEndLabels.push(endLabel)
|
||||||
|
@ -832,7 +832,6 @@ internal class AssignmentAsmGen(private val program: Program, private val errors
|
|||||||
assignFromEvalResult(assign.target)
|
assignFromEvalResult(assign.target)
|
||||||
}
|
}
|
||||||
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign")
|
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array assignment $assign")
|
||||||
is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened ${assign.value.position}")
|
|
||||||
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}")
|
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values ${assign.value.position}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ internal class ExpressionsAsmGen(private val program: Program, private val asmge
|
|||||||
is IdentifierReference -> translateExpression(expression)
|
is IdentifierReference -> translateExpression(expression)
|
||||||
is FunctionCall -> translateExpression(expression)
|
is FunctionCall -> translateExpression(expression)
|
||||||
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable")
|
is ArrayLiteralValue, is StringLiteralValue -> throw AssemblyError("no asm gen for string/array literal value assignment - should have been replaced by a variable")
|
||||||
is StructLiteralValue -> throw AssemblyError("struct literal value assignment should have been flattened")
|
|
||||||
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
is RangeExpr -> throw AssemblyError("range expression should have been changed into array values")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,6 @@ internal class FunctionCallAsmGen(private val program: Program, private val asmg
|
|||||||
when {
|
when {
|
||||||
stmt.args.all {it is AddressOf ||
|
stmt.args.all {it is AddressOf ||
|
||||||
it is NumericLiteralValue ||
|
it is NumericLiteralValue ||
|
||||||
it is StructLiteralValue ||
|
|
||||||
it is StringLiteralValue ||
|
it is StringLiteralValue ||
|
||||||
it is ArrayLiteralValue ||
|
it is ArrayLiteralValue ||
|
||||||
it is IdentifierReference} -> {
|
it is IdentifierReference} -> {
|
||||||
|
@ -251,18 +251,18 @@ internal class StatementOptimizer(private val program: Program,
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun before(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
|
override fun before(untilLoop: UntilLoop, parent: Node): Iterable<IAstModification> {
|
||||||
val constvalue = repeatLoop.untilCondition.constValue(program)
|
val constvalue = untilLoop.untilCondition.constValue(program)
|
||||||
if(constvalue!=null) {
|
if(constvalue!=null) {
|
||||||
if(constvalue.asBooleanValue) {
|
if(constvalue.asBooleanValue) {
|
||||||
// always true -> keep only the statement block (if there are no continue and break statements)
|
// always true -> keep only the statement block (if there are no continue and break statements)
|
||||||
errors.warn("condition is always true", repeatLoop.untilCondition.position)
|
errors.warn("condition is always true", untilLoop.untilCondition.position)
|
||||||
if(!hasContinueOrBreak(repeatLoop.body))
|
if(!hasContinueOrBreak(untilLoop.body))
|
||||||
return listOf(IAstModification.ReplaceNode(repeatLoop, repeatLoop.body, parent))
|
return listOf(IAstModification.ReplaceNode(untilLoop, untilLoop.body, parent))
|
||||||
} else {
|
} else {
|
||||||
// always false
|
// always false
|
||||||
val forever = ForeverLoop(repeatLoop.body, repeatLoop.position)
|
val forever = RepeatLoop(null, untilLoop.body, untilLoop.position)
|
||||||
return listOf(IAstModification.ReplaceNode(repeatLoop, forever, parent))
|
return listOf(IAstModification.ReplaceNode(untilLoop, forever, parent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return noModifications
|
return noModifications
|
||||||
@ -273,7 +273,7 @@ internal class StatementOptimizer(private val program: Program,
|
|||||||
if(constvalue!=null) {
|
if(constvalue!=null) {
|
||||||
return if(constvalue.asBooleanValue) {
|
return if(constvalue.asBooleanValue) {
|
||||||
// always true
|
// always true
|
||||||
val forever = ForeverLoop(whileLoop.body, whileLoop.position)
|
val forever = RepeatLoop(null, whileLoop.body, whileLoop.position)
|
||||||
listOf(IAstModification.ReplaceNode(whileLoop, forever, parent))
|
listOf(IAstModification.ReplaceNode(whileLoop, forever, parent))
|
||||||
} else {
|
} else {
|
||||||
// always false -> remove the while statement altogether
|
// always false -> remove the while statement altogether
|
||||||
@ -284,6 +284,24 @@ internal class StatementOptimizer(private val program: Program,
|
|||||||
return noModifications
|
return noModifications
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun after(repeatLoop: RepeatLoop, parent: Node): Iterable<IAstModification> {
|
||||||
|
val iter = repeatLoop.iterations
|
||||||
|
if(iter!=null) {
|
||||||
|
if(repeatLoop.body.containsNoCodeNorVars()) {
|
||||||
|
errors.warn("empty loop removed", repeatLoop.position)
|
||||||
|
return listOf(IAstModification.Remove(repeatLoop, parent))
|
||||||
|
}
|
||||||
|
val iterations = iter.constValue(program)?.number?.toInt()
|
||||||
|
if (iterations == 0) {
|
||||||
|
errors.warn("iterations is always 0, removed loop", iter.position)
|
||||||
|
return listOf(IAstModification.Remove(repeatLoop, parent))
|
||||||
|
}
|
||||||
|
if (iterations == 1)
|
||||||
|
errors.warn("iterations is always 1", iter.position)
|
||||||
|
}
|
||||||
|
return noModifications
|
||||||
|
}
|
||||||
|
|
||||||
override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
|
override fun after(whenStatement: WhenStatement, parent: Node): Iterable<IAstModification> {
|
||||||
// remove empty choices
|
// remove empty choices
|
||||||
class ChoiceRemover(val choice: WhenChoice) : IAstModification {
|
class ChoiceRemover(val choice: WhenChoice) : IAstModification {
|
||||||
|
@ -50,7 +50,7 @@ Code
|
|||||||
There are different kinds of instructions ('statements' is a better name) such as:
|
There are different kinds of instructions ('statements' is a better name) such as:
|
||||||
|
|
||||||
- value assignment
|
- value assignment
|
||||||
- looping (for, while, repeat, unconditional jumps)
|
- looping (for, while, do-until, repeat, unconditional jumps)
|
||||||
- conditional execution (if - then - else, when, and conditional jumps)
|
- conditional execution (if - then - else, when, and conditional jumps)
|
||||||
- subroutine calls
|
- subroutine calls
|
||||||
- label definition
|
- label definition
|
||||||
@ -137,7 +137,7 @@ Scopes are created using either of these two statements:
|
|||||||
|
|
||||||
.. important::
|
.. important::
|
||||||
Unlike most other programming languages, a new scope is *not* created inside
|
Unlike most other programming languages, a new scope is *not* created inside
|
||||||
for, while and repeat statements, the if statement, and the branching conditionals.
|
for, while, repeat, and do-until statements, the if statement, and the branching conditionals.
|
||||||
These all share the same scope from the subroutine they're defined in.
|
These all share the same scope from the subroutine they're defined in.
|
||||||
You can define variables in these blocks, but these will be treated as if they
|
You can define variables in these blocks, but these will be treated as if they
|
||||||
were defined in the subroutine instead.
|
were defined in the subroutine instead.
|
||||||
@ -391,11 +391,9 @@ The loop variable must be declared as byte or word earlier so you can reuse it f
|
|||||||
Iterating with a floating point variable is not supported. If you want to loop over a floating-point array, use a loop with an integer index variable instead.
|
Iterating with a floating point variable is not supported. If you want to loop over a floating-point array, use a loop with an integer index variable instead.
|
||||||
|
|
||||||
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
The *while*-loop is used to repeat a piece of code while a certain condition is still true.
|
||||||
The *repeat--until* loop is used to repeat a piece of code until a certain condition is true.
|
The *do--until* loop is used to repeat a piece of code until a certain condition is true.
|
||||||
|
The *repeat* loop is used as a short notation of a for loop where the loop variable doesn't matter and you're only interested in the number of iterations.
|
||||||
The *forever*-loop is used to simply run a piece of code in a loop, forever. You can still
|
(without iteration count specified it simply loops forever).
|
||||||
break out of this loop if desired. A "while true" or "until false" loop is equivalent to
|
|
||||||
a forever-loop.
|
|
||||||
|
|
||||||
You can also create loops by using the ``goto`` statement, but this should usually be avoided.
|
You can also create loops by using the ``goto`` statement, but this should usually be avoided.
|
||||||
|
|
||||||
|
@ -596,31 +596,33 @@ You can use a single statement, or a statement block like in the example below::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
repeat-until loop
|
do-until loop
|
||||||
^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
||||||
Until the given condition is true (1), repeat the given statement(s).
|
Until the given condition is true (1), repeat the given statement(s).
|
||||||
You can use a single statement, or a statement block like in the example below::
|
You can use a single statement, or a statement block like in the example below::
|
||||||
|
|
||||||
repeat {
|
do {
|
||||||
; do something...
|
; do something...
|
||||||
break ; break out of the loop
|
break ; break out of the loop
|
||||||
continue ; immediately enter next iteration
|
continue ; immediately enter next iteration
|
||||||
} until <condition>
|
} until <condition>
|
||||||
|
|
||||||
|
|
||||||
forever loop
|
repeat loop
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
|
|
||||||
Simply run the code in a loop, forever. It's the same as a while true or until false loop,
|
When you're only interested in repeating something a given number of times.
|
||||||
or just a jump back to a previous label. You can still break out of this loop as well, if you want::
|
It's a short hand for a for loop without an explicit loop variable::
|
||||||
|
|
||||||
forever {
|
repeat 15 {
|
||||||
; .. do stuff
|
; do something...
|
||||||
if something
|
break ; you can break out of the loop
|
||||||
break ; you can exit the loop if you want
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
If you omit the iteration count, it simply loops forever.
|
||||||
|
You can still ``break`` out of such a loop if you want though.
|
||||||
|
|
||||||
|
|
||||||
Conditional Execution and Jumps
|
Conditional Execution and Jumps
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
@ -21,7 +21,7 @@ main {
|
|||||||
ubyte active_height = 24
|
ubyte active_height = 24
|
||||||
ubyte upwards = true
|
ubyte upwards = true
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
ubyte mountain = 223 ; slope upwards
|
ubyte mountain = 223 ; slope upwards
|
||||||
if active_height < target_height {
|
if active_height < target_height {
|
||||||
active_height++
|
active_height++
|
||||||
|
@ -16,7 +16,7 @@ sub start() {
|
|||||||
void c64.CHRIN()
|
void c64.CHRIN()
|
||||||
c64.CLEARSCR()
|
c64.CLEARSCR()
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
uword note
|
uword note
|
||||||
for note in notes {
|
for note in notes {
|
||||||
ubyte note1 = lsb(note)
|
ubyte note1 = lsb(note)
|
||||||
|
@ -39,7 +39,7 @@ graphics {
|
|||||||
|
|
||||||
if dx >= dy {
|
if dx >= dy {
|
||||||
if positive_ix {
|
if positive_ix {
|
||||||
forever {
|
repeat {
|
||||||
plot(y1)
|
plot(y1)
|
||||||
if plotx==x2
|
if plotx==x2
|
||||||
return
|
return
|
||||||
@ -51,7 +51,7 @@ graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
forever {
|
repeat {
|
||||||
plot(y1)
|
plot(y1)
|
||||||
if plotx==x2
|
if plotx==x2
|
||||||
return
|
return
|
||||||
@ -66,7 +66,7 @@ graphics {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if positive_ix {
|
if positive_ix {
|
||||||
forever {
|
repeat {
|
||||||
plot(y1)
|
plot(y1)
|
||||||
if y1 == y2
|
if y1 == y2
|
||||||
return
|
return
|
||||||
@ -78,7 +78,7 @@ graphics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
forever {
|
repeat {
|
||||||
plot(y1)
|
plot(y1)
|
||||||
if y1 == y2
|
if y1 == y2
|
||||||
return
|
return
|
||||||
|
@ -19,7 +19,7 @@ main {
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
float time=0.0
|
float time=0.0
|
||||||
forever {
|
repeat {
|
||||||
rotate_vertices(time)
|
rotate_vertices(time)
|
||||||
c64scr.clear_screenchars(32)
|
c64scr.clear_screenchars(32)
|
||||||
draw_edges()
|
draw_edges()
|
||||||
|
@ -82,7 +82,7 @@ main {
|
|||||||
uword anglex
|
uword anglex
|
||||||
uword angley
|
uword angley
|
||||||
uword anglez
|
uword anglez
|
||||||
forever {
|
repeat {
|
||||||
c64.TIME_LO=0
|
c64.TIME_LO=0
|
||||||
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
||||||
position_sprites()
|
position_sprites()
|
||||||
|
@ -21,7 +21,7 @@ main {
|
|||||||
uword anglex
|
uword anglex
|
||||||
uword angley
|
uword angley
|
||||||
uword anglez
|
uword anglez
|
||||||
forever {
|
repeat {
|
||||||
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
rotate_vertices(msb(anglex), msb(angley), msb(anglez))
|
||||||
c64scr.clear_screenchars(32)
|
c64scr.clear_screenchars(32)
|
||||||
draw_edges()
|
draw_edges()
|
||||||
|
@ -10,7 +10,7 @@ main {
|
|||||||
graphics.enable_bitmap_mode()
|
graphics.enable_bitmap_mode()
|
||||||
draw_lines()
|
draw_lines()
|
||||||
draw_circles()
|
draw_circles()
|
||||||
forever {
|
repeat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ main {
|
|||||||
ubyte y = y1
|
ubyte y = y1
|
||||||
|
|
||||||
if dx >= dy {
|
if dx >= dy {
|
||||||
forever {
|
repeat {
|
||||||
c64scr.setcc(x, y, 42, 5)
|
c64scr.setcc(x, y, 42, 5)
|
||||||
if x==x2
|
if x==x2
|
||||||
return
|
return
|
||||||
@ -89,7 +89,7 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
forever {
|
repeat {
|
||||||
c64scr.setcc(x, y, 42, 5)
|
c64scr.setcc(x, y, 42, 5)
|
||||||
if y == y2
|
if y == y2
|
||||||
return
|
return
|
||||||
|
@ -48,7 +48,7 @@ main {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@ main {
|
|||||||
; calculate primes
|
; calculate primes
|
||||||
c64scr.print("prime numbers up to 255:\n\n")
|
c64scr.print("prime numbers up to 255:\n\n")
|
||||||
ubyte amount=0
|
ubyte amount=0
|
||||||
forever {
|
repeat {
|
||||||
ubyte prime = find_next_prime()
|
ubyte prime = find_next_prime()
|
||||||
if prime==0
|
if prime==0
|
||||||
break
|
break
|
||||||
|
@ -7,7 +7,7 @@ main {
|
|||||||
c64.SCROLY &= %11101111 ; blank the screen
|
c64.SCROLY &= %11101111 ; blank the screen
|
||||||
c64utils.set_rasterirq_excl(40) ; register exclusive raster irq handler
|
c64utils.set_rasterirq_excl(40) ; register exclusive raster irq handler
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
; enjoy the moving bars :)
|
; enjoy the moving bars :)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ main {
|
|||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
|
|
||||||
Color purple = {255, 0, 255}
|
Color purple = [255, 0, 255]
|
||||||
|
|
||||||
Color other
|
Color other
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ main {
|
|||||||
float t
|
float t
|
||||||
ubyte color
|
ubyte color
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
ubyte xx=(sin(t) * width/2.2) + width/2.0 as ubyte
|
ubyte xx=(sin(t) * width/2.2) + width/2.0 as ubyte
|
||||||
ubyte yy=(cos(t*1.1356) * height/2.2) + height/2.0 as ubyte
|
ubyte yy=(cos(t*1.1356) * height/2.2) + height/2.0 as ubyte
|
||||||
c64scr.setcc(xx, yy, 81, color)
|
c64scr.setcc(xx, yy, 81, color)
|
||||||
|
@ -15,7 +15,7 @@ main {
|
|||||||
|
|
||||||
Ball ball
|
Ball ball
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
ubyte x = msb(sin8u(msb(ball.anglex)) as uword * width)
|
ubyte x = msb(sin8u(msb(ball.anglex)) as uword * width)
|
||||||
ubyte y = msb(cos8u(msb(ball.angley)) as uword * height)
|
ubyte y = msb(cos8u(msb(ball.angley)) as uword * height)
|
||||||
c64scr.setcc(x, y, 81, ball.color)
|
c64scr.setcc(x, y, 81, ball.color)
|
||||||
|
@ -7,11 +7,64 @@
|
|||||||
|
|
||||||
main {
|
main {
|
||||||
|
|
||||||
|
; TODO check removal of empty loops
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sub start() {
|
sub start() {
|
||||||
ubyte i
|
ubyte i
|
||||||
for i in 0 to 20 {
|
for i in 1 to 20 {
|
||||||
c64scr.print_ub(i)
|
c64.CHROUT('*')
|
||||||
c64.CHROUT('\n')
|
|
||||||
}
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
i=0
|
||||||
|
do {
|
||||||
|
c64.CHROUT('*')
|
||||||
|
i++
|
||||||
|
} until i==20
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
c64.CHROUT('*')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
repeat 0 {
|
||||||
|
c64.CHROUT('@')
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
repeat 1 {
|
||||||
|
c64.CHROUT('1')
|
||||||
|
continue
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
repeat 255 {
|
||||||
|
c64.CHROUT('@')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
repeat 256 {
|
||||||
|
c64.CHROUT('!')
|
||||||
|
}
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
uword teller
|
||||||
|
repeat 4000 {
|
||||||
|
teller++
|
||||||
|
}
|
||||||
|
c64scr.print_uw(teller)
|
||||||
|
c64.CHROUT('\n')
|
||||||
|
|
||||||
|
|
||||||
|
repeat {
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ main {
|
|||||||
turtle.rt(94)
|
turtle.rt(94)
|
||||||
}
|
}
|
||||||
|
|
||||||
forever {
|
repeat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,8 +94,8 @@ statement :
|
|||||||
| returnstmt
|
| returnstmt
|
||||||
| forloop
|
| forloop
|
||||||
| whileloop
|
| whileloop
|
||||||
|
| untilloop
|
||||||
| repeatloop
|
| repeatloop
|
||||||
| foreverloop
|
|
||||||
| whenstmt
|
| whenstmt
|
||||||
| breakstmt
|
| breakstmt
|
||||||
| continuestmt
|
| continuestmt
|
||||||
@ -228,8 +228,6 @@ booleanliteral : 'true' | 'false' ;
|
|||||||
|
|
||||||
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines
|
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines
|
||||||
|
|
||||||
structliteral : '{' EOL? expression (',' EOL? expression)* EOL? '}' ; // you can split the values over several lines
|
|
||||||
|
|
||||||
stringliteral : ALT_STRING_ENCODING? STRING ;
|
stringliteral : ALT_STRING_ENCODING? STRING ;
|
||||||
|
|
||||||
charliteral : ALT_STRING_ENCODING? SINGLECHAR ;
|
charliteral : ALT_STRING_ENCODING? SINGLECHAR ;
|
||||||
@ -244,7 +242,6 @@ literalvalue :
|
|||||||
| stringliteral
|
| stringliteral
|
||||||
| charliteral
|
| charliteral
|
||||||
| floatliteral
|
| floatliteral
|
||||||
| structliteral
|
|
||||||
;
|
;
|
||||||
|
|
||||||
inlineasm : '%asm' INLINEASMBLOCK;
|
inlineasm : '%asm' INLINEASMBLOCK;
|
||||||
@ -304,9 +301,9 @@ forloop : 'for' identifier 'in' expression EOL? (statement | statement_block) ;
|
|||||||
|
|
||||||
whileloop: 'while' expression EOL? (statement | statement_block) ;
|
whileloop: 'while' expression EOL? (statement | statement_block) ;
|
||||||
|
|
||||||
repeatloop: 'repeat' (statement | statement_block) EOL? 'until' expression ;
|
untilloop: 'do' (statement | statement_block) EOL? 'until' expression ;
|
||||||
|
|
||||||
foreverloop: 'forever' EOL? (statement | statement_block) ;
|
repeatloop: 'repeat' expression? EOL? (statement | statement_block) ;
|
||||||
|
|
||||||
whenstmt: 'when' expression '{' EOL (when_choice | EOL) * '}' EOL? ;
|
whenstmt: 'when' expression '{' EOL (when_choice | EOL) * '}' EOL? ;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user