Implements #2383 Add syntax modes for FreeMarker template language #2847
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Woah, test cases got really large, much larger than the implementation...
Adds syntax highlighting support for Apache FreeMarker, resolves #2383. Includes tests and samples for the website.
freemarker2
since FreeMarker 3 will most likely change the syntaxfreemarker2.tag-*.interpolation-*
. It also adds the modefreemarker2
, which is an alias forfreemarker2.tag-angle.interpolation-dollar
, the default mode when using FreeMarker via the Java API.(from the source code comment)
The grammar for FreeMarker 2.x. This tokenizer is intentionally limited to FreeMarker 2 as the next release FreeMarker 3 is a breaking change that will change the syntax, see:
https://cwiki.apache.org/confluence/display/FREEMARKER/FreeMarker+3
FreeMarker does not just have one grammar, it has 6 (!) different syntaxes.
These can be combined, resulting in 3*2=6 syntaxes. There's another tag syntax, but that one is legacy and therefore ignored by this tokenizer.
<#if true>...</#if>
[#if true]...[/#if]
Dollar interpolation syntax is like
${1+2}
, bracket syntax like[=1+2]
.To prevent duplicate code, there are factory functions that take a syntax mode and dynamically create the tokenizer for that mode. This does not affect performance since the tokenizer is created only once.
Auto mode is implemented via parser states. Each parser state exists three times, one for each tag syntax mode (e.g.
default.auto
,default.angle
,default.bracket
). Auto mode starts indefault.auto
and switches todefault.angle
ordefault.bracket
when it encounters the first directive.FreeMarker allows expressions within strings (
a${1+2}b
), but these are impossible to tokenize. String interpolation is not implemented via a mode change when encountering${
. Rather, FreeMarker tokenizes the string as a literal string first. Then, during the AST build phase, it creates a new parses and parses the unescaped string content.This is adapted from the official JavaCC grammar for FreeMarker: https://github.com/apache/freemarker/blob/2.3-gae/src/main/javacc/FTL.jj
Taken from the above file, a short rundown of the basic parser states:
It should be noted that there are another parser state not mentioned in the above excerpt: NO_DIRECTIVE is used as the initial starting state when parsing the contents of a string literal, which is allowed to contain interpolations, but no directives. However, note that FreeMarker first tokenizes a string literal as-is, then during the parsing stage, it takes the (unescaped) content of the string literal, and tokenizes + parses that content with a new child parser.