@firehammer/jexl
Version:
Javascript Expression Language: Powerful context-based expression parser and evaluator
221 lines (218 loc) • 5.76 kB
JavaScript
;
/*
* Jexl
* Copyright 2020 Tom Shawver
*/
/* eslint eqeqeq:0 */
exports.getGrammar = function () {
return {
/**
* A map of all expression elements to their properties. Note that changes
* here may require changes in the Lexer or Parser.
* @type {{}}
*/
elements: {
".": {
type: "dot"
},
"[": {
type: "openBracket"
},
"]": {
type: "closeBracket"
},
"|": {
type: "pipe"
},
"{": {
type: "openCurl"
},
"}": {
type: "closeCurl"
},
":": {
type: "colon"
},
",": {
type: "comma"
},
"(": {
type: "openParen"
},
")": {
type: "closeParen"
},
"?": {
type: "question"
},
"+": {
type: "binaryOp",
precedence: 30,
eval: function _eval(left, right) {
return left + right;
}
},
"-": {
type: "binaryOp",
precedence: 30,
eval: function _eval(left, right) {
return left - right;
}
},
"*": {
type: "binaryOp",
precedence: 40,
eval: function _eval(left, right) {
return left * right;
}
},
"/": {
type: "binaryOp",
precedence: 40,
eval: function _eval(left, right) {
return left / right;
}
},
"//": {
type: "binaryOp",
precedence: 40,
eval: function _eval(left, right) {
return Math.floor(left / right);
}
},
"%": {
type: "binaryOp",
precedence: 50,
eval: function _eval(left, right) {
return left % right;
}
},
"^": {
type: "binaryOp",
precedence: 50,
eval: function _eval(left, right) {
return Math.pow(left, right);
}
},
"==": {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
return left == right;
}
},
"!=": {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
return left != right;
}
},
">": {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
return left > right;
}
},
">=": {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
return left >= right;
}
},
"<": {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
return left < right;
}
},
"<=": {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
return left <= right;
}
},
"&&": {
type: "binaryOp",
precedence: 10,
evalOnDemand: function evalOnDemand(left, right) {
return left.eval().then(function (leftVal) {
if (!leftVal) return leftVal;
return right.eval();
});
}
},
"||": {
type: "binaryOp",
precedence: 10,
evalOnDemand: function evalOnDemand(left, right) {
return left.eval().then(function (leftVal) {
if (leftVal) return leftVal;
return right.eval();
});
}
},
in: {
type: "binaryOp",
precedence: 20,
eval: function _eval(left, right) {
if (typeof right === "string") {
return right.indexOf(left) !== -1;
}
if (Array.isArray(right)) {
return right.some(function (elem) {
return elem === left;
});
}
return false;
}
},
"!": {
type: "unaryOp",
precedence: Infinity,
eval: function _eval(right) {
return !right;
}
}
},
/**
* A map of function names to javascript functions. A Jexl function
* takes zero ore more arguemnts:
*
* - {*} ...args: A variable number of arguments passed to this function.
* All of these are pre-evaluated to their actual values before calling
* the function.
*
* The Jexl function should return either the transformed value, or
* a Promises/A+ Promise object that resolves with the value and rejects
* or throws only when an unrecoverable error occurs. Functions should
* generally return undefined when they don't make sense to be used on the
* given value type, rather than throw/reject. An error is only
* appropriate when the function would normally return a value, but
* cannot due to some other failure.
*/
functions: {},
/**
* A map of transform names to transform functions. A transform function
* takes one ore more arguemnts:
*
* - {*} val: A value to be transformed
* - {*} ...args: A variable number of arguments passed to this transform.
* All of these are pre-evaluated to their actual values before calling
* the function.
*
* The transform function should return either the transformed value, or
* a Promises/A+ Promise object that resolves with the value and rejects
* or throws only when an unrecoverable error occurs. Transforms should
* generally return undefined when they don't make sense to be used on the
* given value type, rather than throw/reject. An error is only
* appropriate when the transform would normally return a value, but
* cannot due to some other failure.
*/
transforms: {}
};
};