1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.expression.spel.standard;
18
19 import java.util.ArrayList;
20 import java.util.LinkedList;
21 import java.util.List;
22 import java.util.Stack;
23 import java.util.regex.Pattern;
24
25 import org.springframework.expression.ParseException;
26 import org.springframework.expression.ParserContext;
27 import org.springframework.expression.common.TemplateAwareExpressionParser;
28 import org.springframework.expression.spel.InternalParseException;
29 import org.springframework.expression.spel.SpelMessage;
30 import org.springframework.expression.spel.SpelParseException;
31 import org.springframework.expression.spel.SpelParserConfiguration;
32 import org.springframework.expression.spel.ast.Assign;
33 import org.springframework.expression.spel.ast.BeanReference;
34 import org.springframework.expression.spel.ast.BooleanLiteral;
35 import org.springframework.expression.spel.ast.CompoundExpression;
36 import org.springframework.expression.spel.ast.ConstructorReference;
37 import org.springframework.expression.spel.ast.Elvis;
38 import org.springframework.expression.spel.ast.FunctionReference;
39 import org.springframework.expression.spel.ast.Identifier;
40 import org.springframework.expression.spel.ast.Indexer;
41 import org.springframework.expression.spel.ast.InlineList;
42 import org.springframework.expression.spel.ast.InlineMap;
43 import org.springframework.expression.spel.ast.Literal;
44 import org.springframework.expression.spel.ast.MethodReference;
45 import org.springframework.expression.spel.ast.NullLiteral;
46 import org.springframework.expression.spel.ast.OpAnd;
47 import org.springframework.expression.spel.ast.OpDec;
48 import org.springframework.expression.spel.ast.OpDivide;
49 import org.springframework.expression.spel.ast.OpEQ;
50 import org.springframework.expression.spel.ast.OpGE;
51 import org.springframework.expression.spel.ast.OpGT;
52 import org.springframework.expression.spel.ast.OpInc;
53 import org.springframework.expression.spel.ast.OpLE;
54 import org.springframework.expression.spel.ast.OpLT;
55 import org.springframework.expression.spel.ast.OpMinus;
56 import org.springframework.expression.spel.ast.OpModulus;
57 import org.springframework.expression.spel.ast.OpMultiply;
58 import org.springframework.expression.spel.ast.OpNE;
59 import org.springframework.expression.spel.ast.OpOr;
60 import org.springframework.expression.spel.ast.OpPlus;
61 import org.springframework.expression.spel.ast.OperatorBetween;
62 import org.springframework.expression.spel.ast.OperatorInstanceof;
63 import org.springframework.expression.spel.ast.OperatorMatches;
64 import org.springframework.expression.spel.ast.OperatorNot;
65 import org.springframework.expression.spel.ast.OperatorPower;
66 import org.springframework.expression.spel.ast.Projection;
67 import org.springframework.expression.spel.ast.PropertyOrFieldReference;
68 import org.springframework.expression.spel.ast.QualifiedIdentifier;
69 import org.springframework.expression.spel.ast.Selection;
70 import org.springframework.expression.spel.ast.SpelNodeImpl;
71 import org.springframework.expression.spel.ast.StringLiteral;
72 import org.springframework.expression.spel.ast.Ternary;
73 import org.springframework.expression.spel.ast.TypeReference;
74 import org.springframework.expression.spel.ast.VariableReference;
75 import org.springframework.util.Assert;
76 import org.springframework.util.StringUtils;
77
78
79
80
81
82
83
84
85 class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
86
87 private static final Pattern VALID_QUALIFIED_ID_PATTERN = Pattern.compile("[\\p{L}\\p{N}_$]+");
88
89
90 private final SpelParserConfiguration configuration;
91
92
93 private final Stack<SpelNodeImpl> constructedNodes = new Stack<SpelNodeImpl>();
94
95
96 private String expressionString;
97
98
99 private List<Token> tokenStream;
100
101
102 private int tokenStreamLength;
103
104
105 private int tokenStreamPointer;
106
107
108
109
110
111
112 public InternalSpelExpressionParser(SpelParserConfiguration configuration) {
113 this.configuration = configuration;
114 }
115
116
117 @Override
118 protected SpelExpression doParseExpression(String expressionString, ParserContext context) throws ParseException {
119 try {
120 this.expressionString = expressionString;
121 Tokenizer tokenizer = new Tokenizer(expressionString);
122 tokenizer.process();
123 this.tokenStream = tokenizer.getTokens();
124 this.tokenStreamLength = this.tokenStream.size();
125 this.tokenStreamPointer = 0;
126 this.constructedNodes.clear();
127 SpelNodeImpl ast = eatExpression();
128 if (moreTokens()) {
129 throw new SpelParseException(peekToken().startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
130 }
131 Assert.isTrue(this.constructedNodes.isEmpty());
132 return new SpelExpression(expressionString, ast, this.configuration);
133 }
134 catch (InternalParseException ex) {
135 throw ex.getCause();
136 }
137 }
138
139
140
141
142
143
144
145 private SpelNodeImpl eatExpression() {
146 SpelNodeImpl expr = eatLogicalOrExpression();
147 if (moreTokens()) {
148 Token t = peekToken();
149 if (t.kind == TokenKind.ASSIGN) {
150 if (expr == null) {
151 expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1));
152 }
153 nextToken();
154 SpelNodeImpl assignedValue = eatLogicalOrExpression();
155 return new Assign(toPos(t), expr, assignedValue);
156 }
157
158 if (t.kind == TokenKind.ELVIS) {
159 if (expr == null) {
160 expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 2));
161 }
162 nextToken();
163 SpelNodeImpl valueIfNull = eatExpression();
164 if (valueIfNull==null) {
165 valueIfNull = new NullLiteral(toPos(t.startPos + 1, t.endPos + 1));
166 }
167 return new Elvis(toPos(t), expr, valueIfNull);
168 }
169
170 if (t.kind == TokenKind.QMARK) {
171 if (expr == null) {
172 expr = new NullLiteral(toPos(t.startPos - 1, t.endPos - 1));
173 }
174 nextToken();
175 SpelNodeImpl ifTrueExprValue = eatExpression();
176 eatToken(TokenKind.COLON);
177 SpelNodeImpl ifFalseExprValue = eatExpression();
178 return new Ternary(toPos(t), expr, ifTrueExprValue, ifFalseExprValue);
179 }
180 }
181 return expr;
182 }
183
184
185 private SpelNodeImpl eatLogicalOrExpression() {
186 SpelNodeImpl expr = eatLogicalAndExpression();
187 while (peekIdentifierToken("or") || peekToken(TokenKind.SYMBOLIC_OR)) {
188 Token t = nextToken();
189 SpelNodeImpl rhExpr = eatLogicalAndExpression();
190 checkOperands(t, expr, rhExpr);
191 expr = new OpOr(toPos(t), expr, rhExpr);
192 }
193 return expr;
194 }
195
196
197 private SpelNodeImpl eatLogicalAndExpression() {
198 SpelNodeImpl expr = eatRelationalExpression();
199 while (peekIdentifierToken("and") || peekToken(TokenKind.SYMBOLIC_AND)) {
200 Token t = nextToken();
201 SpelNodeImpl rhExpr = eatRelationalExpression();
202 checkOperands(t, expr, rhExpr);
203 expr = new OpAnd(toPos(t), expr, rhExpr);
204 }
205 return expr;
206 }
207
208
209 private SpelNodeImpl eatRelationalExpression() {
210 SpelNodeImpl expr = eatSumExpression();
211 Token relationalOperatorToken = maybeEatRelationalOperator();
212 if (relationalOperatorToken != null) {
213 Token t = nextToken();
214 SpelNodeImpl rhExpr = eatSumExpression();
215 checkOperands(t, expr, rhExpr);
216 TokenKind tk = relationalOperatorToken.kind;
217
218 if (relationalOperatorToken.isNumericRelationalOperator()) {
219 int pos = toPos(t);
220 if (tk == TokenKind.GT) {
221 return new OpGT(pos, expr, rhExpr);
222 }
223 if (tk == TokenKind.LT) {
224 return new OpLT(pos, expr, rhExpr);
225 }
226 if (tk == TokenKind.LE) {
227 return new OpLE(pos, expr, rhExpr);
228 }
229 if (tk == TokenKind.GE) {
230 return new OpGE(pos, expr, rhExpr);
231 }
232 if (tk == TokenKind.EQ) {
233 return new OpEQ(pos, expr, rhExpr);
234 }
235 Assert.isTrue(tk == TokenKind.NE);
236 return new OpNE(pos, expr, rhExpr);
237 }
238
239 if (tk == TokenKind.INSTANCEOF) {
240 return new OperatorInstanceof(toPos(t), expr, rhExpr);
241 }
242
243 if (tk == TokenKind.MATCHES) {
244 return new OperatorMatches(toPos(t), expr, rhExpr);
245 }
246
247 Assert.isTrue(tk == TokenKind.BETWEEN);
248 return new OperatorBetween(toPos(t), expr, rhExpr);
249 }
250 return expr;
251 }
252
253
254 private SpelNodeImpl eatSumExpression() {
255 SpelNodeImpl expr = eatProductExpression();
256 while (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.INC)) {
257 Token t = nextToken();
258 SpelNodeImpl rhExpr = eatProductExpression();
259 checkRightOperand(t,rhExpr);
260 if (t.kind == TokenKind.PLUS) {
261 expr = new OpPlus(toPos(t), expr, rhExpr);
262 }
263 else if (t.kind == TokenKind.MINUS) {
264 expr = new OpMinus(toPos(t), expr, rhExpr);
265 }
266 }
267 return expr;
268 }
269
270
271 private SpelNodeImpl eatProductExpression() {
272 SpelNodeImpl expr = eatPowerIncDecExpression();
273 while (peekToken(TokenKind.STAR, TokenKind.DIV, TokenKind.MOD)) {
274 Token t = nextToken();
275 SpelNodeImpl rhExpr = eatPowerIncDecExpression();
276 checkOperands(t, expr, rhExpr);
277 if (t.kind == TokenKind.STAR) {
278 expr = new OpMultiply(toPos(t), expr, rhExpr);
279 }
280 else if (t.kind == TokenKind.DIV) {
281 expr = new OpDivide(toPos(t), expr, rhExpr);
282 }
283 else {
284 Assert.isTrue(t.kind == TokenKind.MOD);
285 expr = new OpModulus(toPos(t), expr, rhExpr);
286 }
287 }
288 return expr;
289 }
290
291
292 private SpelNodeImpl eatPowerIncDecExpression() {
293 SpelNodeImpl expr = eatUnaryExpression();
294 if (peekToken(TokenKind.POWER)) {
295 Token t = nextToken();
296 SpelNodeImpl rhExpr = eatUnaryExpression();
297 checkRightOperand(t,rhExpr);
298 return new OperatorPower(toPos(t), expr, rhExpr);
299 }
300
301 if (expr != null && peekToken(TokenKind.INC,TokenKind.DEC)) {
302 Token t = nextToken();
303 if (t.getKind() == TokenKind.INC) {
304 return new OpInc(toPos(t), true, expr);
305 }
306 return new OpDec(toPos(t), true, expr);
307 }
308
309 return expr;
310 }
311
312
313 private SpelNodeImpl eatUnaryExpression() {
314 if (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) {
315 Token t = nextToken();
316 SpelNodeImpl expr = eatUnaryExpression();
317 if (t.kind == TokenKind.NOT) {
318 return new OperatorNot(toPos(t), expr);
319 }
320
321 if (t.kind == TokenKind.PLUS) {
322 return new OpPlus(toPos(t), expr);
323 }
324 Assert.isTrue(t.kind == TokenKind.MINUS);
325 return new OpMinus(toPos(t), expr);
326
327 }
328 if (peekToken(TokenKind.INC, TokenKind.DEC)) {
329 Token t = nextToken();
330 SpelNodeImpl expr = eatUnaryExpression();
331 if (t.getKind() == TokenKind.INC) {
332 return new OpInc(toPos(t), false, expr);
333 }
334 return new OpDec(toPos(t), false, expr);
335 }
336
337 return eatPrimaryExpression();
338 }
339
340
341 private SpelNodeImpl eatPrimaryExpression() {
342 List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
343 SpelNodeImpl start = eatStartNode();
344 nodes.add(start);
345 while (maybeEatNode()) {
346 nodes.add(pop());
347 }
348 if (nodes.size() == 1) {
349 return nodes.get(0);
350 }
351 return new CompoundExpression(toPos(start.getStartPosition(),
352 nodes.get(nodes.size() - 1).getEndPosition()),
353 nodes.toArray(new SpelNodeImpl[nodes.size()]));
354 }
355
356
357 private boolean maybeEatNode() {
358 SpelNodeImpl expr = null;
359 if (peekToken(TokenKind.DOT,TokenKind.SAFE_NAVI)) {
360 expr = eatDottedNode();
361 }
362 else {
363 expr = maybeEatNonDottedNode();
364 }
365
366 if (expr==null) {
367 return false;
368 }
369 else {
370 push(expr);
371 return true;
372 }
373 }
374
375
376 private SpelNodeImpl maybeEatNonDottedNode() {
377 if (peekToken(TokenKind.LSQUARE)) {
378 if (maybeEatIndexer()) {
379 return pop();
380 }
381 }
382 return null;
383 }
384
385
386
387
388
389
390
391
392
393
394 private SpelNodeImpl eatDottedNode() {
395 Token t = nextToken();
396 boolean nullSafeNavigation = t.kind == TokenKind.SAFE_NAVI;
397 if (maybeEatMethodOrProperty(nullSafeNavigation) || maybeEatFunctionOrVar()
398 || maybeEatProjection(nullSafeNavigation)
399 || maybeEatSelection(nullSafeNavigation)) {
400 return pop();
401 }
402 if (peekToken() == null) {
403
404 raiseInternalException(t.startPos, SpelMessage.OOD);
405 }
406 else {
407 raiseInternalException(t.startPos, SpelMessage.UNEXPECTED_DATA_AFTER_DOT,
408 toString(peekToken()));
409 }
410 return null;
411 }
412
413
414
415
416
417
418
419 private boolean maybeEatFunctionOrVar() {
420 if (!peekToken(TokenKind.HASH)) {
421 return false;
422 }
423 Token t = nextToken();
424 Token functionOrVariableName = eatToken(TokenKind.IDENTIFIER);
425 SpelNodeImpl[] args = maybeEatMethodArgs();
426 if (args == null) {
427 push(new VariableReference(functionOrVariableName.data, toPos(t.startPos,
428 functionOrVariableName.endPos)));
429 return true;
430 }
431
432 push(new FunctionReference(functionOrVariableName.data, toPos(t.startPos,
433 functionOrVariableName.endPos), args));
434 return true;
435 }
436
437
438 private SpelNodeImpl[] maybeEatMethodArgs() {
439 if (!peekToken(TokenKind.LPAREN)) {
440 return null;
441 }
442 List<SpelNodeImpl> args = new ArrayList<SpelNodeImpl>();
443 consumeArguments(args);
444 eatToken(TokenKind.RPAREN);
445 return args.toArray(new SpelNodeImpl[args.size()]);
446 }
447
448 private void eatConstructorArgs(List<SpelNodeImpl> accumulatedArguments) {
449 if (!peekToken(TokenKind.LPAREN)) {
450 throw new InternalParseException(new SpelParseException(this.expressionString,positionOf(peekToken()),SpelMessage.MISSING_CONSTRUCTOR_ARGS));
451 }
452 consumeArguments(accumulatedArguments);
453 eatToken(TokenKind.RPAREN);
454 }
455
456
457
458
459 private void consumeArguments(List<SpelNodeImpl> accumulatedArguments) {
460 int pos = peekToken().startPos;
461 Token next;
462 do {
463 nextToken();
464 Token t = peekToken();
465 if (t == null) {
466 raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
467 }
468 if (t.kind != TokenKind.RPAREN) {
469 accumulatedArguments.add(eatExpression());
470 }
471 next = peekToken();
472 }
473 while (next != null && next.kind == TokenKind.COMMA);
474
475 if (next == null) {
476 raiseInternalException(pos, SpelMessage.RUN_OUT_OF_ARGUMENTS);
477 }
478 }
479
480 private int positionOf(Token t) {
481 if (t == null) {
482
483
484 return this.expressionString.length();
485 }
486 return t.startPos;
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500 private SpelNodeImpl eatStartNode() {
501 if (maybeEatLiteral()) {
502 return pop();
503 }
504 else if (maybeEatParenExpression()) {
505 return pop();
506 }
507 else if (maybeEatTypeReference() || maybeEatNullReference() || maybeEatConstructorReference() ||
508 maybeEatMethodOrProperty(false) || maybeEatFunctionOrVar()) {
509 return pop();
510 }
511 else if (maybeEatBeanReference()) {
512 return pop();
513 }
514 else if (maybeEatProjection(false) || maybeEatSelection(false) || maybeEatIndexer()) {
515 return pop();
516 }
517 else if (maybeEatInlineListOrMap()) {
518 return pop();
519 }
520 else {
521 return null;
522 }
523 }
524
525
526
527 private boolean maybeEatBeanReference() {
528 if (peekToken(TokenKind.BEAN_REF)) {
529 Token beanRefToken = nextToken();
530 Token beanNameToken = null;
531 String beanName = null;
532 if (peekToken(TokenKind.IDENTIFIER)) {
533 beanNameToken = eatToken(TokenKind.IDENTIFIER);
534 beanName = beanNameToken.data;
535 }
536 else if (peekToken(TokenKind.LITERAL_STRING)) {
537 beanNameToken = eatToken(TokenKind.LITERAL_STRING);
538 beanName = beanNameToken.stringValue();
539 beanName = beanName.substring(1, beanName.length() - 1);
540 }
541 else {
542 raiseInternalException(beanRefToken.startPos,
543 SpelMessage.INVALID_BEAN_REFERENCE);
544 }
545
546 BeanReference beanReference = new BeanReference(toPos(beanNameToken) ,beanName);
547 this.constructedNodes.push(beanReference);
548 return true;
549 }
550 return false;
551 }
552
553 private boolean maybeEatTypeReference() {
554 if (peekToken(TokenKind.IDENTIFIER)) {
555 Token typeName = peekToken();
556 if (!typeName.stringValue().equals("T")) {
557 return false;
558 }
559 nextToken();
560 eatToken(TokenKind.LPAREN);
561 SpelNodeImpl node = eatPossiblyQualifiedId();
562
563
564 int dims = 0;
565 while (peekToken(TokenKind.LSQUARE, true)) {
566 eatToken(TokenKind.RSQUARE);
567 dims++;
568 }
569 eatToken(TokenKind.RPAREN);
570 this.constructedNodes.push(new TypeReference(toPos(typeName),node,dims));
571 return true;
572 }
573 return false;
574 }
575
576 private boolean maybeEatNullReference() {
577 if (peekToken(TokenKind.IDENTIFIER)) {
578 Token nullToken = peekToken();
579 if (!nullToken.stringValue().equalsIgnoreCase("null")) {
580 return false;
581 }
582 nextToken();
583 this.constructedNodes.push(new NullLiteral(toPos(nullToken)));
584 return true;
585 }
586 return false;
587 }
588
589
590 private boolean maybeEatProjection(boolean nullSafeNavigation) {
591 Token t = peekToken();
592 if (!peekToken(TokenKind.PROJECT, true)) {
593 return false;
594 }
595 SpelNodeImpl expr = eatExpression();
596 eatToken(TokenKind.RSQUARE);
597 this.constructedNodes.push(new Projection(nullSafeNavigation, toPos(t), expr));
598 return true;
599 }
600
601
602
603 private boolean maybeEatInlineListOrMap() {
604 Token t = peekToken();
605 if (!peekToken(TokenKind.LCURLY, true)) {
606 return false;
607 }
608 SpelNodeImpl expr = null;
609 Token closingCurly = peekToken();
610 if (peekToken(TokenKind.RCURLY, true)) {
611
612 expr = new InlineList(toPos(t.startPos,closingCurly.endPos));
613 }
614 else if (peekToken(TokenKind.COLON,true)) {
615 closingCurly = eatToken(TokenKind.RCURLY);
616
617 expr = new InlineMap(toPos(t.startPos,closingCurly.endPos));
618 }
619 else {
620 SpelNodeImpl firstExpression = eatExpression();
621
622
623
624
625
626 if (peekToken(TokenKind.RCURLY)) {
627 List<SpelNodeImpl> listElements = new ArrayList<SpelNodeImpl>();
628 listElements.add(firstExpression);
629 closingCurly = eatToken(TokenKind.RCURLY);
630 expr = new InlineList(toPos(t.startPos,closingCurly.endPos),listElements.toArray(new SpelNodeImpl[listElements.size()]));
631 }
632 else if (peekToken(TokenKind.COMMA, true)) {
633 List<SpelNodeImpl> listElements = new ArrayList<SpelNodeImpl>();
634 listElements.add(firstExpression);
635 do {
636 listElements.add(eatExpression());
637 }
638 while (peekToken(TokenKind.COMMA,true));
639 closingCurly = eatToken(TokenKind.RCURLY);
640 expr = new InlineList(toPos(t.startPos,closingCurly.endPos),listElements.toArray(new SpelNodeImpl[listElements.size()]));
641
642 }
643 else if (peekToken(TokenKind.COLON, true)) {
644 List<SpelNodeImpl> mapElements = new ArrayList<SpelNodeImpl>();
645 mapElements.add(firstExpression);
646 mapElements.add(eatExpression());
647 while (peekToken(TokenKind.COMMA,true)) {
648 mapElements.add(eatExpression());
649 eatToken(TokenKind.COLON);
650 mapElements.add(eatExpression());
651 }
652 closingCurly = eatToken(TokenKind.RCURLY);
653 expr = new InlineMap(toPos(t.startPos,closingCurly.endPos),mapElements.toArray(new SpelNodeImpl[mapElements.size()]));
654 }
655 else {
656 raiseInternalException(t.startPos, SpelMessage.OOD);
657 }
658 }
659 this.constructedNodes.push(expr);
660 return true;
661 }
662
663 private boolean maybeEatIndexer() {
664 Token t = peekToken();
665 if (!peekToken(TokenKind.LSQUARE, true)) {
666 return false;
667 }
668 SpelNodeImpl expr = eatExpression();
669 eatToken(TokenKind.RSQUARE);
670 this.constructedNodes.push(new Indexer(toPos(t), expr));
671 return true;
672 }
673
674 private boolean maybeEatSelection(boolean nullSafeNavigation) {
675 Token t = peekToken();
676 if (!peekSelectToken()) {
677 return false;
678 }
679 nextToken();
680 SpelNodeImpl expr = eatExpression();
681 if (expr == null) {
682 raiseInternalException(toPos(t), SpelMessage.MISSING_SELECTION_EXPRESSION);
683 }
684 eatToken(TokenKind.RSQUARE);
685 if (t.kind == TokenKind.SELECT_FIRST) {
686 this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.FIRST, toPos(t), expr));
687 }
688 else if (t.kind == TokenKind.SELECT_LAST) {
689 this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.LAST, toPos(t), expr));
690 }
691 else {
692 this.constructedNodes.push(new Selection(nullSafeNavigation, Selection.ALL, toPos(t), expr));
693 }
694 return true;
695 }
696
697
698
699
700
701 private SpelNodeImpl eatPossiblyQualifiedId() {
702 LinkedList<SpelNodeImpl> qualifiedIdPieces = new LinkedList<SpelNodeImpl>();
703 Token node = peekToken();
704 while (isValidQualifiedId(node)) {
705 nextToken();
706 if (node.kind != TokenKind.DOT) {
707 qualifiedIdPieces.add(new Identifier(node.stringValue(),toPos(node)));
708 }
709 node = peekToken();
710 }
711 if (qualifiedIdPieces.isEmpty()) {
712 if (node == null) {
713 raiseInternalException( this.expressionString.length(), SpelMessage.OOD);
714 }
715 raiseInternalException(node.startPos, SpelMessage.NOT_EXPECTED_TOKEN,
716 "qualified ID", node.getKind().toString().toLowerCase());
717 }
718 int pos = toPos(qualifiedIdPieces.getFirst().getStartPosition(), qualifiedIdPieces.getLast().getEndPosition());
719 return new QualifiedIdentifier(pos, qualifiedIdPieces.toArray(new SpelNodeImpl[qualifiedIdPieces.size()]));
720 }
721
722 private boolean isValidQualifiedId(Token node) {
723 if (node == null || node.kind == TokenKind.LITERAL_STRING) {
724 return false;
725 }
726 if (node.kind == TokenKind.DOT || node.kind == TokenKind.IDENTIFIER) {
727 return true;
728 }
729 String value = node.stringValue();
730 return (StringUtils.hasLength(value) && VALID_QUALIFIED_ID_PATTERN.matcher(value).matches());
731 }
732
733
734
735 private boolean maybeEatMethodOrProperty(boolean nullSafeNavigation) {
736 if (peekToken(TokenKind.IDENTIFIER)) {
737 Token methodOrPropertyName = nextToken();
738 SpelNodeImpl[] args = maybeEatMethodArgs();
739 if (args==null) {
740
741 push(new PropertyOrFieldReference(nullSafeNavigation, methodOrPropertyName.data,toPos(methodOrPropertyName)));
742 return true;
743 }
744
745 push(new MethodReference(nullSafeNavigation, methodOrPropertyName.data, toPos(methodOrPropertyName), args));
746
747 return true;
748 }
749 return false;
750 }
751
752
753
754 private boolean maybeEatConstructorReference() {
755 if (peekIdentifierToken("new")) {
756 Token newToken = nextToken();
757 SpelNodeImpl possiblyQualifiedConstructorName = eatPossiblyQualifiedId();
758 List<SpelNodeImpl> nodes = new ArrayList<SpelNodeImpl>();
759 nodes.add(possiblyQualifiedConstructorName);
760 if (peekToken(TokenKind.LSQUARE)) {
761
762 List<SpelNodeImpl> dimensions = new ArrayList<SpelNodeImpl>();
763 while (peekToken(TokenKind.LSQUARE,true)) {
764 if (!peekToken(TokenKind.RSQUARE)) {
765 dimensions.add(eatExpression());
766 }
767 else {
768 dimensions.add(null);
769 }
770 eatToken(TokenKind.RSQUARE);
771 }
772 if (maybeEatInlineListOrMap()) {
773 nodes.add(pop());
774 }
775 push(new ConstructorReference(toPos(newToken), dimensions.toArray(new SpelNodeImpl[dimensions.size()]),
776 nodes.toArray(new SpelNodeImpl[nodes.size()])));
777 }
778 else {
779
780 eatConstructorArgs(nodes);
781
782 push(new ConstructorReference(toPos(newToken),
783 nodes.toArray(new SpelNodeImpl[nodes.size()])));
784 }
785 return true;
786 }
787 return false;
788 }
789
790 private void push(SpelNodeImpl newNode) {
791 this.constructedNodes.push(newNode);
792 }
793
794 private SpelNodeImpl pop() {
795 return this.constructedNodes.pop();
796 }
797
798
799
800
801
802
803
804
805
806 private boolean maybeEatLiteral() {
807 Token t = peekToken();
808 if (t == null) {
809 return false;
810 }
811 if (t.kind == TokenKind.LITERAL_INT) {
812 push(Literal.getIntLiteral(t.data, toPos(t), 10));
813 }
814 else if (t.kind == TokenKind.LITERAL_LONG) {
815 push(Literal.getLongLiteral(t.data, toPos(t), 10));
816 }
817 else if (t.kind == TokenKind.LITERAL_HEXINT) {
818 push(Literal.getIntLiteral(t.data, toPos(t), 16));
819 }
820 else if (t.kind == TokenKind.LITERAL_HEXLONG) {
821 push(Literal.getLongLiteral(t.data, toPos(t), 16));
822 }
823 else if (t.kind == TokenKind.LITERAL_REAL) {
824 push(Literal.getRealLiteral(t.data, toPos(t), false));
825 }
826 else if (t.kind == TokenKind.LITERAL_REAL_FLOAT) {
827 push(Literal.getRealLiteral(t.data, toPos(t), true));
828 }
829 else if (peekIdentifierToken("true")) {
830 push(new BooleanLiteral(t.data, toPos(t), true));
831 }
832 else if (peekIdentifierToken("false")) {
833 push(new BooleanLiteral(t.data, toPos(t), false));
834 }
835 else if (t.kind == TokenKind.LITERAL_STRING) {
836 push(new StringLiteral(t.data, toPos(t), t.data));
837 }
838 else {
839 return false;
840 }
841 nextToken();
842 return true;
843 }
844
845
846 private boolean maybeEatParenExpression() {
847 if (peekToken(TokenKind.LPAREN)) {
848 nextToken();
849 SpelNodeImpl expr = eatExpression();
850 eatToken(TokenKind.RPAREN);
851 push(expr);
852 return true;
853 }
854 else {
855 return false;
856 }
857 }
858
859
860
861
862 private Token maybeEatRelationalOperator() {
863 Token t = peekToken();
864 if (t == null) {
865 return null;
866 }
867 if (t.isNumericRelationalOperator()) {
868 return t;
869 }
870 if (t.isIdentifier()) {
871 String idString = t.stringValue();
872 if (idString.equalsIgnoreCase("instanceof")) {
873 return t.asInstanceOfToken();
874 }
875 if (idString.equalsIgnoreCase("matches")) {
876 return t.asMatchesToken();
877 }
878 if (idString.equalsIgnoreCase("between")) {
879 return t.asBetweenToken();
880 }
881 }
882 return null;
883 }
884
885 private Token eatToken(TokenKind expectedKind) {
886 Token t = nextToken();
887 if (t == null) {
888 raiseInternalException( this.expressionString.length(), SpelMessage.OOD);
889 }
890 if (t.kind != expectedKind) {
891 raiseInternalException(t.startPos, SpelMessage.NOT_EXPECTED_TOKEN,
892 expectedKind.toString().toLowerCase(), t.getKind().toString().toLowerCase());
893 }
894 return t;
895 }
896
897 private boolean peekToken(TokenKind desiredTokenKind) {
898 return peekToken(desiredTokenKind,false);
899 }
900
901 private boolean peekToken(TokenKind desiredTokenKind, boolean consumeIfMatched) {
902 if (!moreTokens()) {
903 return false;
904 }
905 Token t = peekToken();
906 if (t.kind == desiredTokenKind) {
907 if (consumeIfMatched) {
908 this.tokenStreamPointer++;
909 }
910 return true;
911 }
912
913 if (desiredTokenKind == TokenKind.IDENTIFIER) {
914
915
916 if (t.kind.ordinal() >= TokenKind.DIV.ordinal() && t.kind.ordinal() <= TokenKind.NOT.ordinal() && t.data != null) {
917
918 return true;
919 }
920 }
921 return false;
922 }
923
924 private boolean peekToken(TokenKind possible1,TokenKind possible2) {
925 if (!moreTokens()) {
926 return false;
927 }
928 Token t = peekToken();
929 return (t.kind == possible1 || t.kind == possible2);
930 }
931
932 private boolean peekToken(TokenKind possible1,TokenKind possible2, TokenKind possible3) {
933 if (!moreTokens()) {
934 return false;
935 }
936 Token t = peekToken();
937 return t.kind == possible1 || t.kind == possible2 || t.kind == possible3;
938 }
939
940 private boolean peekIdentifierToken(String identifierString) {
941 if (!moreTokens()) {
942 return false;
943 }
944 Token t = peekToken();
945 return t.kind == TokenKind.IDENTIFIER && t.stringValue().equalsIgnoreCase(identifierString);
946 }
947
948 private boolean peekSelectToken() {
949 if (!moreTokens()) {
950 return false;
951 }
952 Token t = peekToken();
953 return t.kind == TokenKind.SELECT || t.kind == TokenKind.SELECT_FIRST
954 || t.kind == TokenKind.SELECT_LAST;
955 }
956
957 private boolean moreTokens() {
958 return this.tokenStreamPointer<this.tokenStream.size();
959 }
960
961 private Token nextToken() {
962 if (this.tokenStreamPointer >= this.tokenStreamLength) {
963 return null;
964 }
965 return this.tokenStream.get(this.tokenStreamPointer++);
966 }
967
968 private Token peekToken() {
969 if (this.tokenStreamPointer >= this.tokenStreamLength) {
970 return null;
971 }
972 return this.tokenStream.get(this.tokenStreamPointer);
973 }
974
975 private void raiseInternalException(int pos, SpelMessage message, Object... inserts) {
976 throw new InternalParseException(new SpelParseException(this.expressionString, pos, message, inserts));
977 }
978
979 public String toString(Token t) {
980 if (t.getKind().hasPayload()) {
981 return t.stringValue();
982 }
983 return t.kind.toString().toLowerCase();
984 }
985
986 private void checkOperands(Token token, SpelNodeImpl left, SpelNodeImpl right) {
987 checkLeftOperand(token, left);
988 checkRightOperand(token, right);
989 }
990
991 private void checkLeftOperand(Token token, SpelNodeImpl operandExpression) {
992 if (operandExpression==null) {
993 raiseInternalException(token.startPos, SpelMessage.LEFT_OPERAND_PROBLEM);
994 }
995 }
996
997 private void checkRightOperand(Token token, SpelNodeImpl operandExpression) {
998 if (operandExpression == null) {
999 raiseInternalException(token.startPos, SpelMessage.RIGHT_OPERAND_PROBLEM);
1000 }
1001 }
1002
1003
1004
1005
1006 private int toPos(Token t) {
1007 return (t.startPos<<16) + t.endPos;
1008 }
1009
1010 private int toPos(int start,int end) {
1011 return (start<<16) + end;
1012 }
1013
1014 }