dustjs template AST using ANTLR

http://akdubya.github.com/dustjs/ is hot lately, team starts using it with few editor support, besides, no luck running it at serverside with Rhino due to the performance.

so just took some time using antlr to generate a parser for java runtime as the following, which could be turned to semantic tree for validation, proposal and all sorts of tooling support. and obviously executable by walking this tree.

</pre>
grammar DustJs;
options {
 k=3;//modified to 4 for the sake of indexedPath implementation
 output=AST;
}
tokens {
 COMMENT;
 SPECIAL;
 FOR;
 IF;
 IFNOT;
 OVERRIDE;
 BASE;
 ADHOC;
 PARTIAL;
 REF;
 TEXT;
 CONTEXT;
 PARAM;
 FILTER;
 INLINE;
 BODIES;
 BODY;
 DOT;
 THIS;
 INDEX;
 VALUE_TEXT;
 VALUE_SPECIAL;
 VALUE_REF;
}

everything : body EOF!
 ;

body : part+ -> ^(BODY part+)
 ;

/** the main syntax breakdown, LL(2) based mainly*/
part : '{!' comment '!}' -> ^(COMMENT comment)
 | '{~' special '}' -> ^(SPECIAL special)
 | '{#' section -> ^(FOR section)
 | '{?' section -> ^(IF section)
 | '{^' section -> ^(IFNOT section)
 | '{<' section -> ^(OVERRIDE section)
 | '{+' section_or_partial -> ^(BASE section_or_partial)
 | '{@' section -> ^(ADHOC section)
 | '{>' partial WS? '/}' -> ^(PARTIAL partial)
 | '{' reference '}' -> ^(REF reference)
 | buffer -> ^(TEXT buffer)
 ;

/** the only syntax branch whose LL(2) won't fit, requires backtrack to identify section compared with partial which closes with '/}' immediately */
section_or_partial
options{
 backtrack=true;
}
 : section -> section
 | partial WS? '/}' -> partial
 ;

comment : (~('!}'))*
 ;

/** in fact KEY is a superset, there's a limited known specials, like ~n etc.*/
special : KEY
 ;

/** section is the most common block in dust, for loop, if or not check control structure; <+> partial related ones, and @for special support like index or separator etc.
 * they all have the block structure as {[#?^<+>@] path context params} body else? {/path}
 */
section : WS? path context params WS? '}'! body bodies? section_end
 ;

context : (':' path)? -> ^(CONTEXT path)?
 ;

params : (WS KEY WS? '=' WS? value)* -> ^(PARAM KEY value)*
 ;

value : NUMBER -> NUMBER
 | path -> ^(VALUE_REF path)
 | inline -> ^(INLINE inline)
 ;

section_end : '{/' WS? path WS? '}' -> //YES, EMPTIED ON PURPOSE
 ;

/** {:else} body is the only known case right now*/
bodies : '{:' KEY '}' body -> ^(BODIES KEY body)
 ;

path : '.' -> THIS
 | KEY eitherPath? -> KEY eitherPath?
 | '.' KEY eitherPath? -> THIS DOT KEY eitherPath?
 ;

eitherPath : dottedPath -> DOT dottedPath
 | indexedPath -> INDEX indexedPath
 ;

dottedPath : '.' KEY -> KEY
 | '.' KEY eitherPath -> KEY eitherPath
 ;

indexedPath : '[' indexer -> indexer
 ;

indexer : NUMBER ']' eitherPath? -> NUMBER eitherPath?
 ;

/** partial supports base/child inheritance and overwrites, it also has context params possibly*/
partial : WS? KEY context params
 | WS? inline context params
 ;

/** reference is simply a KEY, or field accessing, or array accessing with optional filters*/
reference : path filters
 ;

filters : ('|' KEY)* -> ^(FILTER KEY)*
 ;

inline : '"' inline_part+ '"' -> inline_part+
 ;

inline_part : literal -> ^(VALUE_TEXT literal)
 | '{~' special '}' -> ^(VALUE_SPECIAL special)
 | '{' reference '}' -> ^(VALUE_REF reference)
 ;

/** literal is to match text within quote to quote for inline rules*/
literal : '\\"'
 | (~('{!' | '{#' | '{?' | '{^' | '{<' | '{:' | '{~' | '{/' | '{@' | '{>' | '{+' | '{' | '"'))+
 ;

/** buffer is to match text outof quotes, all text not part of comment, section, special, partial or reference is indeed buffer*/
buffer : (~('{!' | '{#' | '{?' | '{^' | '{<' | '{:' | '{~' | '{/' | '{@' | '{>' | '{+' | '{'))+
 ;

NUMBER : '0'..'9'+ ('.' '0'..'9' *)?
 ;

KEY : ('a'..'z' |'A'..'Z' |'_' |'$' ) ('a'..'z' |'A'..'Z' |'0'..'9' |'_' |'$' )*
 ;

/** whitespace and new line means little to dust, pack them together and ignore the most*/
WS : ( ' ' | '\f' | '\t' | '\u00A0' | '\uFEFF' | '\r' | '\n' | '\u2028' | '\u2029')+
 ;
<pre>

updated to generate the ast tree

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s