[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: chained relational operators
- From: Tony Finch <dot@...>
- Date: Thu, 16 Dec 2010 21:21:16 +0000
I quite like chained comparison operators, as featured in languages like
BCPL and Python -- and, if you want, Lua:
$ echo '
a = 0
function f()
a = a + 1
print(a)
return a
end
if f() < f() <= f() <> f() == f() > f() or f() == 6 <> f()
then print "yes"
else print "no"
end
' | ./lua
1
2
3
4
5
6
7
yes
Note that each sub-expression is evaluated once, and a chain of relational
operators is joined by implicit and operators.
A patch to implement this can be found below my .sig. I *think* I got the
register allocation right :-) It's slightly dodgy because I make a copy of
the inner argument of two chained relational operators after the code
generator thinks it has been freed - v2 is freed by luaK_posfix() then
brought back to life as v1 by luaK_resurrect().
Tony.
--
f.anthony.n.finch <dot@dotat.at> http://dotat.at/
HUMBER THAMES DOVER WIGHT PORTLAND: NORTH BACKING WEST OR NORTHWEST, 5 TO 7,
DECREASING 4 OR 5, OCCASIONALLY 6 LATER IN HUMBER AND THAMES. MODERATE OR
ROUGH. RAIN THEN FAIR. GOOD.
diff --git a/src/lcode.c b/src/lcode.c
index ea3217f..0b42507 100644
--- a/src/lcode.c
+++ b/src/lcode.c
@@ -492,6 +492,13 @@ int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
}
+void luaK_resurrect (FuncState *fs, expdesc *e1, expdesc *e2) {
+ *e1 = *e2;
+ luaK_reserveregs(fs, 1);
+ exp2reg(fs, e1, fs->freereg - 1);
+}
+
+
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
if (e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
diff --git a/src/lparser.c b/src/lparser.c
index f7e4c77..923eafc 100644
--- a/src/lparser.c
+++ b/src/lparser.c
@@ -964,6 +964,7 @@ static const struct {
};
#define UNARY_PRIORITY 8 /* priority for unary operators */
+#define RELATE_PRIORITY 3 /* priority for relational operators */
/*
@@ -1002,6 +1003,19 @@ static BinOpr subexpr (LexState *ls, expdesc *v, unsigned int limit) {
/* read sub-expression with higher priority */
nextop = subexpr(ls, &v2, priority[op].right);
luaK_posfix(ls->fs, op, v, &v2, line);
+ /* chained relational operators */
+ while (priority[nextop].left == RELATE_PRIORITY
+ && priority[op].left == RELATE_PRIORITY) {
+ expdesc v1;
+ op = nextop;
+ line = ls->linenumber;
+ luaX_next(ls);
+ luaK_infix(ls->fs, OPR_AND, v);
+ luaK_resurrect(ls->fs, &v1, &v2);
+ nextop = subexpr(ls, &v2, priority[op].right);
+ luaK_posfix(ls->fs, op, &v1, &v2, line);
+ luaK_posfix(ls->fs, OPR_AND, v, &v1, line);
+ }
op = nextop;
}
leavelevel(ls);