1WHITESPACE = _{ " "|"\t"|"\n"|"\r" } 2keywords = { "as" | "else" } 3 4escape = @{ ("\\" ~ "{{" ~ "{{"?) | ("\\" ~ "\\"+ ~ &"{{") } 5raw_text = ${ ( escape | (!"{{" ~ ANY) )+ } 6raw_block_text = ${ ( escape | (!"{{{{" ~ ANY) )* } 7 8literal = { string_literal | 9 array_literal | 10 object_literal | 11 number_literal | 12 null_literal | 13 boolean_literal } 14 15null_literal = @{ "null" ~ !symbol_char } 16boolean_literal = @{ ("true"|"false") ~ !symbol_char } 17number_literal = @{ "-"? ~ ASCII_DIGIT+ ~ "."? ~ ASCII_DIGIT* ~ ("E" ~ "-"? ~ ASCII_DIGIT+)? } 18json_char_double_quote = { 19 !("\"" | "\\") ~ ANY 20 | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") 21 | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) 22} 23json_char_single_quote = { 24 !("'" | "\\") ~ ANY 25 | "\\" ~ ("'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") 26 | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) 27} 28string_inner_double_quote = @{ json_char_double_quote* } 29string_inner_single_quote = @{ json_char_single_quote* } 30string_literal = ${ ("\"" ~ string_inner_double_quote ~ "\"") | ("'" ~ string_inner_single_quote ~ "'") } 31array_literal = { "[" ~ literal? ~ ("," ~ literal)* ~ "]" } 32object_literal = { "{" ~ (string_literal ~ ":" ~ literal)? 33 ~ ("," ~ string_literal ~ ":" ~ literal)* ~ "}" } 34 35symbol_char = _{ASCII_ALPHANUMERIC|"-"|"_"|"$"|'\u{80}'..'\u{7ff}'|'\u{800}'..'\u{ffff}'|'\u{10000}'..'\u{10ffff}'} 36partial_symbol_char = _{ASCII_ALPHANUMERIC|"-"|"_"|'\u{80}'..'\u{7ff}'|'\u{800}'..'\u{ffff}'|'\u{10000}'..'\u{10ffff}'|"/"|"."} 37path_char = _{ "/" } 38 39identifier = @{ symbol_char+ } 40partial_identifier = @{ partial_symbol_char+ | ("[" ~ ANY+ ~ "]") | ("'" ~ (!"'" ~ ("\\'" | ANY))+ ~ "'") } 41reference = ${ path_inline } 42 43name = _{ subexpression | reference } 44 45param = { !(keywords ~ !symbol_char) ~ (literal | reference | subexpression) } 46hash = { identifier ~ "=" ~ param } 47block_param = { "as" ~ "|" ~ identifier ~ identifier? ~ "|"} 48exp_line = _{ identifier ~ (hash|param)* ~ block_param?} 49partial_exp_line = _{ ((partial_identifier|name) ~ (hash|param)*) } 50 51subexpression = { "(" ~ ((identifier ~ (hash|param)+) | reference) ~ ")" } 52 53pre_whitespace_omitter = { "~" } 54pro_whitespace_omitter = { "~" } 55 56expression = { !invert_tag ~ "{{" ~ pre_whitespace_omitter? ~ 57 ((identifier ~ (hash|param)+) | name ) 58 ~ pro_whitespace_omitter? ~ "}}" } 59html_expression_triple_bracket = _{ "{{{" ~ pre_whitespace_omitter? ~ 60 ((identifier ~ (hash|param)+) | name ) ~ 61 pro_whitespace_omitter? ~ "}}}" } 62amp_expression = _{ "{{" ~ pre_whitespace_omitter? ~ "&" ~ name ~ 63 pro_whitespace_omitter? ~ "}}" } 64html_expression = { html_expression_triple_bracket | amp_expression } 65 66decorator_expression = { "{{" ~ pre_whitespace_omitter? ~ "*" ~ exp_line ~ 67pro_whitespace_omitter? ~ "}}" } 68partial_expression = { "{{" ~ pre_whitespace_omitter? ~ ">" ~ partial_exp_line 69 ~ pro_whitespace_omitter? ~ "}}" } 70 71invert_tag_item = { "else"|"^" } 72invert_tag = { !escape ~ "{{" ~ pre_whitespace_omitter? ~ invert_tag_item 73 ~ pro_whitespace_omitter? ~ "}}" } 74helper_block_start = { "{{" ~ pre_whitespace_omitter? ~ "#" ~ exp_line ~ 75 pro_whitespace_omitter? ~ "}}" } 76helper_block_end = { "{{" ~ pre_whitespace_omitter? ~ "/" ~ identifier ~ 77 pro_whitespace_omitter? ~ "}}" } 78helper_block = _{ helper_block_start ~ template ~ 79 (invert_tag ~ template)? ~ helper_block_end } 80 81decorator_block_start = { "{{" ~ pre_whitespace_omitter? ~ "#" ~ "*" 82 ~ exp_line ~ pro_whitespace_omitter? ~ "}}" } 83decorator_block_end = { "{{" ~ pre_whitespace_omitter? ~ "/" ~ identifier ~ 84 pro_whitespace_omitter? ~ "}}" } 85decorator_block = _{ decorator_block_start ~ template ~ 86 decorator_block_end } 87 88partial_block_start = { "{{" ~ pre_whitespace_omitter? ~ "#" ~ ">" 89 ~ partial_exp_line ~ pro_whitespace_omitter? ~ "}}" } 90partial_block_end = { "{{" ~ pre_whitespace_omitter? ~ "/" ~ partial_identifier ~ 91 pro_whitespace_omitter? ~ "}}" } 92partial_block = _{ partial_block_start ~ template ~ partial_block_end } 93 94raw_block_start = { "{{{{" ~ pre_whitespace_omitter? ~ exp_line ~ 95 pro_whitespace_omitter? ~ "}}}}" } 96raw_block_end = { "{{{{" ~ pre_whitespace_omitter? ~ "/" ~ identifier ~ 97 pro_whitespace_omitter? ~ "}}}}" } 98raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end } 99 100hbs_comment = { "{{!" ~ "--" ~ (!"--}}" ~ ANY)* ~ "--" ~ "}}" } 101hbs_comment_compact = { "{{!" ~ (!"}}" ~ ANY)* ~ "}}" } 102 103template = { ( 104 raw_text | 105 expression | 106 html_expression | 107 helper_block | 108 raw_block | 109 hbs_comment | 110 hbs_comment_compact | 111 decorator_expression | 112 decorator_block | 113 partial_expression | 114 partial_block )* } 115 116parameter = _{ param ~ EOI } 117handlebars = _{ template ~ EOI } 118 119// json path visitor 120// Disallowed chars: Whitespace ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~ 121 122path_id = @{ symbol_char+ } 123 124path_raw_id = { (!"]" ~ ANY)* } 125path_sep = _{ "/" | "." } 126path_up = { ".." } 127path_key = _{ "[" ~ path_raw_id ~ "]" } 128path_root = { "@root" } 129path_current = _{ "this" ~ path_sep | "./" } 130path_item = _{ path_id|path_key } 131path_local = { "@" } 132path_inline = ${ path_current? ~ (path_root ~ path_sep)? ~ path_local? ~ (path_up ~ path_sep)* ~ path_item ~ (path_sep ~ path_item)* } 133path = _{ path_inline ~ EOI } 134