mirror of
https://github.com/irmen/prog8.git
synced 2024-10-17 10:24:55 +00:00
fix infinte loop in constantfolding of when choices
This commit is contained in:
parent
3aea32551b
commit
025be8cb7c
@ -343,7 +343,7 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
||||
}
|
||||
|
||||
override fun visit(repeatLoop: RepeatLoop) {
|
||||
outputln("repeat ")
|
||||
output("repeat ")
|
||||
repeatLoop.body.accept(this)
|
||||
output(" until ")
|
||||
repeatLoop.untilCondition.accept(this)
|
||||
@ -427,13 +427,14 @@ class AstToSourceCode(val output: (text: String) -> Unit, val program: Program):
|
||||
}
|
||||
|
||||
override fun visit(whenChoice: WhenChoice) {
|
||||
if(whenChoice.values==null)
|
||||
val choiceValues = whenChoice.values
|
||||
if(choiceValues==null)
|
||||
outputi("else -> ")
|
||||
else {
|
||||
outputi("")
|
||||
for(value in whenChoice.values) {
|
||||
for(value in choiceValues) {
|
||||
value.accept(this)
|
||||
if(value !== whenChoice.values.last())
|
||||
if(value !== choiceValues.last())
|
||||
output(",")
|
||||
}
|
||||
output(" -> ")
|
||||
|
@ -962,7 +962,7 @@ internal class AstChecker(private val program: Program,
|
||||
val whenStmt = whenChoice.parent as WhenStatement
|
||||
if(whenChoice.values!=null) {
|
||||
val conditionType = whenStmt.condition.inferType(program)
|
||||
val constvalues = whenChoice.values.map { it.constValue(program) }
|
||||
val constvalues = whenChoice.values!!.map { it.constValue(program) }
|
||||
for(constvalue in constvalues) {
|
||||
when {
|
||||
constvalue == null -> checkResult.add(SyntaxError("choice value must be a constant", whenChoice.position))
|
||||
|
@ -12,7 +12,7 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(module: Module) {
|
||||
module.statements = module.statements.asSequence().map { it.accept(this) }.toMutableList()
|
||||
module.statements = module.statements.map { it.accept(this) }.toMutableList()
|
||||
}
|
||||
|
||||
fun visit(expr: PrefixExpression): Expression {
|
||||
@ -31,18 +31,18 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(block: Block): Statement {
|
||||
block.statements = block.statements.asSequence().map { it.accept(this) }.toMutableList()
|
||||
block.statements = block.statements.map { it.accept(this) }.toMutableList()
|
||||
return block
|
||||
}
|
||||
|
||||
fun visit(decl: VarDecl): Statement {
|
||||
decl.value = decl.value?.accept(this)
|
||||
decl.arraysize = decl.arraysize?.accept(this)
|
||||
decl.arraysize?.accept(this)
|
||||
return decl
|
||||
}
|
||||
|
||||
fun visit(subroutine: Subroutine): Statement {
|
||||
subroutine.statements = subroutine.statements.asSequence().map { it.accept(this) }.toMutableList()
|
||||
subroutine.statements = subroutine.statements.map { it.accept(this) }.toMutableList()
|
||||
return subroutine
|
||||
}
|
||||
|
||||
@ -191,7 +191,7 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(scope: AnonymousScope): Statement {
|
||||
scope.statements = scope.statements.asSequence().map { it.accept(this) }.toMutableList()
|
||||
scope.statements = scope.statements.map { it.accept(this) }.toMutableList()
|
||||
return scope
|
||||
}
|
||||
|
||||
@ -241,12 +241,13 @@ interface IAstModifyingVisitor {
|
||||
}
|
||||
|
||||
fun visit(whenChoice: WhenChoice) {
|
||||
whenChoice.values?.forEach { it.accept(this) }
|
||||
whenChoice.values = whenChoice.values?.map { it.accept(this) }
|
||||
val stmt = whenChoice.statements.accept(this)
|
||||
if(stmt is AnonymousScope)
|
||||
whenChoice.statements = stmt
|
||||
else {
|
||||
whenChoice.statements = AnonymousScope(mutableListOf(stmt), stmt.position)
|
||||
whenChoice.statements.linkParents(whenChoice)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -333,9 +333,10 @@ internal class StatementReorderer(private val program: Program): IAstModifyingVi
|
||||
// make sure all choices are just for one single value
|
||||
val choices = whenStatement.choices.toList()
|
||||
for(choice in choices) {
|
||||
if(choice.values==null || choice.values.size==1)
|
||||
val choiceValues = choice.values
|
||||
if(choiceValues==null || choiceValues.size==1)
|
||||
continue
|
||||
for(v in choice.values) {
|
||||
for(v in choiceValues) {
|
||||
val newchoice=WhenChoice(listOf(v), choice.statements, choice.position)
|
||||
newchoice.parent = choice.parent
|
||||
whenStatement.choices.add(newchoice)
|
||||
|
@ -303,9 +303,8 @@ class ArrayIndex(var index: Expression, override val position: Position) : Node
|
||||
}
|
||||
}
|
||||
|
||||
fun accept(visitor: IAstModifyingVisitor): ArrayIndex {
|
||||
fun accept(visitor: IAstModifyingVisitor) {
|
||||
index = index.accept(visitor)
|
||||
return this
|
||||
}
|
||||
|
||||
fun accept(visitor: IAstVisitor) {
|
||||
@ -750,7 +749,7 @@ class RepeatLoop(var body: AnonymousScope,
|
||||
}
|
||||
|
||||
class WhenStatement(var condition: Expression,
|
||||
val choices: MutableList<WhenChoice>,
|
||||
var choices: MutableList<WhenChoice>,
|
||||
override val position: Position): Statement() {
|
||||
override lateinit var parent: Node
|
||||
override val expensiveToInline: Boolean = true
|
||||
@ -768,7 +767,7 @@ class WhenStatement(var condition: Expression,
|
||||
if(choice.values==null)
|
||||
result.add(null to choice)
|
||||
else {
|
||||
val values = choice.values.map { it.constValue(program)?.number?.toInt() }
|
||||
val values = choice.values!!.map { it.constValue(program)?.number?.toInt() }
|
||||
if(values.contains(null))
|
||||
result.add(null to choice)
|
||||
else
|
||||
@ -782,7 +781,7 @@ class WhenStatement(var condition: Expression,
|
||||
override fun accept(visitor: IAstModifyingVisitor) = visitor.visit(this)
|
||||
}
|
||||
|
||||
class WhenChoice(val values: List<Expression>?, // if null, this is the 'else' part
|
||||
class WhenChoice(var values: List<Expression>?, // if null, this is the 'else' part
|
||||
var statements: AnonymousScope,
|
||||
override val position: Position) : Node {
|
||||
override lateinit var parent: Node
|
||||
|
@ -224,14 +224,16 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||
*/
|
||||
override fun visit(expr: PrefixExpression): Expression {
|
||||
return try {
|
||||
super.visit(expr)
|
||||
val prefixExpr=super.visit(expr)
|
||||
if(prefixExpr !is PrefixExpression)
|
||||
return prefixExpr
|
||||
|
||||
val subexpr = expr.expression
|
||||
val subexpr = prefixExpr.expression
|
||||
if (subexpr is NumericLiteralValue) {
|
||||
// accept prefixed literal values (such as -3, not true)
|
||||
return when {
|
||||
expr.operator == "+" -> subexpr
|
||||
expr.operator == "-" -> when {
|
||||
prefixExpr.operator == "+" -> subexpr
|
||||
prefixExpr.operator == "-" -> when {
|
||||
subexpr.type in IntegerDatatypes -> {
|
||||
optimizationsDone++
|
||||
NumericLiteralValue.optimalNumeric(-subexpr.number.toInt(), subexpr.position)
|
||||
@ -242,21 +244,21 @@ class ConstantFolding(private val program: Program) : IAstModifyingVisitor {
|
||||
}
|
||||
else -> throw ExpressionError("can only take negative of int or float", subexpr.position)
|
||||
}
|
||||
expr.operator == "~" -> when {
|
||||
prefixExpr.operator == "~" -> when {
|
||||
subexpr.type in IntegerDatatypes -> {
|
||||
optimizationsDone++
|
||||
NumericLiteralValue.optimalNumeric(subexpr.number.toInt().inv(), subexpr.position)
|
||||
}
|
||||
else -> throw ExpressionError("can only take bitwise inversion of int", subexpr.position)
|
||||
}
|
||||
expr.operator == "not" -> {
|
||||
prefixExpr.operator == "not" -> {
|
||||
optimizationsDone++
|
||||
NumericLiteralValue.fromBoolean(subexpr.number.toDouble() == 0.0, subexpr.position)
|
||||
}
|
||||
else -> throw ExpressionError(expr.operator, subexpr.position)
|
||||
else -> throw ExpressionError(prefixExpr.operator, subexpr.position)
|
||||
}
|
||||
}
|
||||
return expr
|
||||
return prefixExpr
|
||||
} catch (ax: AstException) {
|
||||
addError(ax)
|
||||
expr
|
||||
|
@ -518,7 +518,7 @@ class AstVm(val program: Program) {
|
||||
executeAnonymousScope(choice.statements)
|
||||
break
|
||||
} else {
|
||||
val value = choice.values.single().constValue(evalCtx.program) ?: throw VmExecutionException("can only use const values in when choices ${choice.position}")
|
||||
val value = choice.values!!.single().constValue(evalCtx.program) ?: throw VmExecutionException("can only use const values in when choices ${choice.position}")
|
||||
val rtval = RuntimeValue.fromLv(value)
|
||||
if(condition==rtval) {
|
||||
executeAnonymousScope(choice.statements)
|
||||
|
@ -6,10 +6,73 @@
|
||||
|
||||
sub start() {
|
||||
uword target = 4444
|
||||
@($d020) = A
|
||||
@($d020) = A+4
|
||||
@(target) = A+4
|
||||
@(target+4) = A+4
|
||||
; @($d020) = A
|
||||
; @($d020) = A+4
|
||||
; @(target) = A+4
|
||||
; @(target+4) = A+4
|
||||
|
||||
whenubyte(20)
|
||||
whenubyte(111)
|
||||
whenbyte(-10)
|
||||
whenbyte(-111)
|
||||
whenbyte(0)
|
||||
|
||||
whenuword(500)
|
||||
whenuword(44)
|
||||
whenword(-3000)
|
||||
whenword(-44)
|
||||
whenword(0)
|
||||
|
||||
sub whenbyte(byte value) {
|
||||
when value {
|
||||
-4 -> c64scr.print("minusfour")
|
||||
-5 -> c64scr.print("minusfive")
|
||||
-10,-20,-30 -> {
|
||||
c64scr.print("minusten or twenty or thirty")
|
||||
}
|
||||
-99 -> c64scr.print("minusninetynine")
|
||||
else -> c64scr.print("don't know")
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub whenubyte(ubyte value) {
|
||||
when value {
|
||||
4 -> c64scr.print("four")
|
||||
5 -> c64scr.print("five")
|
||||
10,20,30 -> {
|
||||
c64scr.print("ten or twenty or thirty")
|
||||
}
|
||||
99 -> c64scr.print("ninetynine")
|
||||
else -> c64scr.print("don't know")
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub whenuword(uword value) {
|
||||
when value {
|
||||
400 -> c64scr.print("four100")
|
||||
500 -> c64scr.print("five100")
|
||||
1000,2000,3000 -> {
|
||||
c64scr.print("thousand 2thousand or 3thousand")
|
||||
}
|
||||
9999 -> c64scr.print("ninetynine99")
|
||||
else -> c64scr.print("don't know")
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
|
||||
sub whenword(word value) {
|
||||
when value {
|
||||
-400 -> c64scr.print("minusfour100")
|
||||
-500 -> c64scr.print("minusfive100")
|
||||
-1000,-2000,-3000 -> {
|
||||
c64scr.print("minusthousand 2thousand or 3thousand")
|
||||
}
|
||||
-9999 -> c64scr.print("minusninetynine99")
|
||||
else -> c64scr.print("don't know")
|
||||
}
|
||||
c64.CHROUT('\n')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user