BNF for FTLParser

NON-TERMINALS


Input ::= Expression <EOF>

Expression ::= OrExpression

OrExpression ::= AndExpression ( ( <OR> | <OR2> ) AndExpression )*

AndExpression ::= EqualityExpression ( ( <AND> | <AND2> ) EqualityExpression )*

EqualityExpression ::= RelationalExpression ( ( <EQUALS> | <DOUBLE_EQUALS> | <NOT_EQUALS> ) RelationalExpression )?

RelationalExpression ::= RangeExpression ( ( <GT> | <GTE> | <LT> | <LTE> | <ALT_GT> | <ALT_GTE> | <ALT_LTE> | <ALT_LT> ) RangeExpression )?

RangeExpression ::= AdditiveExpression ( <DOT_DOT> ( AdditiveExpression )? )?

AdditiveExpression ::= MultiplicativeExpression ( ( <PLUS> | <MINUS> ) MultiplicativeExpression )*

MultiplicativeExpression ::= UnaryExpression ( ( <TIMES> | <DIVIDE> | <PERCENT> ) UnaryExpression )*


UnaryExpression ::= UnaryPlusMinusExpression | NotExpression | DefaultToExpression

UnaryPlusMinusExpression ::= ( <PLUS> | <MINUS> ) DefaultToExpression

NotExpression ::= <EXCLAM> DefaultToExpression

BuiltinVariable ::= <DOT> <IDENTIFIER>

DefaultToExpression ::= PrimaryExpression ( <EXCLAM> PrimaryExpression )* ( <EXCLAM> )?

PrimaryExpression ::= BaseExpression ( ( DotKey | DynamicKey | MethodInvoke | BuiltIn | Exists ))*

BaseExpression ::= <IDENTIFIER> | NumberLiteral | HashLiteral | StringLiteral | BooleanLiteral | NullLiteral | ListLiteral | Parenthesis | BuiltinVariable


DotKey ::= <DOT> ( <IDENTIFIER> | <TIMES> )

DynamicKey ::= <OPEN_BRACKET> Expression <CLOSE_BRACKET>

MethodInvoke ::= <OPEN_PAREN> ( ArgsList )? <CLOSE_PAREN>

BuiltIn ::= <BUILT_IN> <IDENTIFIER>

Exists ::= <EXISTS_OPERATOR>

ListLiteral ::= <OPEN_BRACKET> ( Expression ( ( <COMMA> )? Expression )* )? <CLOSE_BRACKET>

StringLiteral ::= <STRING_LITERAL> | <RAW_STRING>


HashLiteral ::= <OPEN_BRACE> ( Expression <COLON> Expression ( <COMMA> Expression <COLON> Expression )* )? <CLOSE_BRACE>

NumberLiteral ::= <INTEGER> | <DECIMAL>

BooleanLiteral ::= <TRUE> | <FALSE>

NullLiteral ::= <NULL>

Parenthesis ::= <OPEN_PAREN> Expression <CLOSE_PAREN>

ArgsList ::= ( NamedArgsList | PositionalArgsList )

NamedArgsList ::= <IDENTIFIER> <EQUALS> Expression ( ( <COMMA> )? <IDENTIFIER> <EQUALS> Expression )*

PositionalArgsList ::= Expression ( ( <COMMA> )? Expression )*

IdentifierOrStringLiteral ::= <IDENTIFIER> | StringLiteral


Interpolation ::= <INTERPOLATE> Expression <CLOSE_BRACE>

NumericalInterpolation ::= <NUMERICAL_INTERPOLATE> Expression ( <SEMICOLON> <IDENTIFIER> )? <CLOSE_BRACE>


Assignment ::= <FTL_DIRECTIVE_OPEN> ( <SET> | <ASSIGN> | <LOCAL> | <GLOBAL> ) <BLANK> IdentifierOrStringLiteral ( ( <EQUALS> Expression ( ( <COMMA> )? IdentifierOrStringLiteral <EQUALS> Expression )* ( <IN> Expression )? LooseTagEnd )| ( ( <IN> Expression )? <CLOSE_TAG> Block DirectiveEnd ) )

Var ::= <FTL_DIRECTIVE_OPEN> <VAR> <BLANK> IdentifierOrStringLiteral ( <EQUALS> Expression )? ( ( <COMMA> )? IdentifierOrStringLiteral ( <EQUALS> Expression )? )* LooseTagEnd

Setting ::= <FTL_DIRECTIVE_OPEN> <SETTING> <BLANK> <IDENTIFIER> ( <EQUALS> Expression )? ( ( <COMMA> )? IdentifierOrStringLiteral ( <EQUALS> Expression )? )* LooseTagEnd

Attempt ::= <FTL_DIRECTIVE_OPEN> <ATTEMPT> <CLOSE_TAG> Block Recover

Comment ::= <FTL_DIRECTIVE_OPEN> <COMMENT> <END_COMMENT>

NoParse ::= <FTL_DIRECTIVE_OPEN> <NOPARSE> <CLOSE_TAG> <NOPARSE_END>



Trim ::= <FTL_DIRECTIVE_OPEN> <TRIM> LooseTagEnd


NoTrim ::= <FTL_DIRECTIVE_OPEN> <NOTRIM> LooseTagEnd


RightTrim ::= <FTL_DIRECTIVE_OPEN> <RTRIM> LooseTagEnd


LeftTrim ::= <FTL_DIRECTIVE_OPEN> <LTRIM> LooseTagEnd

Break ::= <FTL_DIRECTIVE_OPEN> <BREAK> LooseTagEnd

Flush ::= <FTL_DIRECTIVE_OPEN> <FLUSH> LooseTagEnd

Return ::= <FTL_DIRECTIVE_OPEN> <RETURN> ( <BLANK> Expression )? LooseTagEnd

Stop ::= <FTL_DIRECTIVE_OPEN> <STOP> ( <BLANK> Expression )? LooseTagEnd


Compress ::= <FTL_DIRECTIVE_OPEN> <COMPRESS> <CLOSE_TAG> Block DirectiveEnd

TrimBlock ::= <FTL_DIRECTIVE_OPEN> ( <BLOCKTRIM> | <BLOCKTRIML> | <BLOCKTRIMR> | <BLOCKNOTRIM> ) <CLOSE_TAG> Block DirectiveEnd

NoEscapeBlock ::= <FTL_DIRECTIVE_OPEN> <NOESCAPE> <CLOSE_TAG> Block DirectiveEnd

EscapeBlock ::= <FTL_DIRECTIVE_OPEN> <ESCAPE> <BLANK> <IDENTIFIER> <AS> Expression <CLOSE_TAG> Block DirectiveEnd

Include ::= <FTL_DIRECTIVE_OPEN> <_INCLUDE> <BLANK> Expression ( <SEMICOLON> )? ( <IDENTIFIER> <EQUALS> Expression )* LooseTagEnd

Embed ::= <FTL_DIRECTIVE_OPEN> <EMBED> <BLANK> Expression LooseTagEnd

Import ::= <FTL_DIRECTIVE_OPEN> <IMPORT> <BLANK> Expression <AS> <IDENTIFIER> LooseTagEnd

Visit ::= <FTL_DIRECTIVE_OPEN> <VISIT> <BLANK> Expression ( <USING> Expression ( ( <COMMA> )? Expression )* )? LooseTagEnd

Recurse ::= <FTL_DIRECTIVE_OPEN> <RECURSE> ( LooseTagEnd | ( <BLANK> ( Expression )? ( <USING> Expression ( ( <COMMA> )? Expression )* )? LooseTagEnd ) )

FallBack ::= <FTL_DIRECTIVE_OPEN> <FALLBACK> LooseTagEnd

If ::= <FTL_DIRECTIVE_OPEN> <IF> <BLANK> Expression <CLOSE_TAG> Block ( ElseIf )* ( Else )? DirectiveEnd

ElseIf ::= <FTL_DIRECTIVE_OPEN> <ELSEIF> <BLANK> Expression <CLOSE_TAG> Block

Else ::= <FTL_DIRECTIVE_OPEN> <ELSE> <CLOSE_TAG> Block

Switch ::= <FTL_DIRECTIVE_OPEN> <SWITCH> <BLANK> Expression <CLOSE_TAG> ( <WHITESPACE> )? ( Case )* ( Default )? DirectiveEnd

Case ::= <FTL_DIRECTIVE_OPEN> <CASE> <BLANK> Expression <CLOSE_TAG> Block

Default ::= <FTL_DIRECTIVE_OPEN> <DEFAUL> <CLOSE_TAG> Block

List ::= <FTL_DIRECTIVE_OPEN> <LIST> <BLANK> Expression <AS> <IDENTIFIER> <CLOSE_TAG> Block DirectiveEnd

ForEach ::= <FTL_DIRECTIVE_OPEN> <FOREACH> <BLANK> <IDENTIFIER> <IN> Expression <CLOSE_TAG> Block DirectiveEnd

Nested ::= <FTL_DIRECTIVE_OPEN> <NESTED> ( <BLANK> PositionalArgsList )? LooseTagEnd

MacroDefinition ::= <FTL_DIRECTIVE_OPEN> ( <MACRO> | <FUNCTION> ) <BLANK> IdentifierOrStringLiteral ( <OPEN_PAREN> )? ( ParameterList )? ( <CLOSE_PAREN> )? <CLOSE_TAG> Block DirectiveEnd

ParameterList ::= <IDENTIFIER> ( ( <EQUALS> Expression )| <ELLIPSIS> )? ( ( <COMMA> )? <IDENTIFIER> ( ( <EQUALS> Expression )| <ELLIPSIS> )? )*


LooseTagEnd ::= <CLOSE_TAG> | <CLOSE_EMPTY_TAG>

DirectiveEnd ::= <END_DIRECTIVE>

Text ::= ( ( <PRINTABLE_CHARS> | <WHITESPACE> | <SPECIAL_CHAR> ))+


Recover ::= <FTL_DIRECTIVE_OPEN> <RECOVER> <CLOSE_TAG> Block DirectiveEnd

TopLevelDirective ::= ( Assignment | Attempt | Comment | Compress | Embed | ForEach | If | List | Include | Import | MacroDefinition | NoParse | Switch | Setting | Var | Break | Return | Stop | Flush | Trim | NoTrim | LeftTrim | RightTrim | TrimBlock | Nested | EscapeBlock | NoEscapeBlock | Visit | Recurse | FallBack )

UserDirective ::= <USER_DIRECTIVE_OPEN> Expression ( <BLANK> )? ( ArgsList )? ( <SEMICOLON> ( ParameterList )? )? ( <CLOSE_EMPTY_TAG> | ( <CLOSE_TAG> Block EndUserDirective ) )

EndUserDirective ::= <END_USER_DIRECTIVE>

Block ::= ( ( Text | Interpolation | NumericalInterpolation | UserDirective | TopLevelDirective ))*

FTLHeader ::= <FTL_DIRECTIVE_OPEN> <FTL> ( <BLANK> ( <IDENTIFIER> <EQUALS> Expression )* )? ( <CLOSE_TAG> | <CLOSE_EMPTY_TAG> )



Root ::= ( ( <WHITESPACE> )? FTLHeader )? Block <EOF>

TOKENS

<FTL_EXPRESSION> SKIP : { 
<EXP_WHITE_SPACE: (" " | "\t" | "\n" | "\r")+>
}

<FTL_EXPRESSION> MORE : { 
"<#--"
|"<!--"
|"[#--"
}

<EXPRESSION_COMMENT> MORE : { 
<~[]>
}

<EXPRESSION_COMMENT> SPECIAL_TOKEN : { 
"-->"
|"--]"
}

<FTL_EXPRESSION> TOKEN : { 
<OPEN_PAREN: "(">
|<CLOSE_PAREN: ")">
|<OPEN_BRACKET: "[">
|<CLOSE_BRACKET: "]">
|<OPEN_BRACE: "{">
|<CLOSE_BRACE: "}">
|<EQUALS: "=">
|<DOT: ".">
|<PLUS: "+">
|<MINUS: "-">
|<TIMES: "*">
|<DIVIDE: "/">
|<PERCENT: "%">
|<OR: "|">
|<AND: "&">
|<LT: "<">
|<GT: ">">
|<COMMA: ",">
|<COLON: ":">
|<SEMICOLON: ";">
|<EXCLAM: "!">
|<BUILT_IN: "?">
|<DOUBLE_EQUALS: "==">
|<NOT_EQUALS: "!=">
|<EXISTS_OPERATOR: "??">
|<LTE: "<=">
|<GTE: ">=">
|<OR2: "||">
|<AND2: "&&">
|<DOT_DOT: "..">
|<ALT_GT: "gt">
|<ALT_LT: "lt">
|<AS: "as">
|<IN: "in">
|<ALT_GTE: "gte">
|<ALT_LTE: "lte">
|<ELLIPSIS: "...">
|<NULL: "null">
|<TRUE: "true">
|<FALSE: "false">
|<USING: "using">
|<INTEGER: (["0"-"9"])+>
|<DECIMAL: <INTEGER> "." <INTEGER>>
|<IDENTIFIER: <LETTER> (<LETTER> | <DIGIT>)*>
|<STRING_LITERAL: "\"" (~["\\","\""] | "\\" ~[])* "\"" | "\'" (~["\\","\'"] | "\\" ~[])* "\'">
|<RAW_STRING: "r" ("\"" (~["\""])* "\"" | "\'" (~["\'"])* "\'")>
}

<TEMPLATE_TEXT> TOKEN : { 
<FTL_DIRECTIVE_OPEN: "<#" | "[#">
|<USER_DIRECTIVE_OPEN: "<@" | "[@">
|<INTERPOLATE: "${">
|<NUMERICAL_INTERPOLATE: "#{">
|<WHITESPACE: (["\n","\r","\t"," "])+>
|<SPECIAL_CHAR: "$" | "<" | "[">
|<PRINTABLE_CHARS: (~["$","<","[","\n","\r","\t"," "])+>
|<END_DIRECTIVE: <END_DIRECTIVE1> | <END_DIRECTIVE2>>
|<END_USER_DIRECTIVE: <END_USER_DIRECTIVE1> | <END_USER_DIRECTIVE2>>
|}

<FTL_DIRECTIVE> TOKEN : { 
<TRIM: "t">
|<COMMENT: "--">
|<LTRIM: "lt">
|<RTRIM: "rt">
|<NOTRIM: "nt">
|<IF: "if">
|<FTL: "ftl">
|<SET: "set">
|<VAR: "var">
|<LIST: "list">
|<ELSE: "else">
|<STOP: "stop">
|<CASE: "case">
|<MACRO: "macro">
|<LOCAL: "local">
|<FLUSH: "flush">
|<BREAK: "break">
|<EMBED: "embed">
|<NESTED: "nested">
|<VISIT: "visit">
|<SWITCH: "switch">
|<IMPORT: "import">
|<DEFAUL: "default">
|<RETURN: "return">
|<GLOBAL: "global">
|<ASSIGN: "assign">
|<ELSEIF: "elseif">
|<ESCAPE: "escape">
|<RECURSE: "recurse">
|<FUNCTION: "function">
|<FALLBACK: "fallback">
|<NOESCAPE: "noescape">
|<SETTING: "setting">
|<NOPARSE: "noparse">
|<_INCLUDE: "include">
|<ATTEMPT: "attempt">
|<FOREACH: "foreach">
|<RECOVER: "recover">
|<COMPRESS: "compress">
|<BLOCKTRIM: "t_lines">
|<BLOCKTRIML: "lt_lines">
|<BLOCKTRIMR: "rt_lines">
|<BLOCKNOTRIM: "nt_lines">
|<BLANK: "\n" | "\r" | "\t" | " ">
|<CLOSE_TAG: (<BLANK>)* (">" | "]")>
}

<FTL_DIRECTIVE, FTL_EXPRESSION> TOKEN : { 
<CLOSE_EMPTY_TAG: (<BLANK>)* "/" (">" | "]")>
}

<IN_COMMENT> MORE : { 
<~[]>
}

<IN_COMMENT> TOKEN : { 
<END_COMMENT: "-->" | "--]">
}

<NO_PARSE> MORE : { 
<~[]>
}

<NO_PARSE> TOKEN : { 
<NOPARSE_END: "</#noparse" (<BLANK>)* ">" | "[/#noparse" (<BLANK>)* "]">
}