1. masklinn
  2. py.js

Commits

masklinn  committed b32e532

Implement chained comparators (also unary negative)

  • Participants
  • Parent commits b09ccd0
  • Branches default
  • Tags 0.1

Comments (0)

Files changed (2)

File lib/py.js

View file
         next = function () { return toks[++index]; };
         return expression();
     };
+    evaluate_operator = function (operator, a, b) {
+        switch (operator) {
+        case '==': case 'is': return a === b;
+        case '!=': case 'is not': return a !== b;
+        case '<': return a < b;
+        case '<=': return a <= b;
+        case '>': return a > b;
+        case '>=': return a >= b;
+        case 'in': return b.__contains__(a);
+        case 'not in': return !b.__contains__(a);
+        }
+        throw new Error('SyntaxError: unknown comparator [[' + operator + ']]');
+    }
     exports.evaluate = function (expr, context) {
         switch (expr.id) {
         case '(name)':
         case '(string)':
         case '(number)':
             return expr.value;
-        case '==':
-            return (exports.evaluate(expr.first, context)
-                    ===
-                    exports.evaluate(expr.second, context));
-        case '!=':
-            return (exports.evaluate(expr.first, context)
-                    !==
-                    exports.evaluate(expr.second, context));
-        case '<':
-            return (exports.evaluate(expr.first, context)
-                    <
-                    exports.evaluate(expr.second, context));
-        case '<=':
-            return (exports.evaluate(expr.first, context)
-                    <=
-                    exports.evaluate(expr.second, context));
-        case '>':
-            return (exports.evaluate(expr.first, context)
-                    >
-                    exports.evaluate(expr.second, context));
-        case '>=':
-            return (exports.evaluate(expr.first, context)
-                    >=
-                    exports.evaluate(expr.second, context));
+        case '(comparator)':
+            var result, left = exports.evaluate(expr.expressions[0], context);
+            for(var i=0; i<expr.operators.length; ++i) {
+                result = evaluate_operator(
+                    expr.operators[i],
+                    left,
+                    left = exports.evaluate(expr.expressions[i+1], context));
+                if (!result) { return false; }
+            }
+            return true;
+        case '-':
+            if (this.second) {
+                throw new Error('SyntaxError: binary [-] not implemented yet');
+            }
+            return -(exports.evaluate(expr.first, context));
         case 'and':
             return (exports.evaluate(expr.first, context)
                     && exports.evaluate(expr.second, context));
         case 'or':
             return (exports.evaluate(expr.first, context)
                     || exports.evaluate(expr.second, context));
-        case 'in':
-            return exports.evaluate(expr.second, context).__contains__(
-                exports.evaluate(expr.first, context));
-        case 'not in':
-            return !exports.evaluate(expr.second, context).__contains__(
-                exports.evaluate(expr.first, context));
         case '(':
             if (this.second) {
                 throw new Error('SyntaxError: functions not implemented yet');

File test/test.js

View file
 assert.ok(py.eval('5 >= 3'));
 assert.ok(py.eval('3 >= 3'));
 assert.ok(!py.eval('5 < 3'));
-// TODO: string comparisons, custom types
+assert.ok(py.eval('1 < 3 < 5'));
+assert.ok(py.eval('5 > 3 > 1'));
+assert.ok(py.eval('1 < 3 > 2 == 2 > -2 not in (0, 1, 2)'));
 
 // Boolean operators
 assert.ok(py.eval(