Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
587 lines (541 sloc) 11.6 KB
/*
* 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(3)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: (~[]) >
}
You can’t perform that action at this time.