{ function wrap(node, ck) { node['text'] = input.substring(ck.split('@')[1], pos); return node; } } start = body body = p:part* { return ["body"].concat(p) } part = comment / section / partial / special / reference / buffer section "section" = t:sec_tag_start rd b:body e:bodies n:end_tag &{return result8[1].text === result12.text} { e.push(["param", ["literal", "block"], b]); t.push(e); return t } / t:sec_tag_start "/" rd { t.push(["bodies"]); return t } sec_tag_start = ld t:[#?^<+@%] n:identifier c:context p:params { return [t, n, c, p] } end_tag "end tag" = ld "/" n:identifier rd { return n } context = n:(":" n:identifier {return n})? { return n ? ["context", n] : ["context"] } params "params" = p:(ws k:key "=" v:(identifier / inline) {return ["param", ["literal", k], v]})* { return ["params"].concat(p) } bodies "bodies" = p:(ld ":" k:key rd v:body {return ["param", ["literal", k], v]})* { return ["bodies"].concat(p) } reference "reference" = ld n:identifier f:filters rd { return ["reference", n, f] } partial "partial" = ld ">" n:(k:key {return ["literal", k]} / inline) c:context "/" rd { return ["partial", n, c] } filters "filters" = f:("|" n:key {return n})* { return ["filters"].concat(f) } special "special" = ld "~" k:key rd { return ["special", k] } identifier "identifier" = p:path { return wrap(["path"].concat(p), cacheKey) } / k:key { return wrap(["key", k], cacheKey) } path "path" = k:key? d:("." k:key {return k})+ { if (k) { d.unshift(k); return [false, d]; } return [true, d]; } / "." { return [true, []] } key "key" = h:[a-zA-Z_$] t:[0-9a-zA-Z_$]* { return h + t.join('') } inline "inline" = '"' '"' { return ["literal", ""] } / '"' l:literal '"' { return ["literal", l] } / '"' p:inline_part+ '"' { return ["body"].concat(p) } inline_part = special / reference / l:literal { return ["buffer", l] } buffer "buffer" = e:eol w:ws* { return ["format", e, w.join('')] } / b:(!tag !eol !comment c:. {return c})+ { return ["buffer", b.join('')] } literal "literal" = b:(!tag !eol c:(esc / [^"]) {return c})+ { return b.join('') } esc = '\\"' { return '"' } comment "comment" = "{!" c:(!"!}" c:. {return c})* "!}" { return ["comment", c.join('')] } tag = ld [#?^><+%:@/~%] (!rd !eol .)+ rd / reference ld = "{" rd = "}" eol = "\n" / "\r\n" / "\r" / "\u2028" / "\u2029" ws = [\t\v\f \u00A0\uFEFF]