jexl
Version:
Javascript Expression Language: Powerful context-based expression parser and evaluator
224 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: {}
};
};