Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
587 lines (541 sloc)
11.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. See the NOTICE file distributed with | |
* this work for additional information regarding copyright ownership. | |
* The ASF licenses this file to You 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: Jacob Hookom | |
Email: jacob at hookom.net | |
*/ | |
/* == Option Declaration == */ | |
options | |
{ | |
STATIC=false; | |
NODE_PREFIX="Ast"; | |
VISITOR_EXCEPTION="jakarta.el.ELException"; | |
VISITOR=false; | |
MULTI=true; | |
NODE_DEFAULT_VOID=true; | |
JAVA_UNICODE_ESCAPE=false; | |
UNICODE_INPUT=true; | |
BUILD_NODE_FILES=true; | |
} | |
/* == Parser Declaration == */ | |
PARSER_BEGIN( ELParser ) | |
package org.apache.el.parser; | |
import java.io.StringReader; | |
import jakarta.el.ELException; | |
public class ELParser { | |
public static Node parse(String ref) throws ELException { | |
try { | |
return new ELParser(new StringReader(ref)).CompositeExpression(); | |
} catch (ParseException pe) { | |
throw new ELException(pe.getMessage()); | |
} | |
} | |
} | |
PARSER_END( ELParser ) | |
/* | |
* CompositeExpression | |
* Allow most flexible parsing, restrict by examining | |
* type of returned node | |
*/ | |
AstCompositeExpression CompositeExpression() #CompositeExpression : {} | |
{ | |
(DeferredExpression() | | |
DynamicExpression() | | |
LiteralExpression())* <EOF> { return jjtThis; } | |
} | |
/* | |
* LiteralExpression | |
* Non-EL Expression blocks | |
*/ | |
void LiteralExpression() #LiteralExpression : { Token t = null; } | |
{ | |
t=<LITERAL_EXPRESSION> { jjtThis.setImage(t.image); } | |
} | |
/* | |
* DeferredExpression | |
* #{...} Expressions | |
*/ | |
void DeferredExpression() #DeferredExpression : {} | |
{ | |
<START_DEFERRED_EXPRESSION> Expression() <RBRACE> | |
} | |
/* | |
* DynamicExpression | |
* ${...} Expressions | |
*/ | |
void DynamicExpression() #DynamicExpression : {} | |
{ | |
<START_DYNAMIC_EXPRESSION> Expression() <RBRACE> | |
} | |
/* | |
* Expression | |
* EL Expression Language Root | |
*/ | |
void Expression() : {} | |
{ | |
Semicolon() | |
} | |
/* | |
* Semicolon | |
*/ | |
void Semicolon() : {} | |
{ | |
Assignment() ( <SEMICOLON> Assignment() #Semicolon(2) )* | |
} | |
/* | |
* Assignment | |
*/ | |
void Assignment() : {} | |
{ | |
LOOKAHEAD(4) LambdaExpression() | | |
Choice() ( LOOKAHEAD(2) <ASSIGN> Assignment() #Assign(2) )* | |
} | |
/* | |
* Lambda expression | |
*/ | |
void LambdaExpression() #LambdaExpression : {} | |
{ | |
LambdaParameters() <ARROW> ( LOOKAHEAD(3) LambdaExpression() | Choice() ) | |
} | |
/* | |
* Lambda parameters | |
*/ | |
void LambdaParameters() #LambdaParameters : {} | |
{ | |
Identifier() | <LPAREN> ( Identifier() ( <COMMA> Identifier() )* )? <RPAREN> | |
} | |
/* | |
* Possible invocation of lambda expression. Invocations must be bracketed but | |
* being bracketed does not mean it is an invocation. | |
*/ | |
void LambdaExpressionOrInvocation() #LambdaExpression : {} | |
{ | |
<LPAREN> | |
LambdaParameters() | |
<ARROW> | |
( LOOKAHEAD(3) LambdaExpression() | Choice() ) | |
<RPAREN> | |
( MethodParameters() )* | |
} | |
/* | |
* Choice | |
* For Choice markup a ? b : c, then Or | |
*/ | |
void Choice() : {} | |
{ | |
Or() (LOOKAHEAD(3) <QUESTIONMARK> Choice() <COLON> Choice() #Choice(3))* | |
} | |
/* | |
* Or | |
* For 'or' '||', then And | |
*/ | |
void Or() : {} | |
{ | |
And() ((<OR0>|<OR1>) And() #Or(2))* | |
} | |
/* | |
* And | |
* For 'and' '&&', then Equality | |
*/ | |
void And() : {} | |
{ | |
Equality() ((<AND0>|<AND1>) Equality() #And(2))* | |
} | |
/* | |
* Equality | |
* For '==' 'eq' '!=' 'ne', then Compare | |
*/ | |
void Equality() : {} | |
{ | |
Compare() | |
( | |
((<EQ0>|<EQ1>) Compare() #Equal(2)) | |
| | |
((<NE0>|<NE1>) Compare() #NotEqual(2)) | |
)* | |
} | |
/* | |
* Compare | |
* For a bunch of them, then += | |
*/ | |
void Compare() : {} | |
{ | |
Concatenation() | |
( | |
((<LT0>|<LT1>) Concatenation() #LessThan(2)) | |
| | |
((<GT0>|<GT1>) Concatenation() #GreaterThan(2)) | |
| | |
((<LE0>|<LE1>) Concatenation() #LessThanEqual(2)) | |
| | |
((<GE0>|<GE1>) Concatenation() #GreaterThanEqual(2)) | |
)* | |
} | |
/* | |
* Concatenation | |
* For +=, then Math | |
* | |
*/ | |
void Concatenation() : {} | |
{ | |
Math() | |
( | |
<CONCAT> Math() #Concatenation(2) | |
)* | |
} | |
/* | |
* Math | |
* For '+' '-', then Multiplication | |
*/ | |
void Math() : {} | |
{ | |
Multiplication() | |
( | |
(<PLUS> Multiplication() #Plus(2)) | |
| | |
(<MINUS> Multiplication() #Minus(2)) | |
)* | |
} | |
/* | |
* Multiplication | |
* For a bunch of them, then Unary | |
*/ | |
void Multiplication() : {} | |
{ | |
Unary() | |
( | |
(<MULT> Unary() #Mult(2)) | |
| | |
((<DIV0>|<DIV1>) Unary() #Div(2)) | |
| | |
((<MOD0>|<MOD1>) Unary() #Mod(2)) | |
)* | |
} | |
/* | |
* Unary | |
* For '-' '!' 'not' 'empty', then Value | |
*/ | |
void Unary() : {} | |
{ | |
<MINUS> Unary() #Negative | |
| | |
(<NOT0>|<NOT1>) Unary() #Not | |
| | |
<EMPTY> Unary() #Empty | |
| | |
Value() | |
} | |
/* | |
* Value | |
* Defines Prefix plus zero or more Suffixes | |
*/ | |
void Value() : {} | |
{ | |
(ValuePrefix() (ValueSuffix())*) #Value(>1) | |
} | |
/* | |
* ValuePrefix | |
* For Literals, Variables, and Functions | |
*/ | |
void ValuePrefix() : {} | |
{ | |
Literal() | |
| NonLiteral() | |
} | |
/* | |
* ValueSuffix | |
* Either dot or bracket notation | |
*/ | |
void ValueSuffix() : {} | |
{ | |
( DotSuffix() | BracketSuffix() ) ( MethodParameters())? | |
} | |
/* | |
* DotSuffix | |
* Dot Property | |
*/ | |
void DotSuffix() #DotSuffix : { Token t = null; } | |
{ | |
<DOT> t=<IDENTIFIER> { jjtThis.setImage(t.image); } | |
} | |
/* | |
* BracketSuffix | |
* Sub Expression Suffix | |
*/ | |
void BracketSuffix() #BracketSuffix : {} | |
{ | |
<LBRACK> Expression() <RBRACK> | |
} | |
/* | |
* MethodParameters | |
*/ | |
void MethodParameters() #MethodParameters : {} | |
{ | |
<LPAREN> ( Expression() ( <COMMA> Expression())* )? <RPAREN> | |
} | |
/* | |
* NonLiteral | |
* For Grouped Operations, Identifiers, and Functions | |
*/ | |
void NonLiteral() : {} | |
{ | |
LOOKAHEAD(5) LambdaExpressionOrInvocation() | |
| <LPAREN> Expression() <RPAREN> | |
| LOOKAHEAD((<IDENTIFIER> <COLON>)? <IDENTIFIER> <LPAREN>) Function() | |
| Identifier() | |
| LOOKAHEAD(5)SetData() | |
| ListData() | |
| MapData() | |
} | |
/* | |
* Note that both an empty Set and an empty Map are represented by {}. The | |
* parser will always parse {} as an empty Set and special handling is required | |
* to convert it to an empty Map when appropriate. | |
*/ | |
void SetData() #SetData: {} | |
{ | |
<START_SET_OR_MAP> | |
( Expression() ( <COMMA> Expression() )* )? | |
<RBRACE> | |
} | |
void ListData() #ListData: {} | |
{ | |
<LBRACK> | |
( Expression() ( <COMMA> Expression() )* )? | |
<RBRACK> | |
} | |
/* | |
* Note that both an empty Set and an empty Map are represented by {}. The | |
* parser will always parse {} as an empty Set and special handling is required | |
* to convert it to an empty Map when appropriate. | |
*/ | |
void MapData() #MapData: {} | |
{ | |
<START_SET_OR_MAP> | |
( MapEntry() ( <COMMA> MapEntry() )* )? | |
<RBRACE> | |
} | |
void MapEntry() #MapEntry: {} | |
{ | |
Expression() <COLON> Expression() | |
} | |
/* | |
* Identifier | |
* Java Language Identifier | |
*/ | |
void Identifier() #Identifier : { Token t = null; } | |
{ | |
t=<IDENTIFIER> { jjtThis.setImage(t.image); } | |
} | |
/* | |
* Function | |
* Namespace:Name(a,b,c) | |
*/ | |
void Function() #Function : | |
{ | |
Token t0 = null; | |
Token t1 = null; | |
} | |
{ | |
t0=<IDENTIFIER> ( <COLON> t1=<IDENTIFIER> )? | |
{ | |
if (t1 != null) { | |
jjtThis.setPrefix(t0.image); | |
jjtThis.setLocalName(t1.image); | |
} else { | |
jjtThis.setLocalName(t0.image); | |
} | |
} | |
( MethodParameters() )+ | |
} | |
/* | |
* Literal | |
* Reserved Keywords | |
*/ | |
void Literal() : {} | |
{ | |
Boolean() | |
| FloatingPoint() | |
| Integer() | |
| String() | |
| Null() | |
} | |
/* | |
* Boolean | |
* For 'true' 'false' | |
*/ | |
void Boolean() : {} | |
{ | |
<TRUE> #True | |
| <FALSE> #False | |
} | |
/* | |
* FloatingPoint | |
* For Decimal and Floating Point Literals | |
*/ | |
void FloatingPoint() #FloatingPoint : { Token t = null; } | |
{ | |
t=<FLOATING_POINT_LITERAL> { jjtThis.setImage(t.image); } | |
} | |
/* | |
* Integer | |
* For Simple Numeric Literals | |
*/ | |
void Integer() #Integer : { Token t = null; } | |
{ | |
t=<INTEGER_LITERAL> { jjtThis.setImage(t.image); } | |
} | |
/* | |
* String | |
* For Quoted Literals | |
*/ | |
void String() #String : { Token t = null; } | |
{ | |
t=<STRING_LITERAL> { jjtThis.setImage(t.image); } | |
} | |
/* | |
* Null | |
* For 'null' | |
*/ | |
void Null() #Null : {} | |
{ | |
<NULL> | |
} | |
/* ========================================================================== */ | |
TOKEN_MGR_DECLS: | |
{ | |
java.util.Deque<Integer> deque = new java.util.ArrayDeque<Integer>(); | |
} | |
<DEFAULT> TOKEN : | |
{ | |
/* | |
* The following definition uses + rather than * in two places to prevent | |
* LITERAL_EXPRESSION matching the empty string that could result in the | |
* Parser entering an infinite loop. | |
*/ | |
< LITERAL_EXPRESSION: | |
( (~["$", "#", "\\"])* "\\" (["$", "#"])? | |
| (~["$", "#"])* (["$", "#"] ~["{", "$", "#", "\\"]) | |
| (~["$", "#"])+ | |
)+ | |
| "$" | |
| "#" | |
> | |
| | |
< START_DYNAMIC_EXPRESSION: "${" > {deque.push(DEFAULT);}: IN_EXPRESSION | |
| | |
< START_DEFERRED_EXPRESSION: "#{" > {deque.push(DEFAULT);}: IN_EXPRESSION | |
} | |
<IN_EXPRESSION, IN_SET_OR_MAP> SKIP : { " " | "\t" | "\n" | "\r" } | |
<IN_EXPRESSION, IN_SET_OR_MAP> TOKEN : | |
{ | |
< START_SET_OR_MAP : "{" > {deque.push(curLexState);}: IN_SET_OR_MAP | |
| < RBRACE: "}" > {SwitchTo(deque.pop());} | |
| < INTEGER_LITERAL: ["0"-"9"] (["0"-"9"])* > | |
| < FLOATING_POINT_LITERAL: (["0"-"9"])+ "." (["0"-"9"])* (<EXPONENT>)? | |
| "." (["0"-"9"])+ (<EXPONENT>)? | |
| (["0"-"9"])+ <EXPONENT> | |
> | |
| < #EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > | |
| < STRING_LITERAL: ("\"" ((~["\"","\\"]) | |
| ("\\" ( ["\\","\"","\'"] )))* "\"") | |
| ("\'" ((~["\'","\\"]) | |
| ("\\" ( ["\\","\"","\'"] )))* "\'") | |
> | |
| < TRUE : "true" > | |
| < FALSE : "false" > | |
| < NULL : "null" > | |
| < DOT : "." > | |
| < LPAREN : "(" > | |
| < RPAREN : ")" > | |
| < LBRACK : "[" > | |
| < RBRACK : "]" > | |
| < COLON : ":" > | |
| < SEMICOLON : ";" > | |
| < COMMA : "," > | |
| < GT0 : ">" > | |
| < GT1 : "gt" > | |
| < LT0 : "<" > | |
| < LT1 : "lt" > | |
| < GE0 : ">=" > | |
| < GE1 : "ge" > | |
| < LE0 : "<=" > | |
| < LE1 : "le" > | |
| < EQ0 : "==" > | |
| < EQ1 : "eq" > | |
| < NE0 : "!=" > | |
| < NE1 : "ne" > | |
| < NOT0 : "!" > | |
| < NOT1 : "not" > | |
| < AND0 : "&&" > | |
| < AND1 : "and" > | |
| < OR0 : "||" > | |
| < OR1 : "or" > | |
| < EMPTY : "empty" > | |
| < INSTANCEOF : "instanceof" > | |
| < MULT : "*" > | |
| < PLUS : "+" > | |
| < MINUS : "-" > | |
| < QUESTIONMARK : "?" > | |
| < DIV0 : "/" > | |
| < DIV1 : "div" > | |
| < MOD0 : "%" > | |
| < MOD1 : "mod" > | |
| < CONCAT : "+=" > | |
| < ASSIGN : "=" > | |
| < ARROW : "->" > | |
| < IDENTIFIER : (<LETTER>|<IMPL_OBJ_START>) (<LETTER>|<DIGIT>)* > | |
| < FUNCTIONSUFFIX : (<IDENTIFIER>) > | |
| < #IMPL_OBJ_START: "#" > | |
| < #LETTER: | |
[ | |
"\u0024", | |
"\u0041"-"\u005a", | |
"\u005f", | |
"\u0061"-"\u007a", | |
"\u00c0"-"\u00d6", | |
"\u00d8"-"\u00f6", | |
"\u00f8"-"\u00ff", | |
"\u0100"-"\u1fff", | |
"\u3040"-"\u318f", | |
"\u3300"-"\u337f", | |
"\u3400"-"\u3d2d", | |
"\u4e00"-"\u9fff", | |
"\uf900"-"\ufaff" | |
] | |
> | |
| < #DIGIT: | |
[ | |
"\u0030"-"\u0039", | |
"\u0660"-"\u0669", | |
"\u06f0"-"\u06f9", | |
"\u0966"-"\u096f", | |
"\u09e6"-"\u09ef", | |
"\u0a66"-"\u0a6f", | |
"\u0ae6"-"\u0aef", | |
"\u0b66"-"\u0b6f", | |
"\u0be7"-"\u0bef", | |
"\u0c66"-"\u0c6f", | |
"\u0ce6"-"\u0cef", | |
"\u0d66"-"\u0d6f", | |
"\u0e50"-"\u0e59", | |
"\u0ed0"-"\u0ed9", | |
"\u1040"-"\u1049" | |
] | |
> | |
| < ILLEGAL_CHARACTER: (~[]) > | |
} |