@pru-rt/spel2js
Version:
Parse Spring Expression Language in JavaScript
1,423 lines (1,198 loc) • 135 kB
JavaScript
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.spel2js = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Ben March
* @since 0.2.0
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _SpelExpressionParser = require('../src/SpelExpressionParser');
var _libStack = require('../src/lib/Stack');
var spelExpressionEvaluator = {};
function evalCompiled(compiledExpression, context, locals) {
var activeContext = new _libStack.Stack(),
state;
if (!context) {
context = {};
}
activeContext.push(context);
state = {
rootContext: context,
activeContext: activeContext,
locals: locals
};
return compiledExpression.getValue(state);
}
spelExpressionEvaluator.compile = function (expression) {
var compiledExpression = (0, _SpelExpressionParser.SpelExpressionParser)().parse(expression);
return {
eval: function _eval(context, locals) {
return evalCompiled(compiledExpression, context, locals);
},
_compiledExpression: compiledExpression
};
};
spelExpressionEvaluator.eval = function (expression, context, locals) {
return spelExpressionEvaluator.compile(expression).eval(context, locals);
};
exports.SpelExpressionEvaluator = spelExpressionEvaluator;
},{"./SpelExpressionParser":2,"./lib/Stack":42}],2:[function(require,module,exports){
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Andy Clement
* @author Juergen Hoeller
* @author Ben March
* @since 0.2.0
*
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _TokenKind = require('../src/TokenKind');
var _Tokenizer = require('../src//Tokenizer');
var _astBooleanLiteral = require('../src//ast/BooleanLiteral');
var _astNumberLiteral = require('../src//ast/NumberLiteral');
var _astStringLiteral = require('../src//ast/StringLiteral');
var _astNullLiteral = require('../src//ast/NullLiteral');
var _astFunctionReference = require('../src//ast/FunctionReference');
var _astMethodReference = require('../src//ast/MethodReference');
var _astPropertyReference = require('../src//ast/PropertyReference');
var _astVariableReference = require('../src//ast/VariableReference');
var _astCompoundExpression = require('../src//ast/CompoundExpression');
var _astIndexer = require('../src//ast/Indexer');
var _astAssign = require('../src//ast/Assign');
var _astOpEQ = require('../src//ast/OpEQ');
var _astOpNE = require('../src/ast/OpNE');
var _astOpGE = require('../src/ast/OpGE');
var _astOpGT = require('../src/ast/OpGT');
var _astOpLE = require('../src//ast/OpLE');
var _astOpLT = require('../src//ast/OpLT');
var _astOpPlus = require('../src//ast/OpPlus');
var _astOpMinus = require('../src//ast/OpMinus');
var _astOpMultiply = require('../src//ast/OpMultiply');
var _astOpDivide = require('../src//ast/OpDivide');
var _astOpModulus = require('../src//ast/OpModulus');
var _astOpPower = require('../src//ast/OpPower');
var _astOpInc = require('../src//ast/OpInc');
var _astOpDec = require('../src//ast/OpDec');
var _astOpNot = require('../src//ast/OpNot');
var _astOpAnd = require('../src//ast/OpAnd');
var _astOpOr = require('../src//ast/OpOr');
var _astTernary = require('../src//ast/Ternary');
var _astElvis = require('../src//ast/Elvis');
var _astInlineList = require('../src//ast/InlineList');
var _astInlineMap = require('../src//ast/InlineMap');
var _astSelection = require('../src//ast/Selection');
var _astProjection = require('../src//ast/Projection');
//not yet implemented
var OperatorInstanceof, OperatorMatches, OperatorBetween, BeanReference, TypeReference, QualifiedIdentifier, Identifier, ConstructorReference;
var SpelExpressionParser = function SpelExpressionParser() {
var VALID_QUALIFIED_ID_PATTERN = new RegExp('[\\p{L}\\p{N}_$]+');
var configuration;
// For rules that build nodes, they are stacked here for return
var constructedNodes = [];
// The expression being parsed
var expressionString;
// The token stream constructed from that expression string
var tokenStream;
// length of a populated token stream
var tokenStreamLength;
// Current location in the token stream when processing tokens
var tokenStreamPointer;
/**
* Create a parser with some configured behavior.
* @param config custom configuration options
*/
function setConfiguration(config) {
configuration = config;
}
function parse(expression, context) {
try {
expressionString = expression;
tokenStream = _Tokenizer.Tokenizer.tokenize(expression);
tokenStreamLength = tokenStream.length;
tokenStreamPointer = 0;
constructedNodes = [];
var ast = eatExpression();
if (moreTokens()) {
raiseInternalException(peekToken().startPos, 'MORE_INPUT', nextToken().toString());
}
//Assert.isTrue(this.constructedNodes.isEmpty());
return ast;
} catch (e) {
throw e.message;
}
}
// expression
// : logicalOrExpression
// ( (ASSIGN^ logicalOrExpression)
// | (DEFAULT^ logicalOrExpression)
// | (QMARK^ expression COLON! expression)
// | (ELVIS^ expression))?;
function eatExpression() {
var expr = eatLogicalOrExpression();
if (moreTokens()) {
var token = peekToken();
if (token.getKind() === _TokenKind.TokenKind.ASSIGN) {
// a=b
if (expr === null) {
expr = _astNullLiteral.NullLiteral.create(toPosBounds(token.startPos - 1, token.endPos - 1));
}
nextToken();
var assignedValue = eatLogicalOrExpression();
return _astAssign.Assign.create(toPosToken(token), expr, assignedValue);
}
if (token.getKind() === _TokenKind.TokenKind.ELVIS) {
// a?:b (a if it isn't null, otherwise b)
if (expr === null) {
expr = _astNullLiteral.NullLiteral.create(toPosBounds(token.startPos - 1, token.endPos - 2));
}
nextToken(); // elvis has left the building
var valueIfNull = eatExpression();
if (valueIfNull === null) {
valueIfNull = _astNullLiteral.NullLiteral.create(toPosBounds(token.startPos + 1, token.endPos + 1));
}
return _astElvis.Elvis.create(toPosToken(token), expr, valueIfNull);
}
if (token.getKind() === _TokenKind.TokenKind.QMARK) {
// a?b:c
if (expr === null) {
expr = _astNullLiteral.NullLiteral.create(toPosBounds(token.startPos - 1, token.endPos - 1));
}
nextToken();
var ifTrueExprValue = eatExpression();
eatToken(_TokenKind.TokenKind.COLON);
var ifFalseExprValue = eatExpression();
return _astTernary.Ternary.create(toPosToken(token), expr, ifTrueExprValue, ifFalseExprValue);
}
}
return expr;
}
//logicalOrExpression : logicalAndExpression (OR^ logicalAndExpression)*;
function eatLogicalOrExpression() {
var expr = eatLogicalAndExpression();
while (peekIdentifierToken('or') || peekTokenOne(_TokenKind.TokenKind.SYMBOLIC_OR)) {
var token = nextToken(); //consume OR
var rhExpr = eatLogicalAndExpression();
checkOperands(token, expr, rhExpr);
expr = _astOpOr.OpOr.create(toPosToken(token), expr, rhExpr);
}
return expr;
}
// logicalAndExpression : relationalExpression (AND^ relationalExpression)*;
function eatLogicalAndExpression() {
var expr = eatRelationalExpression();
while (peekIdentifierToken('and') || peekTokenOne(_TokenKind.TokenKind.SYMBOLIC_AND)) {
var token = nextToken(); // consume 'AND'
var rhExpr = eatRelationalExpression();
checkOperands(token, expr, rhExpr);
expr = _astOpAnd.OpAnd.create(toPosToken(token), expr, rhExpr);
}
return expr;
}
// relationalExpression : sumExpression (relationalOperator^ sumExpression)?;
function eatRelationalExpression() {
var expr = eatSumExpression();
var relationalOperatorToken = maybeEatRelationalOperator();
if (relationalOperatorToken !== null) {
var token = nextToken(); // consume relational operator token
var rhExpr = eatSumExpression();
checkOperands(token, expr, rhExpr);
var tk = relationalOperatorToken.kind;
if (relationalOperatorToken.isNumericRelationalOperator()) {
var pos = toPosToken(token);
if (tk === _TokenKind.TokenKind.GT) {
return _astOpGT.OpGT.create(pos, expr, rhExpr);
}
if (tk === _TokenKind.TokenKind.LT) {
return _astOpLT.OpLT.create(pos, expr, rhExpr);
}
if (tk === _TokenKind.TokenKind.LE) {
return _astOpLE.OpLE.create(pos, expr, rhExpr);
}
if (tk === _TokenKind.TokenKind.GE) {
return _astOpGE.OpGE.create(pos, expr, rhExpr);
}
if (tk === _TokenKind.TokenKind.EQ) {
return _astOpEQ.OpEQ.create(pos, expr, rhExpr);
}
//Assert.isTrue(tk === TokenKind.NE);
return _astOpNE.OpNE.create(pos, expr, rhExpr);
}
if (tk === _TokenKind.TokenKind.INSTANCEOF) {
return new OperatorInstanceof(toPosToken(token), expr, rhExpr);
}
if (tk === _TokenKind.TokenKind.MATCHES) {
return new OperatorMatches(toPosToken(token), expr, rhExpr);
}
//Assert.isTrue(tk === TokenKind.BETWEEN);
return new OperatorBetween(toPosToken(token), expr, rhExpr);
}
return expr;
}
//sumExpression: productExpression ( (PLUS^ | MINUS^) productExpression)*;
function eatSumExpression() {
var expr = eatProductExpression();
while (peekTokenAny(_TokenKind.TokenKind.PLUS, _TokenKind.TokenKind.MINUS, _TokenKind.TokenKind.INC)) {
var token = nextToken(); //consume PLUS or MINUS or INC
var rhExpr = eatProductExpression();
checkRightOperand(token, rhExpr);
if (token.getKind() === _TokenKind.TokenKind.PLUS) {
expr = _astOpPlus.OpPlus.create(toPosToken(token), expr, rhExpr);
} else if (token.getKind() === _TokenKind.TokenKind.MINUS) {
expr = _astOpMinus.OpMinus.create(toPosToken(token), expr, rhExpr);
}
}
return expr;
}
// productExpression: powerExpr ((STAR^ | DIV^| MOD^) powerExpr)* ;
function eatProductExpression() {
var expr = eatPowerIncDecExpression();
while (peekTokenAny(_TokenKind.TokenKind.STAR, _TokenKind.TokenKind.DIV, _TokenKind.TokenKind.MOD)) {
var token = nextToken(); // consume STAR/DIV/MOD
var rhExpr = eatPowerIncDecExpression();
checkOperands(token, expr, rhExpr);
if (token.getKind() === _TokenKind.TokenKind.STAR) {
expr = _astOpMultiply.OpMultiply.create(toPosToken(token), expr, rhExpr);
} else if (token.getKind() === _TokenKind.TokenKind.DIV) {
expr = _astOpDivide.OpDivide.create(toPosToken(token), expr, rhExpr);
} else {
//Assert.isTrue(token.getKind() === TokenKind.MOD);
expr = _astOpModulus.OpModulus.create(toPosToken(token), expr, rhExpr);
}
}
return expr;
}
// powerExpr : unaryExpression (POWER^ unaryExpression)? (INC || DEC) ;
function eatPowerIncDecExpression() {
var expr = eatUnaryExpression(),
token;
if (peekTokenOne(_TokenKind.TokenKind.POWER)) {
token = nextToken(); //consume POWER
var rhExpr = eatUnaryExpression();
checkRightOperand(token, rhExpr);
return _astOpPower.OpPower.create(toPosToken(token), expr, rhExpr);
}
if (expr !== null && peekTokenAny(_TokenKind.TokenKind.INC, _TokenKind.TokenKind.DEC)) {
token = nextToken(); //consume INC/DEC
if (token.getKind() === _TokenKind.TokenKind.INC) {
return _astOpInc.OpInc.create(toPosToken(token), true, expr);
}
return _astOpDec.OpDec.create(toPosToken(token), true, expr);
}
return expr;
}
// unaryExpression: (PLUS^ | MINUS^ | BANG^ | INC^ | DEC^) unaryExpression | primaryExpression ;
function eatUnaryExpression() {
var token, expr;
if (peekTokenAny(_TokenKind.TokenKind.PLUS, _TokenKind.TokenKind.MINUS, _TokenKind.TokenKind.NOT)) {
token = nextToken();
expr = eatUnaryExpression();
if (token.getKind() === _TokenKind.TokenKind.NOT) {
return _astOpNot.OpNot.create(toPosToken(token), expr);
}
if (token.getKind() === _TokenKind.TokenKind.PLUS) {
return _astOpPlus.OpPlus.create(toPosToken(token), expr);
}
//Assert.isTrue(token.getKind() === TokenKind.MINUS);
return _astOpMinus.OpMinus.create(toPosToken(token), expr);
}
if (peekTokenAny(_TokenKind.TokenKind.INC, _TokenKind.TokenKind.DEC)) {
token = nextToken();
expr = eatUnaryExpression();
if (token.getKind() === _TokenKind.TokenKind.INC) {
return _astOpInc.OpInc.create(toPosToken(token), false, expr);
}
return _astOpDec.OpDec.create(toPosToken(token), false, expr);
}
return eatPrimaryExpression();
}
// primaryExpression : startNode (node)? -> ^(EXPRESSION startNode (node)?);
function eatPrimaryExpression() {
var nodes = [];
var start = eatStartNode(); // always a start node
nodes.push(start);
while (maybeEatNode()) {
nodes.push(pop());
}
if (nodes.length === 1) {
return nodes[0];
}
return _astCompoundExpression.CompoundExpression.create(toPosBounds(start.getStartPosition(), nodes[nodes.length - 1].getEndPosition()), nodes);
}
// node : ((DOT dottedNode) | (SAFE_NAVI dottedNode) | nonDottedNode)+;
function maybeEatNode() {
var expr = null;
if (peekTokenAny(_TokenKind.TokenKind.DOT, _TokenKind.TokenKind.SAFE_NAVI)) {
expr = eatDottedNode();
} else {
expr = maybeEatNonDottedNode();
}
if (expr === null) {
return false;
} else {
push(expr);
return true;
}
}
// nonDottedNode: indexer;
function maybeEatNonDottedNode() {
if (peekTokenOne(_TokenKind.TokenKind.LSQUARE)) {
if (maybeEatIndexer()) {
return pop();
}
}
return null;
}
//dottedNode
// : ((methodOrProperty
// | functionOrVar
// | projection
// | selection
// | firstSelection
// | lastSelection
// ))
// ;
function eatDottedNode() {
var token = nextToken(); // it was a '.' or a '?.'
var nullSafeNavigation = token.getKind() === _TokenKind.TokenKind.SAFE_NAVI;
if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar() || maybeEatProjection(nullSafeNavigation) || maybeEatSelection(nullSafeNavigation)) {
return pop();
}
if (peekToken() === null) {
// unexpectedly ran out of data
raiseInternalException(token.startPos, 'OOD');
} else {
raiseInternalException(token.startPos, 'UNEXPECTED_DATA_AFTER_DOT', toString(peekToken()));
}
return null;
}
// functionOrVar
// : (POUND ID LPAREN) => function
// | var
//
// function : POUND id=ID methodArgs -> ^(FUNCTIONREF[$id] methodArgs);
// var : POUND id=ID -> ^(VARIABLEREF[$id]);
function maybeEatFunctionOrVar() {
if (!peekTokenOne(_TokenKind.TokenKind.HASH)) {
return false;
}
var token = nextToken();
var functionOrVariableName = eatToken(_TokenKind.TokenKind.IDENTIFIER);
var args = maybeEatMethodArgs();
if (args === null) {
push(_astVariableReference.VariableReference.create(functionOrVariableName.data, toPosBounds(token.startPos, functionOrVariableName.endPos)));
return true;
}
push(_astFunctionReference.FunctionReference.create(functionOrVariableName.data, toPosBounds(token.startPos, functionOrVariableName.endPos), args));
return true;
}
// methodArgs : LPAREN! (argument (COMMA! argument)* (COMMA!)?)? RPAREN!;
function maybeEatMethodArgs() {
if (!peekTokenOne(_TokenKind.TokenKind.LPAREN)) {
return null;
}
var args = [];
consumeArguments(args);
eatToken(_TokenKind.TokenKind.RPAREN);
return args;
}
function eatConstructorArgs(accumulatedArguments) {
if (!peekTokenOne(_TokenKind.TokenKind.LPAREN)) {
raiseInternalException(toPosToken(peekToken()), 'MISSING_CONSTRUCTOR_ARGS');
}
consumeArguments(accumulatedArguments);
eatToken(_TokenKind.TokenKind.RPAREN);
}
/**
* Used for consuming arguments for either a method or a constructor call
*/
function consumeArguments(accumulatedArguments) {
var pos = peekToken().startPos;
var next;
do {
nextToken(); // consume ( (first time through) or comma (subsequent times)
var token = peekToken();
if (token === null) {
raiseInternalException(pos, 'RUN_OUT_OF_ARGUMENTS');
}
if (token.getKind() !== _TokenKind.TokenKind.RPAREN) {
accumulatedArguments.push(eatExpression());
}
next = peekToken();
} while (next !== null && next.kind === _TokenKind.TokenKind.COMMA);
if (next === null) {
raiseInternalException(pos, 'RUN_OUT_OF_ARGUMENTS');
}
}
function positionOf(token) {
if (token === null) {
// if null assume the problem is because the right token was
// not found at the end of the expression
return expressionString.length;
}
return token.startPos;
}
//startNode
// : parenExpr | literal
// | type
// | methodOrProperty
// | functionOrVar
// | projection
// | selection
// | firstSelection
// | lastSelection
// | indexer
// | constructor
function eatStartNode() {
if (maybeEatLiteral()) {
return pop();
} else if (maybeEatParenExpression()) {
return pop();
} else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() || maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) {
return pop();
} else if (maybeEatBeanReference()) {
return pop();
} else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
return pop();
} else if (maybeEatInlineListOrMap()) {
return pop();
} else {
return null;
}
}
// parse: @beanname @'bean.name'
// quoted if dotted
function maybeEatBeanReference() {
if (peekTokenOne(_TokenKind.TokenKind.BEAN_REF)) {
var beanRefToken = nextToken();
var beanNameToken = null;
var beanName = null;
if (peekTokenOne(_TokenKind.TokenKind.IDENTIFIER)) {
beanNameToken = eatToken(_TokenKind.TokenKind.IDENTIFIER);
beanName = beanNameToken.data;
} else if (peekTokenOne(_TokenKind.TokenKind.LITERAL_STRING)) {
beanNameToken = eatToken(_TokenKind.TokenKind.LITERAL_STRING);
beanName = beanNameToken.stringValue();
beanName = beanName.substring(1, beanName.length() - 1);
} else {
raiseInternalException(beanRefToken.startPos, 'INVALID_BEAN_REFERENCE');
}
var beanReference = new BeanReference(toPosToken(beanNameToken), beanName);
push(beanReference);
return true;
}
return false;
}
function maybeEatTypeReference() {
if (peekTokenOne(_TokenKind.TokenKind.IDENTIFIER)) {
var typeName = peekToken();
if (typeName.stringValue() !== 'T') {
return false;
}
// It looks like a type reference but is T being used as a map key?
var token = nextToken();
if (peekTokenOne(_TokenKind.TokenKind.RSQUARE)) {
// looks like 'T]' (T is map key)
push(_astPropertyReference.PropertyReference.create(token.stringValue(), toPosToken(token)));
return true;
}
eatToken(_TokenKind.TokenKind.LPAREN);
var node = eatPossiblyQualifiedId();
// dotted qualified id
// Are there array dimensions?
var dims = 0;
while (peekTokenConsumeIfMatched(_TokenKind.TokenKind.LSQUARE, true)) {
eatToken(_TokenKind.TokenKind.RSQUARE);
dims++;
}
eatToken(_TokenKind.TokenKind.RPAREN);
push(new TypeReference(toPosToken(typeName), node, dims));
return true;
}
return false;
}
function maybeEatNullReference() {
if (peekTokenOne(_TokenKind.TokenKind.IDENTIFIER)) {
var nullToken = peekToken();
if (nullToken.stringValue().toLowerCase() !== 'null') {
return false;
}
nextToken();
push(_astNullLiteral.NullLiteral.create(toPosToken(nullToken)));
return true;
}
return false;
}
//projection: PROJECT^ expression RCURLY!;
function maybeEatProjection(nullSafeNavigation) {
var token = peekToken();
if (!peekTokenConsumeIfMatched(_TokenKind.TokenKind.PROJECT, true)) {
return false;
}
var expr = eatExpression();
eatToken(_TokenKind.TokenKind.RSQUARE);
push(_astProjection.Projection.create(nullSafeNavigation, toPosToken(token), expr));
return true;
}
// list = LCURLY (element (COMMA element)*) RCURLY
// map = LCURLY (key ':' value (COMMA key ':' value)*) RCURLY
function maybeEatInlineListOrMap() {
var token = peekToken(),
listElements = [];
if (!peekTokenConsumeIfMatched(_TokenKind.TokenKind.LCURLY, true)) {
return false;
}
var expr = null;
var closingCurly = peekToken();
if (peekTokenConsumeIfMatched(_TokenKind.TokenKind.RCURLY, true)) {
// empty list '{}'
expr = _astInlineList.InlineList.create(toPosBounds(token.startPos, closingCurly.endPos));
} else if (peekTokenConsumeIfMatched(_TokenKind.TokenKind.COLON, true)) {
closingCurly = eatToken(_TokenKind.TokenKind.RCURLY);
// empty map '{:}'
expr = _astInlineMap.InlineMap.create(toPosBounds(token.startPos, closingCurly.endPos));
} else {
var firstExpression = eatExpression();
// Next is either:
// '}' - end of list
// ',' - more expressions in this list
// ':' - this is a map!
if (peekTokenOne(_TokenKind.TokenKind.RCURLY)) {
// list with one item in it
listElements.push(firstExpression);
closingCurly = eatToken(_TokenKind.TokenKind.RCURLY);
expr = _astInlineList.InlineList.create(toPosBounds(token.startPos, closingCurly.endPos), listElements);
} else if (peekTokenConsumeIfMatched(_TokenKind.TokenKind.COMMA, true)) {
// multi item list
listElements.push(firstExpression);
do {
listElements.push(eatExpression());
} while (peekTokenConsumeIfMatched(_TokenKind.TokenKind.COMMA, true));
closingCurly = eatToken(_TokenKind.TokenKind.RCURLY);
expr = _astInlineList.InlineList.create(toPosToken(token.startPos, closingCurly.endPos), listElements);
} else if (peekTokenConsumeIfMatched(_TokenKind.TokenKind.COLON, true)) {
// map!
var mapElements = [];
mapElements.push(firstExpression);
mapElements.push(eatExpression());
while (peekTokenConsumeIfMatched(_TokenKind.TokenKind.COMMA, true)) {
mapElements.push(eatExpression());
eatToken(_TokenKind.TokenKind.COLON);
mapElements.push(eatExpression());
}
closingCurly = eatToken(_TokenKind.TokenKind.RCURLY);
expr = _astInlineMap.InlineMap.create(toPosBounds(token.startPos, closingCurly.endPos), mapElements);
} else {
raiseInternalException(token.startPos, 'OOD');
}
}
push(expr);
return true;
}
function maybeEatIndexer() {
var token = peekToken();
if (!peekTokenConsumeIfMatched(_TokenKind.TokenKind.LSQUARE, true)) {
return false;
}
var expr = eatExpression();
eatToken(_TokenKind.TokenKind.RSQUARE);
push(_astIndexer.Indexer.create(toPosToken(token), expr));
return true;
}
function maybeEatSelection(nullSafeNavigation) {
var token = peekToken();
if (!peekSelectToken()) {
return false;
}
nextToken();
var expr = eatExpression();
if (expr === null) {
raiseInternalException(toPosToken(token), 'MISSING_SELECTION_EXPRESSION');
}
eatToken(_TokenKind.TokenKind.RSQUARE);
if (token.getKind() === _TokenKind.TokenKind.SELECT_FIRST) {
push(_astSelection.Selection.create(nullSafeNavigation, _astSelection.Selection.FIRST, toPosToken(token), expr));
} else if (token.getKind() === _TokenKind.TokenKind.SELECT_LAST) {
push(_astSelection.Selection.create(nullSafeNavigation, _astSelection.Selection.LAST, toPosToken(token), expr));
} else {
push(_astSelection.Selection.create(nullSafeNavigation, _astSelection.Selection.ALL, toPosToken(token), expr));
}
return true;
}
/**
* Eat an identifier, possibly qualified (meaning that it is dotted).
* TODO AndyC Could create complete identifiers (a.b.c) here rather than a sequence of them? (a, b, c)
*/
function eatPossiblyQualifiedId() {
var qualifiedIdPieces = [];
var node = peekToken();
while (isValidQualifiedId(node)) {
nextToken();
if (node.kind !== _TokenKind.TokenKind.DOT) {
qualifiedIdPieces.push(new Identifier(node.stringValue(), toPosToken(node)));
}
node = peekToken();
}
if (!qualifiedIdPieces.length) {
if (node === null) {
raiseInternalException(expressionString.length(), 'OOD');
}
raiseInternalException(node.startPos, 'NOT_EXPECTED_TOKEN', 'qualified ID', node.getKind().toString().toLowerCase());
}
var pos = toPosBounds(qualifiedIdPieces[0].getStartPosition(), qualifiedIdPieces[qualifiedIdPieces.length - 1].getEndPosition());
return new QualifiedIdentifier(pos, qualifiedIdPieces);
}
function isValidQualifiedId(node) {
if (node === null || node.kind === _TokenKind.TokenKind.LITERAL_STRING) {
return false;
}
if (node.kind === _TokenKind.TokenKind.DOT || node.kind === _TokenKind.TokenKind.IDENTIFIER) {
return true;
}
var value = node.stringValue();
return value.length && VALID_QUALIFIED_ID_PATTERN.test(value);
}
// This is complicated due to the support for dollars in identifiers. Dollars are normally separate tokens but
// there we want to combine a series of identifiers and dollars into a single identifier
function maybeEatMethodOrProperty(nullSafeNavigation) {
if (peekTokenOne(_TokenKind.TokenKind.IDENTIFIER)) {
var methodOrPropertyName = nextToken();
var args = maybeEatMethodArgs();
if (args === null) {
// property
push(_astPropertyReference.PropertyReference.create(nullSafeNavigation, methodOrPropertyName.stringValue(), toPosToken(methodOrPropertyName)));
return true;
}
// methodreference
push(_astMethodReference.MethodReference.create(nullSafeNavigation, methodOrPropertyName.stringValue(), toPosToken(methodOrPropertyName), args));
// TODO what is the end position for a method reference? the name or the last arg?
return true;
}
return false;
}
//constructor
//: ('new' qualifiedId LPAREN) => 'new' qualifiedId ctorArgs -> ^(CONSTRUCTOR qualifiedId ctorArgs)
function maybeEatConstructorReference() {
if (peekIdentifierToken('new')) {
var newToken = nextToken();
// It looks like a constructor reference but is NEW being used as a map key?
if (peekTokenOne(_TokenKind.TokenKind.RSQUARE)) {
// looks like 'NEW]' (so NEW used as map key)
push(_astPropertyReference.PropertyReference.create(newToken.stringValue(), toPosToken(newToken)));
return true;
}
var possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
var nodes = [];
nodes.push(possiblyQualifiedConstructorName);
if (peekTokenOne(_TokenKind.TokenKind.LSQUARE)) {
// array initializer
var dimensions = [];
while (peekTokenConsumeIfMatched(_TokenKind.TokenKind.LSQUARE, true)) {
if (!peekTokenOne(_TokenKind.TokenKind.RSQUARE)) {
dimensions.push(eatExpression());
} else {
dimensions.push(null);
}
eatToken(_TokenKind.TokenKind.RSQUARE);
}
if (maybeEatInlineListOrMap()) {
nodes.push(pop());
}
push(new ConstructorReference(toPosToken(newToken), dimensions, nodes));
} else {
// regular constructor invocation
eatConstructorArgs(nodes);
// TODO correct end position?
push(new ConstructorReference(toPosToken(newToken), nodes));
}
return true;
}
return false;
}
function push(newNode) {
constructedNodes.push(newNode);
}
function pop() {
return constructedNodes.pop();
}
// literal
// : INTEGER_LITERAL
// | boolLiteral
// | STRING_LITERAL
// | HEXADECIMAL_INTEGER_LITERAL
// | REAL_LITERAL
// | DQ_STRING_LITERAL
// | NULL_LITERAL
function maybeEatLiteral() {
var token = peekToken();
if (token === null) {
return false;
}
if (token.getKind() === _TokenKind.TokenKind.LITERAL_INT || token.getKind() === _TokenKind.TokenKind.LITERAL_LONG) {
push(_astNumberLiteral.NumberLiteral.create(parseInt(token.stringValue(), 10), toPosToken(token)));
} else if (token.getKind() === _TokenKind.TokenKind.LITERAL_REAL || token.getKind() === _TokenKind.TokenKind.LITERAL_REAL_FLOAT) {
push(_astNumberLiteral.NumberLiteral.create(parseFloat(token.stringValue()), toPosToken(token)));
} else if (token.getKind() === _TokenKind.TokenKind.LITERAL_HEXINT || token.getKind() === _TokenKind.TokenKind.LITERAL_HEXLONG) {
push(_astNumberLiteral.NumberLiteral.create(parseInt(token.stringValue(), 16), toPosToken(token)));
} else if (peekIdentifierToken('true')) {
push(_astBooleanLiteral.BooleanLiteral.create(true, toPosToken(token)));
} else if (peekIdentifierToken('false')) {
push(_astBooleanLiteral.BooleanLiteral.create(false, toPosToken(token)));
} else if (token.getKind() === _TokenKind.TokenKind.LITERAL_STRING) {
push(_astStringLiteral.StringLiteral.create(token.stringValue(), toPosToken(token)));
} else {
return false;
}
nextToken();
return true;
}
//parenExpr : LPAREN! expression RPAREN!;
function maybeEatParenExpression() {
if (peekTokenOne(_TokenKind.TokenKind.LPAREN)) {
nextToken();
var expr = eatExpression();
eatToken(_TokenKind.TokenKind.RPAREN);
push(expr);
return true;
} else {
return false;
}
}
// relationalOperator
// : EQUAL | NOT_EQUAL | LESS_THAN | LESS_THAN_OR_EQUAL | GREATER_THAN
// | GREATER_THAN_OR_EQUAL | INSTANCEOF | BETWEEN | MATCHES
function maybeEatRelationalOperator() {
var token = peekToken();
if (token === null) {
return null;
}
if (token.isNumericRelationalOperator()) {
return token;
}
if (token.isIdentifier()) {
var idString = token.stringValue();
if (idString.toLowerCase() === 'instanceof') {
return token.asInstanceOfToken();
}
if (idString.toLowerCase() === 'matches') {
return token.asMatchesToken();
}
if (idString.toLowerCase() === 'between') {
return token.asBetweenToken();
}
}
return null;
}
function eatToken(expectedKind) {
var token = nextToken();
if (token === null) {
raiseInternalException(expressionString.length, 'OOD');
}
if (token.getKind() !== expectedKind) {
raiseInternalException(token.startPos, 'NOT_EXPECTED_TOKEN', expectedKind.toString().toLowerCase(), token.getKind().toString().toLowerCase());
}
return token;
}
function peekTokenOne(desiredTokenKind) {
return peekTokenConsumeIfMatched(desiredTokenKind, false);
}
function peekTokenConsumeIfMatched(desiredTokenKind, consumeIfMatched) {
if (!moreTokens()) {
return false;
}
var token = peekToken();
if (token.getKind() === desiredTokenKind) {
if (consumeIfMatched) {
tokenStreamPointer++;
}
return true;
}
if (desiredTokenKind === _TokenKind.TokenKind.IDENTIFIER) {
// might be one of the textual forms of the operators (e.g. NE for !== ) - in which case we can treat it as an identifier
// The list is represented here: Tokenizer.alternativeOperatorNames and those ones are in order in the TokenKind enum
if (token.getKind().ordinal() >= _TokenKind.TokenKind.DIV.ordinal() && token.getKind().ordinal() <= _TokenKind.TokenKind.NOT.ordinal() && token.data !== null) {
// if token.data were null, we'd know it wasn'token the textual form, it was the symbol form
return true;
}
}
return false;
}
function peekTokenAny() {
if (!moreTokens()) {
return false;
}
var token = peekToken();
var args = Array.prototype.slice.call(arguments);
for (var i = 0, l = args.length; i < l; i += 1) {
if (token.getKind() === args[i]) {
return true;
}
}
return false;
}
function peekIdentifierToken(identifierString) {
if (!moreTokens()) {
return false;
}
var token = peekToken();
return token.getKind() === _TokenKind.TokenKind.IDENTIFIER && token.stringValue().toLowerCase() === identifierString.toLowerCase();
}
function peekSelectToken() {
if (!moreTokens()) {
return false;
}
var token = peekToken();
return token.getKind() === _TokenKind.TokenKind.SELECT || token.getKind() === _TokenKind.TokenKind.SELECT_FIRST || token.getKind() === _TokenKind.TokenKind.SELECT_LAST;
}
function moreTokens() {
return tokenStreamPointer < tokenStream.length;
}
function nextToken() {
if (tokenStreamPointer >= tokenStreamLength) {
return null;
}
return tokenStream[tokenStreamPointer++];
}
function peekToken() {
if (tokenStreamPointer >= tokenStreamLength) {
return null;
}
return tokenStream[tokenStreamPointer];
}
function raiseInternalException(pos, message, expected, actual) {
if (expected) {
message += '\nExpected: ' + expected;
}
if (actual) {
message += '\nActual: ' + actual;
}
throw {
name: 'InternalParseException',
message: 'Error occurred while attempting to parse expression \'' + expressionString + '\' at position ' + pos + '. Message: ' + message
};
}
function toString(token) {
if (token.getKind().hasPayload()) {
return token.stringValue();
}
return token.getKind().toString().toLowerCase();
}
function checkOperands(token, left, right) {
checkLeftOperand(token, left);
checkRightOperand(token, right);
}
function checkLeftOperand(token, operandExpression) {
if (operandExpression === null) {
raiseInternalException(token.startPos, 'LEFT_OPERAND_PROBLEM');
}
}
function checkRightOperand(token, operandExpression) {
if (operandExpression === null) {
raiseInternalException(token.startPos, 'RIGHT_OPERAND_PROBLEM');
}
}
/**
* Compress the start and end of a token into a single int.
*/
function toPosToken(token) {
return (token.startPos << 16) + token.endPos;
}
function toPosBounds(start, end) {
return (start << 16) + end;
}
return {
setConfiguration: setConfiguration,
parse: parse
};
};
exports.SpelExpressionParser = SpelExpressionParser;
},{"./TokenKind":5,"./Tokenizer":6,"./ast/Assign":7,"./ast/BooleanLiteral":8,"./ast/CompoundExpression":9,"./ast/Elvis":10,"./ast/FunctionReference":11,"./ast/Indexer":12,"./ast/InlineList":13,"./ast/InlineMap":14,"./ast/MethodReference":15,"./ast/NullLiteral":16,"./ast/NumberLiteral":17,"./ast/OpAnd":18,"./ast/OpDec":19,"./ast/OpDivide":20,"./ast/OpEQ":21,"./ast/OpGE":22,"./ast/OpGT":23,"./ast/OpInc":24,"./ast/OpLE":25,"./ast/OpLT":26,"./ast/OpMinus":27,"./ast/OpModulus":28,"./ast/OpMultiply":29,"./ast/OpNE":30,"./ast/OpNot":31,"./ast/OpOr":32,"./ast/OpPlus":33,"./ast/OpPower":34,"./ast/Projection":35,"./ast/PropertyReference":36,"./ast/Selection":37,"./ast/StringLiteral":39,"./ast/Ternary":40,"./ast/VariableReference":41}],3:[function(require,module,exports){
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Ben March
* @since 0.2.0
*/
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
function create(authentication, principal) {
var context = {};
context.authentication = authentication || {};
context.principal = principal || {};
context.hasRole = function (role) {
var hasRole = false;
if (!role) {
return false;
}
if (!context.authentication && !Array.isArray(context.authentication.authorities)) {
return false;
}
context.authentication.authorities.forEach(function (grantedAuthority) {
if (grantedAuthority.authority.toLowerCase() === role.toLowerCase()) {
hasRole = true;
}
});
return hasRole;
};
context.hasPermission = function () {
var args = Array.prototype.slice.call(arguments);
if (args.length === 1) {
return context.hasRole(args[0]);
}
};
return context;
}
var StandardContext = {
create: create
};
exports.StandardContext = StandardContext;
/*variable arguments*/
},{}],4:[function(require,module,exports){
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Andy Clement
* @author Ben March
* @since 0.2.0
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _TokenKind = require('../src/TokenKind');
function Token(tokenKind, tokenData, startPos, endPos) {
this.kind = tokenKind;
this.startPos = startPos;
this.endPos = endPos;
if (tokenData) {
this.data = tokenData;
}
}
Token.prototype.getKind = function () {
return this.kind;
};
Token.prototype.toString = function () {
var s = '[';
s += this.kind.toString();
if (this.kind.hasPayload()) {
s += ':' + this.data;
}
s += ']';
s += '(' + this.startPos + ',' + this.endPos + ')';
return s;
};
Token.prototype.isIdentifier = function () {
return this.kind === _TokenKind.TokenKind.IDENTIFIER;
};
Token.prototype.isNumericRelationalOperator = function () {
return this.kind === _TokenKind.TokenKind.GT || this.kind === _TokenKind.TokenKind.GE || this.kind === _TokenKind.TokenKind.LT || this.kind === _TokenKind.TokenKind.LE || this.kind === _TokenKind.TokenKind.EQ || this.kind === _TokenKind.TokenKind.NE;
};
Token.prototype.stringValue = function () {
return this.data;
};
Token.prototype.asInstanceOfToken = function () {
return new Token(_TokenKind.TokenKind.INSTANCEOF, this.startPos, this.endPos);
};
Token.prototype.asMatchesToken = function () {
return new Token(_TokenKind.TokenKind.MATCHES, this.startPos, this.endPos);
};
Token.prototype.asBetweenToken = function () {
return new Token(_TokenKind.TokenKind.BETWEEN, this.startPos, this.endPos);
};
Token.prototype.getStartPosition = function () {
return this.startPos;
};
Token.prototype.getEndPosition = function () {
return this.endPos;
};
exports.Token = Token;
},{"./TokenKind":5}],5:[function(require,module,exports){
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Andy Clement
* @author Ben March
* @since 0.2.0
*/
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var types = {
LITERAL_INT: 1, //tested
LITERAL_LONG: 2, //tested
LITERAL_HEXINT: 3, //tested
LITERAL_HEXLONG: 4, //tested
LITERAL_STRING: 5, //tested
LITERAL_REAL: 6, //tested
LITERAL_REAL_FLOAT: 7, //tested
LPAREN: '(', //tested
RPAREN: ')', //tested
COMMA: ',', //tested
IDENTIFIER: 0, //tested
COLON: ':', //tested
HASH: '#', //tested
RSQUARE: ']', //tested
LSQUARE: '[', //tested
LCURLY: '{', //tested
RCURLY: '}', //tested
DOT: '.', //tested
PLUS: '+', //tested
STAR: '*', //tested
MINUS: '-', //tested
SELECT_FIRST: '^[', //tested
SELECT_LAST: '$[', //tested
QMARK: '?', //tested
PROJECT: '![', //tested
DIV: '/', //tested
GE: '>=', //tested
GT: '>', //tested
LE: '<=', //tested
LT: '<', //tested
EQ: '==', //tested
NE: '!=', //tested
MOD: '%', //tested
NOT: '!', //tested
ASSIGN: '=', //tested
INSTANCEOF: 'instanceof', //test fails
MATCHES: 'matches', //test fails
BETWEEN: 'between', //test fails
SELECT: '?[', //tested
POWER: '^', //tested
ELVIS: '?:', //tested
SAFE_NAVI: '?.', //tested
BEAN_REF: '@', //tested
SYMBOLIC_OR: '||', //tested
SYMBOLIC_AND: '&&', //tested
INC: '++', //tested
DEC: '--' //tested
};
function TokenKind(type) {
this.type = type;
this.tokenChars = types[type];
this._hasPayload = typeof types[type] !== 'string';
if (typeof types[type] === 'number') {
this._ordinal = types[type];
}
}
//create enum
for (var t in types) {
if (types.hasOwnProperty(t)) {
TokenKind[t] = new TokenKind(t);
}
}
TokenKind.prototype.toString = function () {
return this.type + (this.tokenChars.length !== 0 ? '(' + this.tokenChars + ')' : '');
};
TokenKind.prototype.getLength = function () {
return this.tokenChars.length;
};
TokenKind.prototype.hasPayload = function () {
return this._hasPayload;
};
TokenKind.prototype.valueOf = function (id) {
for (var t in types) {
if (types.hasOwnProperty(t) && types[t] === id) {
return TokenKind[t];
}
}
};
TokenKind.prototype.ordinal = function () {
return this._ordinal;
};
exports.TokenKind = TokenKind;
},{}],6:[function(require,module,exports){
/*
* Copyright 2002-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may