C -> D o D
D -> C
D -> t
D -> D o D
D -> t
D -> t D'
D'-> o D D'|''
E = t
/ u E
/ E o E
/ E ? E : E
/ s E e
E = t
/ u E
/ ( t / u E / s E e ) B
/ ( t / u E / s E e ) T
/ s E e
B = o E
T = ? E : E
start | |
= expression | |
expression | |
= operand binary | |
/ operand ternary | |
/ operand | |
operand | |
= unary | |
/ '(' expression ')' | |
/ token | |
unary | |
= [!~-] expression | |
binary | |
= operator expression | |
ternary | |
= '?' expression ':' expression | |
operator | |
= '+' / '-' / '*' / '/' / '%' / '&&' / '||' | |
token | |
= path | |
/ invoke | |
/ literal | |
path | |
= v:variable p:( a:('.' word) { return a.join(''); } | |
/ b:('[' expression ']') { return b.join(''); } )* { return v + p.join('');} | |
variable | |
= w:word { return w; } | |
word | |
= v:[$_a-zA-Z] c:[$_a-zA-Z0-9]* { return v + c.join(''); } | |
invoke | |
= path '(' p:items? ')' | |
literal | |
= number | |
/ string | |
/ boolean | |
/ array | |
/ object | |
/ 'null' | |
boolean | |
= 'true' / 'false' | |
number | |
= d:[0-9]+ { return d.join(''); } | |
string | |
= s:( '"' (c:[^"]* { return c.join(''); }) '"' ) { return s.join(''); } | |
/ s:( "'" (c:[^']* { return c.join(''); }) "'" ) { return s.join(''); } | |
array | |
= '[' c:items? ']' { return '[' + (c ? c.join('') : '') + ']'; } | |
items | |
= expression (m:( ',' i:expression { return i } )* { return (m.length ? ',' : '') + m.join(','); } ) | |
object | |
= '{' c:pairs? '}' { return '{' + (c ? c.join('') : '') + '}'; } | |
pairs | |
= p:pair (m:( ',' i:pair { return i; } )* { return (m.length ? ',' : '') + m.join(','); }) | |
pair | |
= k:key ':' v:expression { return k + ':' + v; } | |
key | |
= word | |
/ string | |
section | |
= text | |
/ var | |
/ if | |
/ for | |
var | |
= '{$' let ( m:( ',' i:let ) { return (m.length ? ',' : '') + m.join(''); } ) '/}' | |
let | |
= word '=' expression | |
if | |
= '{?' expression '}' section elseif* else? '{/}' | |
for | |
= '{#' expression ':' word ( '@' word )? '}' section '{/}' |