diff options
Diffstat (limited to 'vendor/handlebars/src/grammar.rs')
-rw-r--r-- | vendor/handlebars/src/grammar.rs | 372 |
1 files changed, 372 insertions, 0 deletions
diff --git a/vendor/handlebars/src/grammar.rs b/vendor/handlebars/src/grammar.rs new file mode 100644 index 000000000..1fd292ce1 --- /dev/null +++ b/vendor/handlebars/src/grammar.rs @@ -0,0 +1,372 @@ +// const _GRAMMAR: &'static str = include_str!("grammar.pest"); + +#[derive(Parser)] +#[grammar = "grammar.pest"] +pub struct HandlebarsParser; + +#[inline] +pub(crate) fn whitespace_matcher(c: char) -> bool { + c == ' ' || c == '\t' +} + +#[inline] +pub(crate) fn newline_matcher(c: char) -> bool { + c == '\n' || c == '\r' +} + +pub(crate) fn ends_with_empty_line(text: &str) -> bool { + text.trim_end_matches(whitespace_matcher) + .ends_with(newline_matcher) +} + +pub(crate) fn starts_with_empty_line(text: &str) -> bool { + text.trim_start_matches(whitespace_matcher) + .starts_with(newline_matcher) +} + +#[cfg(test)] +mod test { + use super::{HandlebarsParser, Rule}; + use pest::Parser; + + macro_rules! assert_rule { + ($rule:expr, $in:expr) => { + assert_eq!( + HandlebarsParser::parse($rule, $in) + .unwrap() + .last() + .unwrap() + .as_span() + .end(), + $in.len() + ); + }; + } + + macro_rules! assert_not_rule { + ($rule:expr, $in:expr) => { + assert!( + HandlebarsParser::parse($rule, $in).is_err() + || HandlebarsParser::parse($rule, $in) + .unwrap() + .last() + .unwrap() + .as_span() + .end() + != $in.len() + ); + }; + } + + macro_rules! assert_rule_match { + ($rule:expr, $in:expr) => { + assert!(HandlebarsParser::parse($rule, $in).is_ok()); + }; + } + + #[test] + fn test_raw_text() { + let s = vec![ + "<h1> helloworld </h1> ", + r"hello\{{world}}", + r"hello\{{#if world}}nice\{{/if}}", + r"hello \{{{{raw}}}}hello\{{{{/raw}}}}", + ]; + for i in s.iter() { + assert_rule!(Rule::raw_text, i); + } + + let s_not_escape = vec![r"\\{{hello}}"]; + for i in s_not_escape.iter() { + assert_not_rule!(Rule::raw_text, i); + } + } + + #[test] + fn test_raw_block_text() { + let s = "<h1> {{hello}} </h1>"; + assert_rule!(Rule::raw_block_text, s); + } + + #[test] + fn test_reference() { + let s = vec![ + "a", + "abc", + "../a", + "a.b", + "@abc", + "a.[abc]", + "aBc.[abc]", + "abc.[0].[nice]", + "some-name", + "this.[0].ok", + "this.[$id]", + "[$id]", + "$id", + "this.[null]", + ]; + for i in s.iter() { + assert_rule!(Rule::reference, i); + } + } + + #[test] + fn test_name() { + let s = vec!["if", "(abc)"]; + for i in s.iter() { + assert_rule!(Rule::name, i); + } + } + + #[test] + fn test_param() { + let s = vec!["hello", "\"json literal\"", "nullable", "truestory"]; + for i in s.iter() { + assert_rule!(Rule::param, i); + } + } + + #[test] + fn test_hash() { + let s = vec![ + "hello=world", + "hello=\"world\"", + "hello=(world)", + "hello=(world 0)", + ]; + for i in s.iter() { + assert_rule!(Rule::hash, i); + } + } + + #[test] + fn test_json_literal() { + let s = vec![ + "\"json string\"", + "\"quot: \\\"\"", + "[]", + "[\"hello\"]", + "[1,2,3,4,true]", + "{\"hello\": \"world\"}", + "{}", + "{\"a\":1, \"b\":2 }", + "\"nullable\"", + ]; + for i in s.iter() { + assert_rule!(Rule::literal, i); + } + } + + #[test] + fn test_comment() { + let s = vec!["{{!-- <hello {{ a-b c-d}} {{d-c}} ok --}}", + "{{!-- + <li><a href=\"{{up-dir nest-count}}{{base-url}}index.html\">{{this.title}}</a></li> + --}}", + "{{! -- good --}}"]; + for i in s.iter() { + assert_rule!(Rule::hbs_comment, i); + } + let s2 = vec!["{{! hello }}", "{{! test me }}"]; + for i in s2.iter() { + assert_rule!(Rule::hbs_comment_compact, i); + } + } + + #[test] + fn test_subexpression() { + let s = vec!["(sub)", "(sub 0)", "(sub a=1)"]; + for i in s.iter() { + assert_rule!(Rule::subexpression, i); + } + } + + #[test] + fn test_expression() { + let s = vec![ + "{{exp}}", + "{{(exp)}}", + "{{../exp}}", + "{{exp 1}}", + "{{exp \"literal\"}}", + "{{exp \"literal with space\"}}", + r#"{{exp "literal with escape \\\\"}}"#, + "{{exp ref}}", + "{{exp (sub)}}", + "{{exp (sub 123)}}", + "{{exp []}}", + "{{exp {}}}", + "{{exp key=1}}", + "{{exp key=ref}}", + "{{exp key=(sub)}}", + "{{exp key=(sub 0)}}", + "{{exp key=(sub 0 key=1)}}", + ]; + for i in s.iter() { + assert_rule!(Rule::expression, i); + } + } + + #[test] + fn test_identifier_with_dash() { + let s = vec!["{{exp-foo}}"]; + for i in s.iter() { + assert_rule!(Rule::expression, i); + } + } + + #[test] + fn test_html_expression() { + let s = vec![ + "{{{html}}}", + "{{{(html)}}}", + "{{{(html)}}}", + "{{&html}}", + "{{{html 1}}}", + "{{{html p=true}}}", + ]; + for i in s.iter() { + assert_rule!(Rule::html_expression, i); + } + } + + #[test] + fn test_helper_start() { + let s = vec![ + "{{#if hello}}", + "{{#if (hello)}}", + "{{#if hello=world}}", + "{{#if hello hello=world}}", + "{{#if []}}", + "{{#if {}}}", + "{{#if}}", + "{{~#if hello~}}", + "{{#each people as |person|}}", + "{{#each-obj obj as |val key|}}", + "{{#each assets}}", + ]; + for i in s.iter() { + assert_rule!(Rule::helper_block_start, i); + } + } + + #[test] + fn test_helper_end() { + let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if ~}}"]; + for i in s.iter() { + assert_rule!(Rule::helper_block_end, i); + } + } + + #[test] + fn test_helper_block() { + let s = vec![ + "{{#if hello}}hello{{/if}}", + "{{#if true}}hello{{/if}}", + "{{#if nice ok=1}}hello{{/if}}", + "{{#if}}hello{{else}}world{{/if}}", + "{{#if}}hello{{^}}world{{/if}}", + "{{#if}}{{#if}}hello{{/if}}{{/if}}", + "{{#if}}hello{{~else}}world{{/if}}", + "{{#if}}hello{{else~}}world{{/if}}", + "{{#if}}hello{{~^~}}world{{/if}}", + "{{#if}}{{/if}}", + ]; + for i in s.iter() { + assert_rule!(Rule::helper_block, i); + } + } + + #[test] + fn test_raw_block() { + let s = vec![ + "{{{{if hello}}}}good {{hello}}{{{{/if}}}}", + "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}", + ]; + for i in s.iter() { + assert_rule!(Rule::raw_block, i); + } + } + + #[test] + fn test_block_param() { + let s = vec!["as |person|", "as |val key|"]; + for i in s.iter() { + assert_rule!(Rule::block_param, i); + } + } + + #[test] + fn test_path() { + let s = vec![ + "a", + "a.b.c.d", + "a.[0].[1].[2]", + "a.[abc]", + "a/v/c.d.s", + "a.[0]/b/c/d", + "a.[bb c]/b/c/d", + "a.[0].[#hello]", + "../a/b.[0].[1]", + "this.[0]/[1]/this/a", + "./this_name", + "./goo/[/bar]", + "a.[你好]", + "a.[10].[#comment]", + "a.[]", // empty key + "./[/foo]", + "[foo]", + "@root/a/b", + "nullable", + ]; + for i in s.iter() { + assert_rule_match!(Rule::path, i); + } + } + + #[test] + fn test_decorator_expression() { + let s = vec!["{{* ssh}}", "{{~* ssh}}"]; + for i in s.iter() { + assert_rule!(Rule::decorator_expression, i); + } + } + + #[test] + fn test_decorator_block() { + let s = vec![ + "{{#* inline}}something{{/inline}}", + "{{~#* inline}}hello{{/inline}}", + "{{#* inline \"partialname\"}}something{{/inline}}", + ]; + for i in s.iter() { + assert_rule!(Rule::decorator_block, i); + } + } + + #[test] + fn test_partial_expression() { + let s = vec![ + "{{> hello}}", + "{{> (hello)}}", + "{{~> hello a}}", + "{{> hello a=1}}", + "{{> (hello) a=1}}", + "{{> hello.world}}", + "{{> [a83?f4+.3]}}", + "{{> 'anif?.bar'}}", + ]; + for i in s.iter() { + assert_rule!(Rule::partial_expression, i); + } + } + + #[test] + fn test_partial_block() { + let s = vec!["{{#> hello}}nice{{/hello}}"]; + for i in s.iter() { + assert_rule!(Rule::partial_block, i); + } + } +} |