lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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);