diff --git a/src/grammar.rs b/src/grammar.rs index df8b953..d942962 100644 --- a/src/grammar.rs +++ b/src/grammar.rs @@ -1,7 +1,150 @@ // const _GRAMMAR: &'static str = include_str!("grammar.pest"); #[derive(Parser)] -#[grammar = "grammar.pest"] +// #[grammar = "grammar.pest"] can't be used here, because +// CARGO_MANIFEST_DIR is not set in soong environment. +#[grammar_inline = r##" +//! Pest grammar for handlebars templating +WHITESPACE = _{ " "|"\t"|"\n"|"\r" } +keywords = { "as" | "else" } + +escape = @{ ("\\" ~ "{{" ~ "{{"?) | ("\\" ~ "\\"+ ~ &"{{") } +raw_text = ${ ( escape | (!"{{" ~ ANY) )+ } +raw_block_text = ${ ( escape | (!"{{{{" ~ ANY) )* } + +literal = { string_literal | + array_literal | + object_literal | + number_literal | + null_literal | + boolean_literal } + +null_literal = @{ "null" ~ !symbol_char } +boolean_literal = @{ ("true"|"false") ~ !symbol_char } +number_literal = @{ "-"? ~ ASCII_DIGIT+ ~ "."? ~ ASCII_DIGIT* ~ ("E" ~ "-"? ~ ASCII_DIGIT+)? ~ !symbol_char } +json_char_double_quote = { + !("\"" | "\\") ~ ANY + | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") + | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) +} +json_char_single_quote = { + !("'" | "\\") ~ ANY + | "\\" ~ ("'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") + | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) +} +string_inner_double_quote = @{ json_char_double_quote* } +string_inner_single_quote = @{ json_char_single_quote* } +string_literal = ${ ("\"" ~ string_inner_double_quote ~ "\"") | ("'" ~ string_inner_single_quote ~ "'") } +array_literal = { "[" ~ literal? ~ ("," ~ literal)* ~ "]" } +object_literal = { "{" ~ (string_literal ~ ":" ~ literal)? + ~ ("," ~ string_literal ~ ":" ~ literal)* ~ "}" } + +symbol_char = _{ASCII_ALPHANUMERIC|"-"|"_"|"$"|'\u{80}'..'\u{7ff}'|'\u{800}'..'\u{ffff}'|'\u{10000}'..'\u{10ffff}'} +partial_symbol_char = _{ASCII_ALPHANUMERIC|"-"|"_"|'\u{80}'..'\u{7ff}'|'\u{800}'..'\u{ffff}'|'\u{10000}'..'\u{10ffff}'|"/"|"."} +path_char = _{ "/" } + +identifier = @{ symbol_char+ } +partial_identifier = @{ partial_symbol_char+ | ("[" ~ ANY+ ~ "]") | ("'" ~ (!"'" ~ ("\\'" | ANY))+ ~ "'") } +reference = ${ path_inline } + +name = _{ subexpression | reference } + +helper_parameter = { !(keywords ~ !symbol_char) ~ (literal | reference | subexpression) } +hash = { identifier ~ "=" ~ helper_parameter } +block_param = { "as" ~ "|" ~ identifier ~ identifier? ~ "|"} +exp_line = _{ identifier ~ (hash|helper_parameter)* ~ block_param?} +partial_exp_line = _{ ((partial_identifier|name) ~ (hash|helper_parameter)*) } + +subexpression = { "(" ~ ((identifier ~ (hash|helper_parameter)+) | reference) ~ ")" } + +leading_tilde_to_omit_whitespace = { "~" } +trailing_tilde_to_omit_whitespace = { "~" } + +expression = { !(invert_tag|invert_chain_tag) ~ "{{" ~ leading_tilde_to_omit_whitespace? ~ + ((identifier ~ (hash|helper_parameter)+) | name ) + ~ trailing_tilde_to_omit_whitespace? ~ "}}" } +html_expression_triple_bracket_legacy = _{ "{{{" ~ leading_tilde_to_omit_whitespace? ~ + ((identifier ~ (hash|helper_parameter)+) | name ) ~ + trailing_tilde_to_omit_whitespace? ~ "}}}" } +html_expression_triple_bracket = _{ "{{" ~ leading_tilde_to_omit_whitespace? ~ "{" ~ + ((identifier ~ (hash|helper_parameter)+) | name ) ~ + "}" ~ trailing_tilde_to_omit_whitespace? ~ "}}" } + +amp_expression = _{ "{{" ~ leading_tilde_to_omit_whitespace? ~ "&" ~ name ~ + trailing_tilde_to_omit_whitespace? ~ "}}" } +html_expression = { (html_expression_triple_bracket_legacy | html_expression_triple_bracket) + | amp_expression } + +decorator_expression = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "*" ~ exp_line ~ +trailing_tilde_to_omit_whitespace? ~ "}}" } +partial_expression = { "{{" ~ leading_tilde_to_omit_whitespace? ~ ">" ~ partial_exp_line + ~ trailing_tilde_to_omit_whitespace? ~ "}}" } + +invert_tag_item = { "else"|"^" } +invert_tag = { !escape ~ "{{" ~ leading_tilde_to_omit_whitespace? ~ invert_tag_item + ~ trailing_tilde_to_omit_whitespace? ~ "}}" } +invert_chain_tag = { !escape ~ "{{" ~ leading_tilde_to_omit_whitespace? ~ invert_tag_item + ~ exp_line ~ trailing_tilde_to_omit_whitespace? ~ "}}" } +helper_block_start = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "#" ~ exp_line ~ + trailing_tilde_to_omit_whitespace? ~ "}}" } +helper_block_end = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "/" ~ identifier ~ + trailing_tilde_to_omit_whitespace? ~ "}}" } +helper_block = _{ helper_block_start ~ template ~ + (invert_chain_tag ~ template)* ~ (invert_tag ~ template)? ~ helper_block_end } + +decorator_block_start = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "#" ~ "*" + ~ exp_line ~ trailing_tilde_to_omit_whitespace? ~ "}}" } +decorator_block_end = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "/" ~ identifier ~ + trailing_tilde_to_omit_whitespace? ~ "}}" } +decorator_block = _{ decorator_block_start ~ template ~ + decorator_block_end } + +partial_block_start = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "#" ~ ">" + ~ partial_exp_line ~ trailing_tilde_to_omit_whitespace? ~ "}}" } +partial_block_end = { "{{" ~ leading_tilde_to_omit_whitespace? ~ "/" ~ partial_identifier ~ + trailing_tilde_to_omit_whitespace? ~ "}}" } +partial_block = _{ partial_block_start ~ template ~ partial_block_end } + +raw_block_start = { "{{{{" ~ leading_tilde_to_omit_whitespace? ~ exp_line ~ + trailing_tilde_to_omit_whitespace? ~ "}}}}" } +raw_block_end = { "{{{{" ~ leading_tilde_to_omit_whitespace? ~ "/" ~ identifier ~ + trailing_tilde_to_omit_whitespace? ~ "}}}}" } +raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end } + +hbs_comment = { "{{!" ~ "--" ~ (!"--}}" ~ ANY)* ~ "--" ~ "}}" } +hbs_comment_compact = { "{{!" ~ (!"}}" ~ ANY)* ~ "}}" } + +template = { ( + raw_text | + expression | + html_expression | + helper_block | + raw_block | + hbs_comment | + hbs_comment_compact | + decorator_expression | + decorator_block | + partial_expression | + partial_block )* } + +parameter = _{ helper_parameter ~ EOI } +handlebars = _{ template ~ EOI } + +/// json path visitor +/// Disallowed chars: Whitespace ! " # % & ' ( ) * + , . / ; < = > @ [ \ ] ^ ` { | } ~ +path_id = @{ symbol_char+ } + +path_raw_id = { (!"]" ~ ANY)* } +path_sep = _{ "/" | "." } +path_up = { ".." } +path_key = _{ "[" ~ path_raw_id ~ "]" } +path_root = { "@root" } +path_current = _{ "this" ~ path_sep | "./" } +path_item = _{ path_id|path_key } +path_local = { "@" } +path_inline = ${ path_current? ~ (path_root ~ path_sep)? ~ path_local? ~ (path_up ~ path_sep)* ~ path_item ~ (path_sep ~ path_item)* } +path = _{ path_inline ~ EOI } +"##] pub struct HandlebarsParser; #[cfg(test)]