UNPKG

@pru-rt/spel2js

Version:

Parse Spring Expression Language in JavaScript

1,423 lines (1,198 loc) 135 kB
/* * 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