📄 fmparser.jj
字号:
|
<ELSE_IF : <START_TAG> "elseif" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<LIST : <START_TAG> "list" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<FOREACH : <START_TAG> "foreach" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<SWITCH : <START_TAG> "switch" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<CASE : <START_TAG> "case" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<ASSIGN : <START_TAG> "assign" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<GLOBALASSIGN : <START_TAG> "global" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<LOCALASSIGN : <START_TAG> "local" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<INCLUDE : <START_TAG> "include" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<IMPORT : <START_TAG> "import" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<FUNCTION : <START_TAG> "function" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<MACRO : <START_TAG> "macro" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<TRANSFORM : <START_TAG> "transform" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<VISIT : <START_TAG> "visit" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<STOP : <START_TAG> "stop" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<RETURN : <START_TAG> "return" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<CALL : <START_TAG> "call" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<SETTING : <START_TAG> "setting" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<COMPRESS : <START_TAG> "compress" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<COMMENT : <START_TAG> "comment" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, NO_PARSE); noparseTag="comment";}
|
<TERSE_COMMENT : ("<" | "[") "#--" > {noparseTag = "-->"; strictSyntaxCheck(matchedToken, NO_PARSE); }
|
<NOPARSE : <START_TAG> "noparse" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, NO_PARSE); noparseTag="noparse";}
|
<END_IF : <END_TAG> "if" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_LIST : <END_TAG> "list" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_RECOVER : <END_TAG> "recover" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_ATTEMPT : <END_TAG> "attempt" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_FOREACH : <END_TAG> "foreach" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_LOCAL : <END_TAG> "local" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_GLOBAL : <END_TAG> "global" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_ASSIGN : <END_TAG> "assign" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_FUNCTION : <END_TAG> "function" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_MACRO : <END_TAG> "macro" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_COMPRESS : <END_TAG> "compress" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_TRANSFORM : <END_TAG> "transform" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_SWITCH : <END_TAG> "switch" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<ELSE : <START_TAG> "else" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<BREAK : <START_TAG> "break" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<SIMPLE_RETURN : <START_TAG> "return" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<HALT : <START_TAG> "stop" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<FLUSH : <START_TAG> "flush" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<TRIM : <START_TAG> "t" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<LTRIM : <START_TAG> "lt" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<RTRIM : <START_TAG> "rt" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<NOTRIM : <START_TAG> "nt" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<DEFAUL : <START_TAG> "default" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<SIMPLE_NESTED : <START_TAG> "nested" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<NESTED : <START_TAG> "nested" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<SIMPLE_RECURSE : <START_TAG> "recurse" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<RECURSE : <START_TAG> "recurse" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<FALLBACK : <START_TAG> "fallback" <CLOSE_TAG2>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<ESCAPE : <START_TAG> "escape" <BLANK>> {strictSyntaxCheck(matchedToken, FM_EXPRESSION);}
|
<END_ESCAPE : <END_TAG> "escape" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<NOESCAPE : <START_TAG> "noescape" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<END_NOESCAPE : <END_TAG> "noescape" <CLOSE_TAG1>> {strictSyntaxCheck(matchedToken, DEFAULT);}
|
<UNIFIED_CALL : "<@" | "[@" > {unifiedCall(matchedToken);}
|
<UNIFIED_CALL_END : ("<" | "[") "/@" ((<ID>) ("."<ID>)*)? <CLOSE_TAG1>> {unifiedCallEnd(matchedToken);}
|
<FTL_HEADER : ("<#ftl" | "[#ftl") <BLANK>> {ftlHeader(matchedToken);}
|
<TRIVIAL_FTL_HEADER : ("<#ftl" | "[#ftl") ("/")? (">" | "]")> {ftlHeader(matchedToken);}
|
<UNKNOWN_DIRECTIVE : ("[#" | "[/#" | "<#" | "</#") (["a"-"z","A"-"Z", "_"])+>
{
if (!directiveSyntaxEstablished) {
matchedToken.kind = PRINTABLE_CHARS;
} else {
char firstChar = matchedToken.image.charAt(0);
if (firstChar == '<' && altDirectiveSyntax) {
matchedToken.kind = PRINTABLE_CHARS;
} else if (firstChar == '[' && !altDirectiveSyntax) {
matchedToken.kind = PRINTABLE_CHARS;
}
else if (strictEscapeSyntax) {
String s = matchedToken.image;
int index = s.indexOf('#');
s = s.substring(index);
String msg = "Unknown directive: "
+ s
+ " on line: " + matchedToken.beginLine
+ ", column: " + matchedToken.beginColumn +1
+ ", in template: " + templateName;
throw new TokenMgrError(msg, TokenMgrError.LEXICAL_ERROR);
}
}
}
}
<DEFAULT, NODIRECTIVE> TOKEN :
{
<WHITESPACE : (["\n", "\r", "\t", " "])+>
|
<PRINTABLE_CHARS : (~["$", "<", "#", "[", "{", "\n", "\r", "\t", " "])+>
|
<FALSE_ALERT : "$" | "#" | "<" | "[" | "{"> // to handle a lone dollar sign or "<" or "# or <@ with whitespace after"
|
<OUTPUT_ESCAPE : "${"> : FM_EXPRESSION
|
<NUMERICAL_ESCAPE : "#{"> : FM_EXPRESSION
}
<FM_EXPRESSION, IN_PAREN> SKIP :
{
< ( " " | "\t" | "\n" | "\r" )+ >
|
< ["<", "["] ["#", "!"] "--"> : EXPRESSION_COMMENT
}
<EXPRESSION_COMMENT> SKIP:
{
< (~["-", ">", "]"])+ >
|
< ">">
|
< "]">
|
< "-">
|
< "-->" | "--]"> {if (parenthesisNesting >0) SwitchTo(IN_PAREN); else SwitchTo(FM_EXPRESSION);}
}
<FM_EXPRESSION, IN_PAREN, NO_SPACE_EXPRESSION> TOKEN :
{
<#ESCAPED_CHAR : "\\"
(
["n","t","r","f","b","g","l","a","\\","'","\"","$"]
|
("x" ["0"-"9","A"-"F","a"-"f"])
)
>
|
<STRING_LITERAL :
("\""
((~["\"","\\"]) | <ESCAPED_CHAR>)*
"\"")
|
("'"
((~["'","\\"]) | <ESCAPED_CHAR>)*
"'"
)
>
|
<RAW_STRING : "r" (("\"" (~["\""])* "\"") | ("'" (~["'"])* "'"))>
|
<FALSE : "false">
|
<TRUE : "true">
|
<INTEGER : (["0"-"9"])+>
|
<DECIMAL : <INTEGER> "." <INTEGER>>
|
<DOT : ".">
|
<DOT_DOT : "..">
|
<BUILT_IN : "?">
|
<EXISTS : "??">
|
<EQUALS : "=">
|
<DOUBLE_EQUALS : "==">
|
<NOT_EQUALS : "!=">
|
<LESS_THAN : "lt" | "\\lt" | "<" | "<">
|
<LESS_THAN_EQUALS : "lte" | "\\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 : "["> {++bracketNesting;}
|
<CLOSE_BRACKET : "]"> {closeBracket(matchedToken);}
|
<OPEN_PAREN : "(">
{
++parenthesisNesting;
if (parenthesisNesting == 1)
SwitchTo(IN_PAREN);
}
|
<CLOSE_PAREN : ")">
{
--parenthesisNesting;
if (parenthesisNesting == 0)
SwitchTo(FM_EXPRESSION);
}
|
<OPEN_BRACE : "{" > {++hashLiteralNesting;}
|
<CLOSE_BRACE : "}" >
{
if (hashLiteralNesting == 0)
SwitchTo(DEFAULT);
else
--hashLiteralNesting;
}
|
< IN : "in">
|
< AS : "as">
|
< USING : "using">
|
< ID: <LETTER> (<LETTER>|<DIGIT>)* >
|
< #LETTER:
[
"\u0024",
"\u0040"-"\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"
]
>
}
<FM_EXPRESSION, NO_SPACE_EXPRESSION> TOKEN :
{
<DIRECTIVE_END : ">">
{
if (inFTLHeader) eatNewline();
inFTLHeader = false;
if (altDirectiveSyntax) {
matchedToken.kind = NATURAL_GT;
} else {
SwitchTo(DEFAULT);
}
}
|
<EMPTY_DIRECTIVE_END : "/>" | "/]"> {if (inFTLHeader) eatNewline(); inFTLHeader = false; SwitchTo(DEFAULT);}
}
<IN_PAREN> TOKEN :
{
<NATURAL_GT : ">">
|
<NATURAL_GTE : ">=">
}
<NO_SPACE_EXPRESSION> TOKEN :
{
<TERMINATING_WHITESPACE : (["\n", "\r", "\t", " "])+> : FM_EXPRESSION
}
<NO_PARSE> TOKEN :
{
<TERSE_COMMENT_END : "-->" | "--]">
{
if (noparseTag.equals("-->")) {
boolean squareBracket = matchedToken.image.endsWith("]");
if ((altDirectiveSyntax && squareBracket) || (!altDirectiveSyntax && !squareBracket))
SwitchTo(DEFAULT);
}
}
|
<MAYBE_END :
("<" | "[")
"/"
("#")?
(["a"-"z", "A"-"Z"])+
( " " | "\t" | "\n" | "\r" )*
(">" | "]")
>
{
StringTokenizer st = new StringTokenizer(image.toString(),
" \t\n\r<>[]/#",
false);
if (st.nextToken().equals(noparseTag)) {
SwitchTo(DEFAULT);
}
}
|
<KEEP_GOING : (~["<", "[", "-"])+>
|
<LONE_LESS_THAN_OR_DASH : ["<", "[", "-"]>
}
// Now the actual parsing code, starting
// with the productions for FreeMarker's
// expression syntax.
/**
* This is the same as OrExpression, since
* the OR is the operator with the lowest
* precedence.
*/
Expression Expression() :
{
Expression exp;
}
{
exp=OrExpression()
{
return exp;
}
}
/**
* Lowest level expression, a literal, a variable,
* or a possibly more complex expression bounded
* by parentheses.
*/
Expression PrimaryExpression() :
{
Expression exp;
}
{
(
exp=NumberLiteral()
|
exp=HashLiteral()
|
exp=StringLiteral(true)
|
exp=BooleanLiteral()
|
exp=ListLiteral()
|
exp=Identifier()
|
exp=Parenthesis()
|
exp=BuiltinVariable()
)
(
LOOKAHEAD(<DOT>
|<OPEN_BRACKET>
|<OPEN_PAREN>
|<BUILT_IN>
|<EXCLAM>
|<EXISTS>)
exp=AddSubExpression(exp)
)*
{
return exp;
}
}
Expression Parenthesis() :
{
Expression exp, result;
Token start, end;
}
{
start=<OPEN_PAREN>
exp=Expression()
end=<CLOSE_PAREN>
{
result = new ParentheticalExpression(exp);
result.setLocation(template, start, end);
return result;
}
}
/**
* A primary expression preceded by zero or
* more unary operators. (The only unary operator we
* currently have is the NOT.)
*/
Expression UnaryExpression() :
{
Expression exp, result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -