From be51899f7d5f1f9ede689ca0a9707a0aca3d31c4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 1 Sep 2019 13:51:12 +0200 Subject: Rewrite the make_parser macro as a proc_macro --- Cargo.lock | 42 ++++- dhall_proc_macros/Cargo.toml | 6 +- dhall_proc_macros/src/lib.rs | 9 + dhall_proc_macros/src/parser.rs | 398 ++++++++++++++++++++++++++++++++++++++++ dhall_syntax/Cargo.toml | 1 + dhall_syntax/src/parser.rs | 209 +-------------------- 6 files changed, 456 insertions(+), 209 deletions(-) create mode 100644 dhall_proc_macros/src/parser.rs diff --git a/Cargo.lock b/Cargo.lock index 9bd7adc..360168a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,9 +95,9 @@ name = "dhall_proc_macros" version = "0.1.0" dependencies = [ "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -105,6 +105,7 @@ name = "dhall_syntax" version = "0.1.0" dependencies = [ "dhall_generated_parser 0.1.0", + "dhall_proc_macros 0.1.0", "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -269,6 +270,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.6.12" @@ -277,6 +286,14 @@ dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "same-file" version = "1.0.4" @@ -344,6 +361,16 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "take_mut" version = "0.2.2" @@ -386,6 +413,11 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.5" @@ -468,13 +500,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pretty 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f60c0d9f6fc88ecdd245d90c1920ff76a430ab34303fc778d33b1d0a4c3bf6d3" "checksum pretty_assertions 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95" "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267" "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" "checksum serde_cbor 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45cd6d95391b16cd57e88b68be41d504183b7faae22030c0cc3b3f73dd57b2fd" "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" "checksum syn 0.15.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d2b4cfac95805274c6afdb12d8f770fa2d27c045953e7b630a81801953699a9a" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term-painter 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "dcaa948f0e3e38470cd8dc8dcfe561a75c9e43f28075bb183845be2b9b3c08cf" @@ -482,6 +517,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-trie 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "71a9c5b1fe77426cf144cc30e49e955270f5086e31a6441dfa8b32efc09b9d77" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/dhall_proc_macros/Cargo.toml b/dhall_proc_macros/Cargo.toml index df1eda8..b641a39 100644 --- a/dhall_proc_macros/Cargo.toml +++ b/dhall_proc_macros/Cargo.toml @@ -11,6 +11,6 @@ doctest = false [dependencies] itertools = "0.8.0" -quote = "0.6.11" -proc-macro2 = "0.4.27" -syn = "0.15.29" +quote = "1.0.2" +proc-macro2 = "1.0.2" +syn = { version = "1.0.5", features = ["full", "extra-traits"] } diff --git a/dhall_proc_macros/src/lib.rs b/dhall_proc_macros/src/lib.rs index 5304429..37c9985 100644 --- a/dhall_proc_macros/src/lib.rs +++ b/dhall_proc_macros/src/lib.rs @@ -6,6 +6,7 @@ extern crate proc_macro; mod derive; +mod parser; use proc_macro::TokenStream; @@ -13,3 +14,11 @@ use proc_macro::TokenStream; pub fn derive_static_type(input: TokenStream) -> TokenStream { derive::derive_static_type(input) } + +#[proc_macro] +pub fn make_parser(input: TokenStream) -> TokenStream { + TokenStream::from(match parser::make_parser(input) { + Ok(tokens) => tokens, + Err(err) => err.to_compile_error(), + }) +} diff --git a/dhall_proc_macros/src/parser.rs b/dhall_proc_macros/src/parser.rs new file mode 100644 index 0000000..bb4e894 --- /dev/null +++ b/dhall_proc_macros/src/parser.rs @@ -0,0 +1,398 @@ +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::parse::{Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::{bracketed, parenthesized, token, Expr, Ident, Pat, Token, Type}; + +mod rule_kw { + syn::custom_keyword!(rule); + syn::custom_keyword!(captured_str); + syn::custom_keyword!(children); + syn::custom_keyword!(prec_climb); +} + +#[derive(Debug, Clone)] +struct Rules(Vec); + +#[derive(Debug, Clone)] +struct Rule { + rule_token: rule_kw::rule, + bang_token: Token![!], + paren_token: token::Paren, + name: Ident, + lt_token: token::Lt, + output_type: Type, + gt_token: token::Gt, + contents: RuleContents, + semi_token: Token![;], +} + +#[derive(Debug, Clone)] +enum RuleContents { + Empty, + CapturedString { + span: Option, + captured_str_token: rule_kw::captured_str, + bang_token: Token![!], + paren_token: token::Paren, + pattern: Pat, + fat_arrow_token: Token![=>], + body: Expr, + }, + Children { + span: Option, + children_token: rule_kw::children, + bang_token: Token![!], + paren_token: token::Paren, + branches: Punctuated, + }, + PrecClimb { + span: Option, + prec_climb_token: rule_kw::prec_climb, + bang_token: Token![!], + paren_token: token::Paren, + child_rule: Ident, + comma_token: Token![,], + climber: Expr, + comma_token2: Token![,], + pattern: Pat, + fat_arrow_token: Token![=>], + body: Expr, + }, +} + +#[derive(Debug, Clone)] +struct ChildrenBranch { + bracket_token: token::Bracket, + pattern_unparsed: TokenStream, + pattern: Punctuated, + fat_arrow_token: Token![=>], + body: Expr, +} + +#[derive(Debug, Clone)] +enum ChildrenBranchPatternItem { + Single { + rule_name: Ident, + paren_token: token::Paren, + binder: Pat, + }, + Multiple { + rule_name: Ident, + paren_token: token::Paren, + binder: Ident, + slice_token: Token![..], + }, +} + +impl Parse for Rules { + fn parse(input: ParseStream) -> Result { + let mut rules = Vec::new(); + while !input.is_empty() { + rules.push(input.parse()?) + } + Ok(Rules(rules)) + } +} + +impl Parse for Rule { + fn parse(input: ParseStream) -> Result { + let contents; + Ok(Rule { + rule_token: input.parse()?, + bang_token: input.parse()?, + paren_token: parenthesized!(contents in input), + name: contents.parse()?, + lt_token: contents.parse()?, + output_type: contents.parse()?, + gt_token: contents.parse()?, + contents: contents.parse()?, + semi_token: input.parse()?, + }) + } +} + +impl Parse for RuleContents { + fn parse(input: ParseStream) -> Result { + if input.is_empty() { + return Ok(RuleContents::Empty); + } + let _: Token![;] = input.parse()?; + let span = if input.peek(Ident) && input.peek2(Token![;]) { + let span: Ident = input.parse()?; + let _: Token![;] = input.parse()?; + Some(span) + } else { + None + }; + + let lookahead = input.lookahead1(); + if lookahead.peek(rule_kw::captured_str) { + let contents; + Ok(RuleContents::CapturedString { + span, + captured_str_token: input.parse()?, + bang_token: input.parse()?, + paren_token: parenthesized!(contents in input), + pattern: contents.parse()?, + fat_arrow_token: input.parse()?, + body: input.parse()?, + }) + } else if lookahead.peek(rule_kw::children) { + let contents; + Ok(RuleContents::Children { + span, + children_token: input.parse()?, + bang_token: input.parse()?, + paren_token: parenthesized!(contents in input), + branches: Punctuated::parse_terminated(&contents)?, + }) + } else if lookahead.peek(rule_kw::prec_climb) { + let contents; + Ok(RuleContents::PrecClimb { + span, + prec_climb_token: input.parse()?, + bang_token: input.parse()?, + paren_token: parenthesized!(contents in input), + child_rule: contents.parse()?, + comma_token: contents.parse()?, + climber: contents.parse()?, + comma_token2: contents.parse()?, + pattern: contents.parse()?, + fat_arrow_token: contents.parse()?, + body: contents.parse()?, + }) + } else { + Err(lookahead.error()) + } + } +} + +impl Parse for ChildrenBranch { + fn parse(input: ParseStream) -> Result { + let contents; + Ok(ChildrenBranch { + bracket_token: bracketed!(contents in input), + pattern_unparsed: contents.fork().parse()?, + pattern: Punctuated::parse_terminated(&contents)?, + fat_arrow_token: input.parse()?, + body: input.parse()?, + }) + } +} + +impl Parse for ChildrenBranchPatternItem { + fn parse(input: ParseStream) -> Result { + let rule_name = input.parse()?; + let contents; + let paren_token = parenthesized!(contents in input); + if input.peek(Token![..]) { + Ok(ChildrenBranchPatternItem::Multiple { + rule_name, + paren_token, + binder: contents.parse()?, + slice_token: input.parse()?, + }) + } else if input.is_empty() || input.peek(Token![,]) { + Ok(ChildrenBranchPatternItem::Single { + rule_name, + paren_token, + binder: contents.parse()?, + }) + } else { + Err(input.error("expected `..` or nothing")) + } + } +} + +fn make_construct_precclimbers(rules: &Rules) -> Result { + let mut entries: Vec = Vec::new(); + for rule in &rules.0 { + if let RuleContents::PrecClimb { climber, .. } = &rule.contents { + let name = &rule.name; + entries.push(quote!( + map.insert(Rule::#name, #climber); + )) + } + } + + Ok(quote!( + fn construct_precclimbers() -> HashMap> { + let mut map = HashMap::new(); + #(#entries)* + map + } + )) +} + +fn make_entrypoints(rules: &Rules) -> Result { + let mut entries: Vec = Vec::new(); + for rule in &rules.0 { + let name = &rule.name; + let output_type = &rule.output_type; + entries.push(quote!( + #[allow(non_snake_case, dead_code)] + fn #name<'a>( + input: Rc, + pair: Pair<'a, Rule>, + ) -> ParseResult<#output_type> { + let climbers = construct_precclimbers(); + Parsers::#name((&climbers, input), pair) + } + )) + } + + Ok(quote!( + struct EntryPoint; + impl EntryPoint { + #(#entries)* + } + )) +} + +fn make_parser_branch(branch: &ChildrenBranch) -> TokenStream { + let ChildrenBranch { + pattern, + body, + pattern_unparsed, + .. + } = branch; + let variable_pattern = Ident::new("variable_pattern", Span::call_site()); + let match_pat = pattern.iter().map(|item| match item { + ChildrenBranchPatternItem::Single { rule_name, .. } => { + quote!(Rule::#rule_name) + } + ChildrenBranchPatternItem::Multiple { .. } => { + quote!(#variable_pattern..) + } + }); + let match_filter = pattern.iter().map(|item| match item { + ChildrenBranchPatternItem::Single { .. } => quote!(true &&), + ChildrenBranchPatternItem::Multiple { rule_name, .. } => { + quote!(#variable_pattern.iter().all(|r| r == &Rule::#rule_name) &&) + } + }); + quote!( + [#(#match_pat),*] if #(#match_filter)* true => { + parse_children!((climbers, input.clone()), iter; + [#pattern_unparsed] => { + #[allow(unused_variables)] + let res: Result<_, String> = try { #body }; + res.map_err(|msg| + custom_parse_error(&pair, msg) + ) + } + ) + } + ) +} + +fn make_parser_expr(rule: &Rule) -> Result { + let name = &rule.name; + let expr = match &rule.contents { + RuleContents::Empty => quote!(Ok(())), + RuleContents::CapturedString { pattern, body, .. } => quote!( + let #pattern = pair.as_str(); + let res: Result<_, String> = try { #body }; + res.map_err(|msg| custom_parse_error(&pair, msg)) + ), + RuleContents::PrecClimb { + child_rule, + pattern, + body, + .. + } => quote!( + let climber = climbers.get(&Rule::#name).unwrap(); + climber.climb( + pair.clone().into_inner(), + |p| Parsers::#child_rule((climbers, input.clone()), p), + |l, op, r| { + let #pattern = (l?, op, r?); + let res: Result<_, String> = try { #body }; + res.map_err(|msg| custom_parse_error(&pair, msg)) + }, + ) + ), + RuleContents::Children { branches, .. } => { + let branches = branches.iter().map(make_parser_branch); + quote!( + let children_rules: Vec = pair + .clone() + .into_inner() + .map(|p| p.as_rule()) + .collect(); + + #[allow(unused_mut)] + let mut iter = pair.clone().into_inner(); + + #[allow(unreachable_code)] + match children_rules.as_slice() { + #(#branches,)* + [..] => Err(custom_parse_error( + &pair, + format!("Unexpected children: {:?}", children_rules) + )), + } + ) + } + }; + Ok(expr) +} + +fn make_parsers(rules: &Rules) -> Result { + let mut entries: Vec = Vec::new(); + for rule in &rules.0 { + let span_def = match &rule.contents { + RuleContents::CapturedString { + span: Some(span), .. + } + | RuleContents::Children { + span: Some(span), .. + } + | RuleContents::PrecClimb { + span: Some(span), .. + } => Some(quote!( + let #span = Span::make(input.clone(), pair.as_span()); + )), + _ => None, + }; + + let name = &rule.name; + let output_type = &rule.output_type; + let expr = make_parser_expr(rule)?; + + entries.push(quote!( + #[allow(non_snake_case, dead_code)] + fn #name<'a>( + (climbers, input): (&HashMap>, Rc), + pair: Pair<'a, Rule>, + ) -> ParseResult<#output_type> { + #span_def + #expr + } + )) + } + + Ok(quote!( + struct Parsers; + impl Parsers { + #(#entries)* + } + )) +} + +pub fn make_parser( + input: proc_macro::TokenStream, +) -> Result { + let rules: Rules = syn::parse_macro_input::parse(input.clone())?; + + let construct_precclimbers = make_construct_precclimbers(&rules)?; + let entrypoints = make_entrypoints(&rules)?; + let parsers = make_parsers(&rules)?; + + Ok(quote!( + #construct_precclimbers + #entrypoints + #parsers + )) +} diff --git a/dhall_syntax/Cargo.toml b/dhall_syntax/Cargo.toml index 1da10c7..62ecced 100644 --- a/dhall_syntax/Cargo.toml +++ b/dhall_syntax/Cargo.toml @@ -16,3 +16,4 @@ either = "1.5.2" take_mut = "0.2.2" hex = "0.3.2" dhall_generated_parser = { path = "../dhall_generated_parser" } +dhall_proc_macros = { path = "../dhall_proc_macros" } diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index 53fd68a..4fd6f57 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -189,203 +189,6 @@ macro_rules! parse_children { }; } -macro_rules! make_parser { - (@children_pattern, - $varpat:ident, - ($($acc:tt)*), - [$variant:ident ($x:pat), $($rest:tt)*] - ) => ( - make_parser!(@children_pattern, - $varpat, - ($($acc)* , Rule::$variant), - [$($rest)*] - ) - ); - (@children_pattern, - $varpat:ident, - ($($acc:tt)*), - [$variant:ident ($x:ident).., $($rest:tt)*] - ) => ( - make_parser!(@children_pattern, - $varpat, - ($($acc)* , $varpat..), - [$($rest)*] - ) - ); - (@children_pattern, - $varpat:ident, - (, $($acc:tt)*), [$(,)*] - ) => ([$($acc)*]); - (@children_pattern, - $varpat:ident, - ($($acc:tt)*), [$(,)*] - ) => ([$($acc)*]); - - (@children_filter, - $varpat:ident, - [$variant:ident ($x:pat), $($rest:tt)*] - ) => ( - make_parser!(@children_filter, $varpat, [$($rest)*]) - ); - (@children_filter, - $varpat:ident, - [$variant:ident ($x:ident).., $($rest:tt)*] - ) => ( - $varpat.iter().all(|r| r == &Rule::$variant) && - make_parser!(@children_filter, $varpat, [$($rest)*]) - ); - (@children_filter, $varpat:ident, [$(,)*]) => (true); - - (@body, - ($climbers:expr, $input:expr, $pair:expr), - rule!( - $name:ident<$o:ty>; - $span:ident; - captured_str!($x:pat) => $body:expr - ) - ) => ({ - let $span = Span::make($input.clone(), $pair.as_span()); - let $x = $pair.as_str(); - let res: Result<_, String> = try { $body }; - res.map_err(|msg| custom_parse_error(&$pair, msg)) - }); - (@body, - ($climbers:expr, $input:expr, $pair:expr), - rule!( - $name:ident<$o:ty>; - $span:ident; - children!( $( [$($args:tt)*] => $body:expr ),* $(,)* ) - ) - ) => ({ - let children_rules: Vec = $pair - .clone() - .into_inner() - .map(|p| p.as_rule()) - .collect(); - - let $span = Span::make($input.clone(), $pair.as_span()); - #[allow(unused_mut)] - let mut iter = $pair.clone().into_inner(); - - #[allow(unreachable_code)] - match children_rules.as_slice() { - $( - make_parser!(@children_pattern, x, (), [$($args)*,]) - if make_parser!(@children_filter, x, [$($args)*,]) - => { - parse_children!(($climbers, $input.clone()), iter; - [$($args)*] => { - let res: Result<_, String> = try { $body }; - res.map_err(|msg| custom_parse_error(&$pair, msg)) - } - ) - } - , - )* - [..] => Err(custom_parse_error( - &$pair, - format!("Unexpected children: {:?}", children_rules) - )), - } - }); - (@body, - ($climbers:expr, $input:expr, $pair:expr), - rule!( - $name:ident<$o:ty>; - prec_climb!( - $other_rule:ident, - $_climber:expr, - $args:pat => $body:expr $(,)* - ) - ) - ) => ({ - let climber = $climbers.get(&Rule::$name).unwrap(); - climber.climb( - $pair.clone().into_inner(), - |p| Parsers::$other_rule(($climbers, $input.clone()), p), - |l, op, r| { - let $args = (l?, op, r?); - let res: Result<_, String> = try { $body }; - res.map_err(|msg| custom_parse_error(&$pair, msg)) - }, - ) - }); - (@body, - ($($things:tt)*), - rule!( - $name:ident<$o:ty>; - $($args:tt)* - ) - ) => ({ - make_parser!(@body, - ($($things)*), - rule!( - $name<$o>; - _span; - $($args)* - ) - ) - }); - (@body, - ($($things:tt)*), - rule!($name:ident<$o:ty>) - ) => ({ - Ok(()) - }); - - (@construct_climber, - ($map:expr), - rule!( - $name:ident<$o:ty>; - prec_climb!($other_rule:ident, $climber:expr, $($_rest:tt)* ) - ) - ) => ({ - $map.insert(Rule::$name, $climber) - }); - (@construct_climber, ($($things:tt)*), $($args:tt)*) => (()); - - ($( $submac:ident!( $name:ident<$o:ty> $($args:tt)* ); )*) => ( - struct Parsers; - - impl Parsers { - $( - #[allow(non_snake_case, unused_variables, clippy::let_unit_value)] - fn $name<'a>( - (climbers, input): (&HashMap>, Rc), - pair: Pair<'a, Rule>, - ) -> ParseResult<$o> { - make_parser!(@body, (climbers, input, pair), - $submac!( $name<$o> $($args)* )) - } - )* - } - - fn construct_precclimbers() -> HashMap> { - let mut map = HashMap::new(); - $( - make_parser!(@construct_climber, (map), - $submac!( $name<$o> $($args)* )); - )* - map - } - - struct EntryPoint; - - impl EntryPoint { - $( - #[allow(non_snake_case, dead_code)] - fn $name<'a>( - input: Rc, - pair: Pair<'a, Rule>, - ) -> ParseResult<$o> { - let climbers = construct_precclimbers(); - Parsers::$name((&climbers, input), pair) - } - )* - } - ); -} - // Trim the shared indent off of a vec of lines, as defined by the Dhall semantics of multiline // literals. fn trim_indent(lines: &mut Vec) { @@ -427,7 +230,7 @@ fn trim_indent(lines: &mut Vec) { } } -make_parser! { +dhall_proc_macros::make_parser! { rule!(EOI<()>); rule!(simple_label