// Now the actual parsing code, starting // with the productions for FreeMarker's // expression syntax. /** * An Expression production with error recovery * The start Token is the token just before the expression * we are trying to parse, the recoverToType is * the kind of token to scan ahead for to recover from * errors, and the boolean consumeToken * says whether to consume the recoverToken or not. */ | ||
Expression | ::= | OrExpression |
Exp | ::= | OrExpression |
KeepGoingUntil | ::= | java code |
/** * Lowest level expression, a literal, a variable, * or a possibly more complex expression bounded * by parentheses. */ | ||
PrimaryExpression | ::= | ( NumberLiteral | HashLiteral | StringLiteral | BooleanLiteral | NullLiteral | ListLiteral | Identifier | Parenthesis | BuiltinVariable ) ( AddSubExpression )* |
Parenthesis | ::= | <OPEN_PAREN> Expression <CLOSE_PAREN> |
/** * A primary expression preceded by zero or * more unary operators. */ | ||
UnaryExpression | ::= | ( UnaryPlusMinusExpression | NotExpression | PrimaryExpression ) |
NotExpression | ::= | ( <EXCLAM> )+ PrimaryExpression |
UnaryPlusMinusExpression | ::= | ( <PLUS> | <MINUS> ) PrimaryExpression |
AdditiveExpression | ::= | MultiplicativeExpression ( ( ( <PLUS> | <MINUS> ) ) MultiplicativeExpression )* |
/** * A unary expression followed by zero or more * unary expressions with operators in between. */ | ||
MultiplicativeExpression | ::= | UnaryExpression ( ( <TIMES> | <DIVIDE> | <PERCENT> ) UnaryExpression )* |
EqualityExpression | ::= | RelationalExpression ( ( <NOT_EQUALS> | <EQUALS> | <DOUBLE_EQUALS> ) RelationalExpression )? |
RelationalExpression | ::= | RangeExpression ( ( <GREATER_THAN_EQUALS> | <ESCAPED_GTE> | <GREATER_THAN> | <ESCAPED_GT> | <LESS_THAN_EQUALS> | <LESS_THAN> ) RangeExpression )? |
RangeExpression | ::= | AdditiveExpression ( <DOT_DOT> ( AdditiveExpression )? )? |
AndExpression | ::= | EqualityExpression ( <AND> EqualityExpression )* |
OrExpression | ::= | AndExpression ( <OR> AndExpression )* |
ListLiteral | ::= | <OPEN_BRACKET> ( Exp ( ( <COMMA> )? Exp )* )? <CLOSE_BRACKET> |
NumberLiteral | ::= | ( <INTEGER> | <DECIMAL> ) |
Identifier | ::= | <ID> |
IdentifierOrStringLiteral | ::= | ( Identifier | StringLiteral ) |
BuiltinVariable | ::= | <DOT> <ID> |
/** * Production that builds up an expression * using the dot or dynamic key name * or the args list if this is a method invocation. */ | ||
AddSubExpression | ::= | ( DotVariable | DynamicKey | MethodArgs | BuiltIn | Exists | DefaultTo ) |
DefaultTo | ::= | ( <EXCLAM> ( PrimaryExpression )? ) |
Exists | ::= | <EXISTS> |
BuiltIn | ::= | <BUILT_IN> <ID> |
/** * production for when a key is specified by <DOT> + keyname */ | ||
DotVariable | ::= | <DOT> <ID> |
/** * production for when the key is specified * in brackets. */ | ||
DynamicKey | ::= | <OPEN_BRACKET> Exp <CLOSE_BRACKET> |
/** * production for an arglist part of a method invocation. */ | ||
MethodArgs | ::= | <OPEN_PAREN> ( ArgsList )? <CLOSE_PAREN> |
StringLiteral | ::= | ( <STRING_LITERAL> | <RAW_STRING> ) |
BooleanLiteral | ::= | ( <FALSE> | <TRUE> ) |
NullLiteral | ::= | <NULL> |
HashLiteral | ::= | <OPEN_BRACE> ( Exp ( <COMMA> | <COLON> ) Exp ( <COMMA> Exp ( <COMMA> | <COLON> ) Exp )* )? <CLOSE_BRACE> |
/** * A production representing the ${...} * that outputs a variable. */ | ||
StringOutput | ::= | <OUTPUT_ESCAPE> Expression <CLOSE_BRACE> |
NumericalOutput | ::= | <NUMERICAL_ESCAPE> Exp ( <SEMICOLON> <ID> )? <CLOSE_BRACE> |
If | ::= | <IF> Exp <DIRECTIVE_END> OptionalBlock ( <ELSE_IF> Exp LooseDirectiveEnd OptionalBlock )* ( <ELSE> OptionalBlock )? CloseDirectiveBlock |
Attempt | ::= | <ATTEMPT> OptionalBlock Recover CloseDirectiveBlock |
Recover | ::= | <RECOVER> OptionalBlock |
List | ::= | <LIST> Expression <AS> <ID> <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock |
ForEach | ::= | <FOREACH> <ID> <IN> Exp <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock |
Visit | ::= | <VISIT> Exp ( <USING> Exp )? LooseDirectiveEnd |
Recurse | ::= | ( <SIMPLE_RECURSE> | ( <RECURSE> ( Exp )? ( <USING> Exp )? LooseDirectiveEnd ) ) |
FallBack | ::= | <FALLBACK> |
/** * Production used to break out of a loop or a switch block. */ | ||
Break | ::= | <BREAK> |
/** * Production used to jump out of a macro. * The stop instruction terminates the rendering of the template. */ | ||
Return | ::= | ( <SIMPLE_RETURN> | <RETURN> Exp LooseDirectiveEnd ) |
Stop | ::= | ( <HALT> | <STOP> Exp LooseDirectiveEnd ) |
Nested | ::= | ( ( <SIMPLE_NESTED> )| ( <NESTED> PositionalArgsList LooseDirectiveEnd ) ) |
Flush | ::= | <FLUSH> |
Trim | ::= | ( <TRIM> | <LTRIM> | <RTRIM> | <NOTRIM> ) |
Assign | ::= | ( <ASSIGN> | <GLOBALASSIGN> | <LOCALASSIGN> | <SET> ) IdentifierOrStringLiteral ( ( <EQUALS> Exp ( ( <COMMA> )? IdentifierOrStringLiteral <EQUALS> Exp )* ( <IN> Exp )? LooseDirectiveEnd )| ( ( <IN> Exp )? <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock ) ) |
Include | ::= | ( <_INCLUDE> | <EMBED> ) Exp ( <SEMICOLON> )? ( <ID> <EQUALS> Exp )* LooseDirectiveEnd |
Import | ::= | <IMPORT> Exp <AS> <ID> LooseDirectiveEnd |
ParameterList | ::= | ( <ID> ( <ELLIPSIS> )? ( <EQUALS> Exp )? ( <COMMA> )? )* |
Param | ::= | <PARAM> IdentifierOrStringLiteral ( <OPEN_PAREN> )? ParameterList ( <CLOSE_PAREN> )? ( <EMPTY_DIRECTIVE_END> | ( <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock ) ) |
Macro | ::= | ( <MACRO> | <FUNCTION> ) IdentifierOrStringLiteral ( <OPEN_PAREN> )? ParameterList ( <CLOSE_PAREN> )? <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock |
Compress | ::= | <COMPRESS> OptionalBlock CloseDirectiveBlock |
PositionalArgsList | ::= | Exp ( ( <COMMA> )? Exp )* |
NamedArgsList | ::= | <ID> <EQUALS> Exp ( ( <COMMA> )? <ID> <EQUALS> Exp )* |
ArgsList | ::= | ( NamedArgsList | PositionalArgsList ) |
UnifiedMacroTransform | ::= | <UNIFIED_CALL> Exp ( <TERMINATING_WHITESPACE> )? ( ArgsList )? ( <SEMICOLON> ( <TERMINATING_WHITESPACE> )? ParameterList )? ( <EMPTY_DIRECTIVE_END> | ( <DIRECTIVE_END> OptionalBlock <UNIFIED_CALL_END> ) ) |
Call | ::= | <CALL> Identifier ( <OPEN_PAREN> )? ArgsList ( <CLOSE_PAREN> )? LooseDirectiveEnd |
NamedArgs | ::= | ( <ID> <EQUALS> Exp )+ |
TerseComment | ::= | <TERSE_COMMENT> ( <PRINTABLE_CHARS> )* <TERSE_COMMENT_END> |
Comment | ::= | <COMMENT> ( <PRINTABLE_CHARS> )* <COMMENT_END> |
NoParse | ::= | <NOPARSE> ( <PRINTABLE_CHARS> )* <NOPARSE_END> |
Transform | ::= | <TRANSFORM> Exp ( <SEMICOLON> )? ( <ID> <EQUALS> Exp )* ( <EMPTY_DIRECTIVE_END> | ( <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock ) ) |
Switch | ::= | <SWITCH> Exp <DIRECTIVE_END> ( <WHITESPACE> | Comment )* ( Case )* CloseDirectiveBlock |
Case | ::= | ( <CASE> Exp <DIRECTIVE_END> | <DEFAUL> ) OptionalBlock |
TrimBlock | ::= | ( <BLOCKTRIM> | <BLOCKTRIML> | <BLOCKTRIMR> | <BLOCKNOTRIM> ) OptionalBlock CloseDirectiveBlock |
Escape | ::= | <ESCAPE> <ID> <AS> Exp <DIRECTIVE_END> OptionalBlock CloseDirectiveBlock |
NoEscape | ::= | <NOESCAPE> OptionalBlock CloseDirectiveBlock |
CloseDirectiveBlock | ::= | <CLOSE_DIRECTIVE_BLOCK> |
/** * Production to terminate potentially empty elements. Either a ">" or "/>" */ | ||
LooseDirectiveEnd | ::= | ( <DIRECTIVE_END> | <EMPTY_DIRECTIVE_END> ) |
Setting | ::= | <SETTING> <ID> <EQUALS> Exp LooseDirectiveEnd |
Var | ::= | <VAR> ( IdentifierOrStringLiteral ( <EQUALS> Exp )? ) ( ( ( <COMMA> )? IdentifierOrStringLiteral ( <EQUALS> Exp )? ) )* LooseDirectiveEnd |
/** * A production for FreeMarker directives. */ | ||
FreemarkerDirective | ::= | ( If | List | ForEach | Assign | Include | Import | Macro | Compress | UnifiedMacroTransform | Call | TerseComment | Comment | NoParse | Transform | Switch | Setting | Var | Break | Return | Stop | Flush | Trim | Nested | Escape | NoEscape | TrimBlock | Visit | Recurse | FallBack | Attempt ) |
/** * Production for a block of raw text * i.e. text that contains no * FreeMarker directives. */ | ||
PCData | ::= | ( ( <PRINTABLE_CHARS> | <WHITESPACE> ) )+ |
/** * Production for dealing with unparsed content, * i.e. what is inside a comment or noparse tag. * It returns the ending token. The content * of the tag is put in buf. */ | ||
Content | ::= | ( ( PCData | StringOutput | NumericalOutput | FreemarkerDirective ) )+ |
/** * A production freemarker text that may contain * ${...} and #{...} but no directives. */ | ||
FreeMarkerText | ::= | ( ( PCData | StringOutput | NumericalOutput ) )+ |
/** * A production for a block of optional content. * Returns an empty Text block if there is no * content. */ | ||
OptionalBlock | ::= | ( Content )? |
HeaderElement | ::= | ( <WHITESPACE> )? ( <TRIVIAL_FTL_HEADER> | ( <FTL_HEADER> ( <ID> <EQUALS> Exp )* LooseDirectiveEnd ) ) |
ParamList | ::= | ( Identifier <EQUALS> Exp ( <COMMA> )? )+ |
/** * Root production to be used when parsing * an entire file. */ | ||
Root | ::= | ( HeaderElement )? OptionalBlock <EOF> |
<DEFAULT> TOKEN : { <CLOSE_DIRECTIVE_BLOCK: "[/#" (~["]"])* "]" | "</#" (~[">"])* ">"> |<ATTEMPT: <START_TAG> "attempt" <CLOSE_TAG1>> |<RECOVER: <START_TAG> "recover" <CLOSE_TAG1>> |<BLOCKTRIM: <START_TAG> "t_lines" <CLOSE_TAG1>> |<BLOCKTRIML: <START_TAG> "lt_lines" <CLOSE_TAG2>> |<BLOCKTRIMR: <START_TAG> "rt_lines" <CLOSE_TAG1>> |<BLOCKNOTRIM: <START_TAG> "nt_lines" <CLOSE_TAG1>> |<IF: <START_TAG> "if" <BLANK>> |<ELSE_IF: <START_TAG> "elseif" <BLANK>> |<LIST: <START_TAG> "list" <BLANK>> |<FOREACH: <START_TAG> "foreach" <BLANK>> |<SWITCH: <START_TAG> "switch" <BLANK>> |<CASE: <START_TAG> "case" <BLANK>> |<ASSIGN: <START_TAG> "assign" <BLANK>> |<GLOBALASSIGN: <START_TAG> "global" <BLANK>> |<LOCALASSIGN: <START_TAG> "local" <BLANK>> |<SET: <START_TAG> "set" <BLANK>> |<_INCLUDE: <START_TAG> "include" <BLANK>> |<IMPORT: <START_TAG> "import" <BLANK>> |<FUNCTION: <START_TAG> "function" <BLANK>> |<MACRO: <START_TAG> "macro" <BLANK>> |<PARAM: <START_TAG> "param" <BLANK>> |<TRANSFORM: <START_TAG> "transform" <BLANK>> |<VISIT: <START_TAG> "visit" <BLANK>> |<STOP: <START_TAG> "stop" <BLANK>> |<RETURN: <START_TAG> "return" <BLANK>> |<CALL: <START_TAG> "call" <BLANK>> |<SETTING: <START_TAG> "setting" <BLANK>> |<EMBED: <START_TAG> "embed" <BLANK>> |<VAR: <START_TAG> "var" <BLANK>> |<COMPRESS: <START_TAG> "compress" <CLOSE_TAG1>> |<COMMENT: <START_TAG> "comment" <CLOSE_TAG1>> |<TERSE_COMMENT: ("<" | "[") "#--"> |<NOPARSE: <START_TAG> "noparse" <CLOSE_TAG1>> |<ELSE: <START_TAG> "else" <CLOSE_TAG2>> |<BREAK: <START_TAG> "break" <CLOSE_TAG2>> |<SIMPLE_RETURN: <START_TAG> "return" <CLOSE_TAG2>> |<HALT: <START_TAG> "stop" <CLOSE_TAG2>> |<FLUSH: <START_TAG> "flush" <CLOSE_TAG2>> |<TRIM: <START_TAG> "t" <CLOSE_TAG2>> |<LTRIM: <START_TAG> "lt" <CLOSE_TAG2>> |<RTRIM: <START_TAG> "rt" <CLOSE_TAG2>> |<NOTRIM: <START_TAG> "nt" <CLOSE_TAG2>> |<DEFAUL: <START_TAG> "default" <CLOSE_TAG1>> |<SIMPLE_NESTED: <START_TAG> "nested" <CLOSE_TAG2>> |<NESTED: <START_TAG> "nested" <BLANK>> |<SIMPLE_RECURSE: <START_TAG> "recurse" <CLOSE_TAG2>> |<RECURSE: <START_TAG> "recurse" <BLANK>> |<FALLBACK: <START_TAG> "fallback" <CLOSE_TAG2>> |<ESCAPE: <START_TAG> "escape" <BLANK>> |<NOESCAPE: <START_TAG> "noescape" <CLOSE_TAG1>> |<UNIFIED_CALL: "<@" | "[@"> |<UNIFIED_CALL_END: ("<" | "[") "/@" ((<ID>) ("." <ID>)*)? <CLOSE_TAG1>> |<FTL_HEADER: ("<#ftl" | "[#ftl") <BLANK>> |<TRIVIAL_FTL_HEADER: ("<#ftl" | "[#ftl") ("/")? (">" | "]")> |<UNKNOWN_DIRECTIVE: ("[#" | "[/#" | "<#" | "</#") (["a"-"z","A"-"Z","_"])+> } |
<DEFAULT, NODIRECTIVE> TOKEN : { <WHITESPACE: (["\t"," ","\r","\n"])+> |<PRINTABLE_CHARS: "$" | "#" | "<" | "[" | "{" | (~["$","<","#","[","{","\n","\r","\t"," "])+> |<OUTPUT_ESCAPE: "${"> |<NUMERICAL_ESCAPE: "#{"> } |
<EXPRESSION> SKIP : { <(" " | "\t" | "\n" | "\r")+> |<["<","["] ["#","!"] "--"> } |
<EXPRESSION_COMMENT> SKIP : { <~[]> |"-->" |"--]" } |
<EXPRESSION, NO_SPACE_EXPRESSION> TOKEN : { <STRING_LITERAL: "\"" (~["\\","\""] | "\\" ~[])* "\"" | "\'" (~["\\","\'"] | "\\" ~[])* "\'"> |<RAW_STRING: "r" ("\"" (~["\""])* "\"" | "\'" (~["\'"])* "\'")> |<FALSE: "false"> |<TRUE: "true"> |<NULL: "null"> |<INTEGER: (["0"-"9"])+> |<DECIMAL: <INTEGER> "." <INTEGER>> |<DOT: "."> |<DOT_DOT: ".."> |<BUILT_IN: "?"> |<EXISTS: "??"> |<EQUALS: "="> |<DOUBLE_EQUALS: "=="> |<NOT_EQUALS: "!="> |<GREATER_THAN: ">"> |<GREATER_THAN_EQUALS: ">="> |<EMPTY_DIRECTIVE_END: "/>" | "/]"> |<LESS_THAN: "lt" | "<" | "<"> |<LESS_THAN_EQUALS: "lte" | "<=" | "<="> |<ESCAPED_GT: "gt" | "\\gt" | ">"> |<ESCAPED_GTE: "gte" | "\\gte" | ">="> |<PLUS: "+"> |<MINUS: "-"> |<TIMES: "*"> |<DOUBLE_STAR: "**"> |<ELLIPSIS: "..."> |<DIVIDE: "/"> |<PERCENT: "%"> |<AND: "&" | "&&"> |<OR: "|" | "||"> |<EXCLAM: "!"> |<COMMA: ","> |<SEMICOLON: ";"> |<COLON: ":"> |<OPEN_BRACKET: "["> |<CLOSE_BRACKET: "]"> |<OPEN_PAREN: "("> |<CLOSE_PAREN: ")"> |<OPEN_BRACE: "{"> |<CLOSE_BRACE: "}"> |<IN: "in"> |<AS: "as"> |<USING: "using"> |<ID: <LETTER> (<LETTER> | <DIGIT>)*> |} |
<NO_SPACE_EXPRESSION> TOKEN : { <TERMINATING_WHITESPACE: (["\n","\r","\t"," "])+> } |
<EXPRESSION, NO_SPACE_EXPRESSION> TOKEN : { <UNEXPECTED: ~[]> } |
<NO_PARSE> MORE : { <~[]> } |
<NO_PARSE> TOKEN : { <TERSE_COMMENT_END: "-->" | "--]"> |<COMMENT_END: "</#comment" (<BLANK>)* ">" | "[/#comment" (<BLANK>)* "]"> |<NOPARSE_END: "</#noparse" (<BLANK>)* ">" | "[/#noparse" (<BLANK>)* "]"> } |
<PHONY> TOKEN : { <DIRECTIVE_END: ">" | "]"> } |