mirror of
https://github.com/irmen/prog8.git
synced 2025-01-18 13:34:02 +00:00
allow chained comparisons i<x<j (desugared into: i<x and x<j)
This commit is contained in:
parent
2b8f613a00
commit
dfce292294
@ -171,6 +171,30 @@ 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.)
|
||||
|
@ -423,7 +423,7 @@ private fun IntegerliteralContext.toAst(): NumericLiteralNode {
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExpressionContext.toAst() : Expression {
|
||||
private fun ExpressionContext.toAst(insideParentheses: Boolean=false) : Expression {
|
||||
|
||||
val litval = literalvalue()
|
||||
if(litval!=null) {
|
||||
@ -468,7 +468,7 @@ private fun ExpressionContext.toAst() : Expression {
|
||||
return scoped_identifier().toAst()
|
||||
|
||||
if(bop!=null)
|
||||
return BinaryExpression(left.toAst(), bop.text.trim(), right.toAst(), toPosition())
|
||||
return BinaryExpression(left.toAst(), bop.text.trim(), right.toAst(), toPosition(), insideParentheses=insideParentheses)
|
||||
|
||||
if(prefix!=null)
|
||||
return PrefixExpression(prefix.text, expression(0).toAst(), toPosition())
|
||||
@ -483,7 +483,7 @@ private fun ExpressionContext.toAst() : Expression {
|
||||
}
|
||||
|
||||
if(childCount==3 && children[0].text=="(" && children[2].text==")")
|
||||
return expression(0).toAst() // expression within ( )
|
||||
return expression(0).toAst(insideParentheses=true) // expression within ( )
|
||||
|
||||
if(typecast()!=null)
|
||||
return TypecastExpression(expression(0).toAst(), typecast().datatype().toAst(), false, toPosition())
|
||||
|
@ -148,7 +148,13 @@ class PrefixExpression(val operator: String, var expression: Expression, overrid
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryExpression(var left: Expression, var operator: String, var right: Expression, override val position: Position) : Expression() {
|
||||
class BinaryExpression(
|
||||
var left: Expression,
|
||||
var operator: String,
|
||||
var right: Expression,
|
||||
override val position: Position,
|
||||
val insideParentheses: Boolean = false // used in very few places to check priorities
|
||||
) : Expression() {
|
||||
override lateinit var parent: Node
|
||||
|
||||
override fun linkParents(parent: Node) {
|
||||
|
@ -579,9 +579,10 @@ postfix increment and decrement: ``++`` ``--``
|
||||
Syntactic sugar; ``aa++`` is equivalent to ``aa = aa + 1``, and ``aa--`` is equivalent to ``aa = aa - 1``.
|
||||
Because these operations are so common, we have these short forms.
|
||||
|
||||
comparison: ``!=`` ``<`` ``>`` ``<=`` ``>=``
|
||||
comparison: ``==`` ``!=`` ``<`` ``>`` ``<=`` ``>=``
|
||||
Equality, Inequality, Less-than, Greater-than, Less-or-Equal-than, Greater-or-Equal-than comparisons.
|
||||
The result is a 'boolean' value 'true' or 'false' (which in reality is just a byte value of 1 or 0).
|
||||
The result is a boolean value 'true' or 'false' (1 or 0).
|
||||
Note that you can chain comparisons like so: ``i < x < j``, which is the same as ``i<x and x<j``.
|
||||
|
||||
logical: ``not`` ``and`` ``or`` ``xor``
|
||||
These operators are the usual logical operations that are part of a logical expression to reason
|
||||
|
@ -83,4 +83,3 @@ Other language/syntax features to think about
|
||||
- add (rom/ram)bank support to romsub. A call will then automatically switch banks, use callfar and something else when in banked ram.
|
||||
challenges: how to not make this too X16 specific? How does the compiler know what bank to switch (ram/rom)?
|
||||
How to make it performant when we want to (i.e. NOT have it use callfar/auto bank switching) ?
|
||||
- chained comparisons `10<x<20` , `x==y==z` (desugars to `10<x and x<20`, `x==y and y==z`) BUT this changes the semantics of what it is right now ! (x==(y==z) --> x==true)
|
||||
|
@ -3,19 +3,15 @@
|
||||
|
||||
main {
|
||||
sub start() {
|
||||
cx16.r0++
|
||||
str[] names = ["irmen", "de", "jong"]
|
||||
uword zz = names[1]
|
||||
txt.print(names[1])
|
||||
}
|
||||
|
||||
sub derp() {
|
||||
cx16.r0++
|
||||
}
|
||||
|
||||
asmsub hurrah() {
|
||||
%ir {{
|
||||
nop
|
||||
}}
|
||||
ubyte x = 10
|
||||
ubyte y = 2
|
||||
txt.print_ub(5<x and x<=20)
|
||||
txt.nl()
|
||||
txt.print_ub(5<x and x<=9)
|
||||
txt.nl()
|
||||
txt.print_ub(5<x<=9)
|
||||
txt.nl()
|
||||
txt.print_ub(5<(x-y)<=9<y)
|
||||
txt.nl()
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user