tweak chained comparisons

This commit is contained in:
Irmen de Jong 2023-12-28 02:31:39 +01:00
parent dfce292294
commit b428343c2a
4 changed files with 30 additions and 30 deletions

View File

@ -96,10 +96,11 @@ internal fun Program.addTypecasts(errors: IErrorReporter, options: CompilationOp
caster.applyModifications()
}
fun Program.desugaring(errors: IErrorReporter): Int {
fun Program.desugaring(errors: IErrorReporter) {
val desugar = CodeDesugarer(this, errors)
desugar.visit(this)
return desugar.applyModifications()
while(errors.noErrors() && desugar.applyModifications()>0)
desugar.visit(this)
}
internal fun Program.verifyFunctionArgTypes(errors: IErrorReporter) {
@ -110,9 +111,8 @@ internal fun Program.verifyFunctionArgTypes(errors: IErrorReporter) {
internal fun Program.preprocessAst(errors: IErrorReporter, options: CompilationOptions) {
val transforms = AstPreprocessor(this, errors, options)
transforms.visit(this)
var mods = transforms.applyModifications()
while(mods>0)
mods = transforms.applyModifications()
while(errors.noErrors() && transforms.applyModifications()>0)
transforms.visit(this)
}
internal fun Program.checkIdentifiers(errors: IErrorReporter, options: CompilationOptions) {

View File

@ -26,6 +26,7 @@ internal class CodeDesugarer(val program: Program, private val errors: IErrorRep
// - pointer[word] replaced by @(pointer+word)
// - @(&var) and @(&var+1) replaced by lsb(var) and msb(var) if var is a word
// - flatten chained assignments
// - rewrite chained comparisons like i<x<j into i<x and x<j
override fun before(breakStmt: Break, parent: Node): Iterable<IAstModification> {
fun jumpAfter(stmt: Statement): Iterable<IAstModification> {
@ -259,6 +260,29 @@ _after:
return listOf(IAstModification.ReplaceNode(expr, squareCall, parent))
}
// desugar chained comparisons: i < x < j ---> i<x and x<j
// only if i<x or x<j was not written in parentheses! (i<x) < y, i < (x<y) -> leave untouched
if(expr.operator in ComparisonOperators) {
val leftBinExpr = expr.left as? BinaryExpression
val rightBinExpr = expr.right as? BinaryExpression
if(leftBinExpr!=null && !leftBinExpr.insideParentheses && leftBinExpr.operator in ComparisonOperators) {
if(!leftBinExpr.right.isSimple) {
errors.warn("possible multiple evaluation of subexpression in chained comparison, consider using a temporary variable", leftBinExpr.right.position)
}
val right = BinaryExpression(leftBinExpr.right.copy(), expr.operator, expr.right, leftBinExpr.right.position)
val desugar = BinaryExpression(leftBinExpr, "and", right, expr.position)
return listOf(IAstModification.ReplaceNode(expr, desugar, parent))
}
else if(rightBinExpr!=null && !rightBinExpr.insideParentheses && rightBinExpr.operator in ComparisonOperators) {
if(!rightBinExpr.left.isSimple) {
errors.warn("possible multiple evaluation of subexpression in chained comparison, consider using a temporary variable", rightBinExpr.left.position)
}
val left = BinaryExpression(expr.left, expr.operator, rightBinExpr.left.copy(), rightBinExpr.left.position)
val desugar = BinaryExpression(left, "and", rightBinExpr, expr.position)
return listOf(IAstModification.ReplaceNode(expr, desugar, parent))
}
}
return noModifications
}

View File

@ -171,30 +171,6 @@ internal class StatementReorderer(
}
override fun after(expr: BinaryExpression, parent: Node): Iterable<IAstModification> {
// desugar chained comparisons: i < x < j ---> i<x and x<j
// only if i<x or x<j was not written in parentheses! (i<x) < y, i < (x<y) -> leave untouched
if(expr.operator in ComparisonOperators) {
val leftBinExpr = expr.left as? BinaryExpression
val rightBinExpr = expr.right as? BinaryExpression
if(leftBinExpr!=null && !leftBinExpr.insideParentheses && leftBinExpr.operator in ComparisonOperators) {
if(!leftBinExpr.right.isSimple) {
errors.warn("possible multiple evaluation of subexpression in chained comparison, consider using a temporary variable", leftBinExpr.right.position)
}
val right = BinaryExpression(leftBinExpr.right.copy(), expr.operator, expr.right, leftBinExpr.right.position)
val desugar = BinaryExpression(leftBinExpr, "and", right, expr.position)
return listOf(IAstModification.ReplaceNode(expr, desugar, parent))
}
else if(rightBinExpr!=null && !rightBinExpr.insideParentheses && rightBinExpr.operator in ComparisonOperators) {
if(!rightBinExpr.left.isSimple) {
errors.warn("possible multiple evaluation of subexpression in chained comparison, consider using a temporary variable", rightBinExpr.left.position)
}
val left = BinaryExpression(expr.left, expr.operator, rightBinExpr.left.copy(), rightBinExpr.left.position)
val desugar = BinaryExpression(left, "and", rightBinExpr, expr.position)
return listOf(IAstModification.ReplaceNode(expr, desugar, parent))
}
}
// ConstValue <associativeoperator> X --> X <associativeoperator> ConstValue
// (this should be done by the ExpressionSimplifier when optimizing is enabled,
// but the current assembly code generator for IF statements now also depends on it, so we do it here regardless of optimization.)

View File

@ -173,7 +173,7 @@ class BinaryExpression(
replacement.parent = this
}
override fun copy() = BinaryExpression(left.copy(), operator, right.copy(), position)
override fun copy() = BinaryExpression(left.copy(), operator, right.copy(), position, insideParentheses)
override fun toString() = "[$left $operator $right]"
override val isSimple = false