twig.expression.operator.js | |
---|---|
| |
twig.expression.operator.jsThis file handles operator lookups and parsing. | var Twig = (function (Twig) {
"use strict";
/**
* Operator associativity constants.
*/
Twig.expression.operator = {
leftToRight: 'leftToRight',
rightToLeft: 'rightToLeft'
};
/**
* Get the precidence and associativity of an operator. These follow the order that C/C++ use.
* See http://en.wikipedia.org/wiki/Operators_in_C_and_C++ for the table of values.
*/
Twig.expression.operator.lookup = function (operator, token) {
switch (operator) {
case "..":
case 'not in':
case 'in':
token.precidence = 20;
token.associativity = Twig.expression.operator.leftToRight;
break;
case ',':
token.precidence = 18;
token.associativity = Twig.expression.operator.leftToRight;
break; |
Ternary | case '?':
case ':':
token.precidence = 16;
token.associativity = Twig.expression.operator.rightToLeft;
break;
case 'or':
token.precidence = 14;
token.associativity = Twig.expression.operator.leftToRight;
break;
case 'and':
token.precidence = 13;
token.associativity = Twig.expression.operator.leftToRight;
break;
case '==':
case '!=':
token.precidence = 9;
token.associativity = Twig.expression.operator.leftToRight;
break;
case '<':
case '<=':
case '>':
case '>=':
token.precidence = 8;
token.associativity = Twig.expression.operator.leftToRight;
break;
case '~': // String concatination
case '+':
case '-':
token.precidence = 6;
token.associativity = Twig.expression.operator.leftToRight;
break;
case '//':
case '**':
case '*':
case '/':
case '%':
token.precidence = 5;
token.associativity = Twig.expression.operator.leftToRight;
break;
case 'not':
token.precidence = 3;
token.associativity = Twig.expression.operator.rightToLeft;
break;
default:
throw new Twig.Error(operator + " is an unknown operator.");
}
token.operator = operator;
return token;
};
/**
* Handle operations on the RPN stack.
*
* Returns the updated stack.
*/
Twig.expression.operator.parse = function (operator, stack) {
Twig.log.trace("Twig.expression.operator.parse: ", "Handling ", operator);
var a, b, c;
switch (operator) {
case ':': |
Ignore | break;
case '?':
c = stack.pop(); // false expr
b = stack.pop(); // true expr
a = stack.pop(); // conditional
if (a) {
stack.push(b);
} else {
stack.push(c);
}
break;
case '+':
b = parseFloat(stack.pop());
a = parseFloat(stack.pop());
stack.push(a + b);
break;
case '-':
b = parseFloat(stack.pop());
a = parseFloat(stack.pop());
stack.push(a - b);
break;
case '*':
b = parseFloat(stack.pop());
a = parseFloat(stack.pop());
stack.push(a * b);
break;
case '/':
b = parseFloat(stack.pop());
a = parseFloat(stack.pop());
stack.push(a / b);
break;
case '//':
b = parseFloat(stack.pop());
a = parseFloat(stack.pop());
stack.push(parseInt(a / b));
break;
case '%':
b = parseFloat(stack.pop());
a = parseFloat(stack.pop());
stack.push(a % b);
break;
case '~':
b = stack.pop();
a = stack.pop();
stack.push( (a !== undefined ? a.toString() : "")
+ (b !== undefined ? b.toString() : "") );
break;
case 'not':
case '!':
stack.push(!stack.pop());
break;
case '<':
b = stack.pop();
a = stack.pop();
stack.push(a < b);
break;
case '<=':
b = stack.pop();
a = stack.pop();
stack.push(a <= b);
break;
case '>':
b = stack.pop();
a = stack.pop();
stack.push(a > b);
break;
case '>=':
b = stack.pop();
a = stack.pop();
stack.push(a >= b);
break;
case '===':
b = stack.pop();
a = stack.pop();
stack.push(a === b);
break;
case '==':
b = stack.pop();
a = stack.pop();
stack.push(a == b);
break;
case '!==':
b = stack.pop();
a = stack.pop();
stack.push(a !== b);
break;
case '!=':
b = stack.pop();
a = stack.pop();
stack.push(a != b);
break;
case 'or':
b = stack.pop();
a = stack.pop();
stack.push(a || b);
break;
case 'and':
b = stack.pop();
a = stack.pop();
stack.push(a && b);
break;
case '**':
b = stack.pop();
a = stack.pop();
stack.push(Math.pow(a, b));
break;
case 'not in':
b = stack.pop();
a = stack.pop();
stack.push( !containment(a, b) );
break;
case 'in':
b = stack.pop();
a = stack.pop();
stack.push( containment(a, b) );
break;
case '..':
b = stack.pop();
a = stack.pop();
stack.push( Twig.functions.range(a, b) );
break;
default:
throw new Twig.Error(operator + " is an unknown operator.");
}
};
var containment = function(a, b) {
if (b.indexOf != undefined) {
return b.indexOf(a) > -1;
} else {
var el;
for (el in b) {
if (b.hasOwnProperty(el) && b[el] === a) {
return true;
}
}
return false;
}
}
return Twig;
})( Twig || { } );
|