diff options
author | Nadrieril | 2019-09-02 17:44:23 +0200 |
---|---|---|
committer | Nadrieril | 2019-09-02 17:44:23 +0200 |
commit | 4bc3380f57e6ce1c7766df0d6b720371b216490d (patch) | |
tree | ef09f7faf9c4c88c48abe204aec1b36ecd6d2576 | |
parent | 98b53bfe084fcdb58207de19fccbd9ac10a7baf7 (diff) |
Get rid of EntryPoint magic
-rw-r--r-- | dhall_proc_macros/src/lib.rs | 1 | ||||
-rw-r--r-- | dhall_proc_macros/src/parser.rs | 156 | ||||
-rw-r--r-- | dhall_syntax/src/parser.rs | 91 |
3 files changed, 80 insertions, 168 deletions
diff --git a/dhall_proc_macros/src/lib.rs b/dhall_proc_macros/src/lib.rs index 92cf981..3e41254 100644 --- a/dhall_proc_macros/src/lib.rs +++ b/dhall_proc_macros/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(drain_filter)] //! This crate contains the code-generation primitives for the [dhall-rust][dhall-rust] crate. //! This is highly unstable and breaks regularly; use at your own risk. //! diff --git a/dhall_proc_macros/src/parser.rs b/dhall_proc_macros/src/parser.rs index f2efb80..5d03cf5 100644 --- a/dhall_proc_macros/src/parser.rs +++ b/dhall_proc_macros/src/parser.rs @@ -5,7 +5,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ braced, bracketed, parenthesized, parse_quote, token, Error, Expr, Ident, - ItemFn, Pat, ReturnType, Token, Type, + ItemFn, Pat, ReturnType, Token, }; mod rule_kw { @@ -20,21 +20,7 @@ struct Rules(Vec<Rule>); #[derive(Debug, Clone)] struct Rule { - name: Ident, - output_type: Type, - contents: RuleContents, -} - -#[derive(Debug, Clone)] -enum RuleContents { - PrecClimb { - child_rule: Ident, - climber: Expr, - function: ItemFn, - }, - Function { - function: ItemFn, - }, + function: ItemFn, } #[derive(Debug, Clone)] @@ -72,16 +58,11 @@ impl Parse for Rules { impl Parse for Rule { fn parse(input: ParseStream) -> Result<Self> { - let function: ItemFn = input.parse()?; - let (recognized_attrs, remaining_attrs) = function + let mut function: ItemFn = input.parse()?; + let recognized_attrs: Vec<_> = function .attrs - .iter() - .cloned() - .partition::<Vec<_>, _>(|attr| attr.path.is_ident("prec_climb")); - let function = ItemFn { - attrs: remaining_attrs, - ..(function.clone()) - }; + .drain_filter(|attr| attr.path.is_ident("prec_climb")) + .collect(); let name = function.sig.ident.clone(); let output_type = match &function.sig.output { @@ -90,11 +71,7 @@ impl Parse for Rule { }; if recognized_attrs.is_empty() { - Ok(Rule { - name, - output_type, - contents: RuleContents::Function { function }, - }) + Ok(Rule { function }) } else if recognized_attrs.len() != 1 { Err(input.error("expected a prec_climb attribute")) } else { @@ -107,15 +84,24 @@ impl Parse for Rule { Ok((child_rule, climber)) })?; - Ok(Rule { - name, - output_type, - contents: RuleContents::PrecClimb { - child_rule, - climber, - function, - }, - }) + let function = parse_quote!( + fn #name<'a>( + input: ParseInput<'a, Rule>, + ) -> #output_type { + #[allow(non_snake_case, dead_code)] + #function + + #climber.climb( + input.pair.clone().into_inner(), + |p| Parsers::#child_rule(input.with_pair(p)), + |l, op, r| { + #name(input.clone(), l?, op, r?) + }, + ) + } + ); + + Ok(Rule { function }) } } } @@ -169,86 +155,13 @@ impl Parse for ParseChildrenInput { } } -fn make_construct_precclimbers(rules: &Rules) -> Result<TokenStream> { - let mut entries: Vec<TokenStream> = 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<Rule, PrecClimber<Rule>> { - let mut map = HashMap::new(); - #(#entries)* - map - } - )) -} - -fn make_entrypoints(rules: &Rules) -> Result<TokenStream> { - let mut entries: Vec<TokenStream> = 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_str: &str, - pair: Pair<'a, Rule>, - ) -> #output_type { - let climbers = construct_precclimbers(); - let input = ParseInput { - climbers: &climbers, - original_input_str: input_str.to_string().into(), - pair - }; - Parsers::#name(input) - } - )) - } - - Ok(quote!( - struct EntryPoint; - impl EntryPoint { - #(#entries)* - } - )) -} - fn make_parsers(rules: &Rules) -> Result<TokenStream> { let entries = rules.0.iter().map(|rule| { - let name = &rule.name; - let output_type = &rule.output_type; - match &rule.contents { - RuleContents::PrecClimb { - child_rule, - function, - .. - } => quote!( - #[allow(non_snake_case, dead_code)] - fn #name<'a, 'climbers>( - input: ParseInput<'a, 'climbers, Rule>, - ) -> #output_type { - #function - let climber = input.climbers.get(&Rule::#name).unwrap(); - climber.climb( - input.pair.clone().into_inner(), - |p| Parsers::#child_rule(input.with_pair(p)), - |l, op, r| { - #name(input.clone(), l?, op, r?) - }, - ) - } - ), - RuleContents::Function { function } => quote!( - #[allow(non_snake_case, dead_code)] - #function - ), - } + let function = &rule.function; + quote!( + #[allow(non_snake_case, dead_code)] + #function + ) }); Ok(quote!( @@ -263,16 +176,9 @@ pub fn make_parser( input: proc_macro::TokenStream, ) -> Result<proc_macro2::TokenStream> { let rules: Rules = syn::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 - )) + Ok(quote!( #parsers )) } fn make_parser_branch(branch: &ChildrenBranch) -> Result<TokenStream> { diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index 2864a97..5ed524d 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -4,7 +4,6 @@ use pest::prec_climber as pcl; use pest::prec_climber::PrecClimber; use pest::Parser; use std::borrow::Cow; -use std::collections::HashMap; use std::rc::Rc; use dhall_generated_parser::{DhallParser, Rule}; @@ -29,16 +28,15 @@ pub type ParseError = pest::error::Error<Rule>; pub type ParseResult<T> = Result<T, ParseError>; #[derive(Debug, Clone)] -struct ParseInput<'input, 'climbers, Rule> +struct ParseInput<'input, Rule> where Rule: std::fmt::Debug + Copy + std::hash::Hash + Ord, { pair: Pair<'input, Rule>, - climbers: &'climbers HashMap<Rule, PrecClimber<Rule>>, original_input_str: Rc<str>, } -impl<'input, 'climbers> ParseInput<'input, 'climbers, Rule> { +impl<'input> ParseInput<'input, Rule> { fn error(&self, message: String) -> ParseError { let message = format!( "{} while matching on:\n{}", @@ -48,10 +46,19 @@ impl<'input, 'climbers> ParseInput<'input, 'climbers, Rule> { let e = pest::error::ErrorVariant::CustomError { message }; pest::error::Error::new_from_span(e, self.pair.as_span()) } + fn parse(input_str: &'input str, rule: Rule) -> ParseResult<Self> { + let mut pairs = DhallParser::parse(rule, input_str)?; + // TODO: proper errors + let pair = pairs.next().unwrap(); + assert_eq!(pairs.next(), None); + Ok(ParseInput { + original_input_str: input_str.to_string().into(), + pair, + }) + } fn with_pair(&self, new_pair: Pair<'input, Rule>) -> Self { ParseInput { pair: new_pair, - climbers: self.climbers, original_input_str: self.original_input_str.clone(), } } @@ -189,30 +196,32 @@ fn trim_indent(lines: &mut Vec<ParsedText>) { } } -fn make_precclimber() -> PrecClimber<Rule> { - use Rule::*; - // In order of precedence - let operators = vec![ - import_alt, - bool_or, - natural_plus, - text_append, - list_append, - bool_and, - combine, - prefer, - combine_types, - natural_times, - bool_eq, - bool_ne, - equivalent, - ]; - PrecClimber::new( - operators - .into_iter() - .map(|op| pcl::Operator::new(op, pcl::Assoc::Left)) - .collect(), - ) +lazy_static::lazy_static! { + static ref PRECCLIMBER: PrecClimber<Rule> = { + use Rule::*; + // In order of precedence + let operators = vec![ + import_alt, + bool_or, + natural_plus, + text_append, + list_append, + bool_and, + combine, + prefer, + combine_types, + natural_times, + bool_eq, + bool_ne, + equivalent, + ]; + PrecClimber::new( + operators + .into_iter() + .map(|op| pcl::Operator::new(op, pcl::Assoc::Left)) + .collect(), + ) + }; } #[make_parser] @@ -330,7 +339,7 @@ impl _ { }) } fn double_quote_char<'a>( - input: ParseInput<'a, '_, Rule>, + input: ParseInput<'a, Rule>, ) -> ParseResult<&'a str> { Ok(input.as_str()) } @@ -359,17 +368,15 @@ impl _ { )) } fn single_quote_char<'a>( - input: ParseInput<'a, '_, Rule>, + input: ParseInput<'a, Rule>, ) -> ParseResult<&'a str> { Ok(input.as_str()) } - fn escaped_quote_pair<'a>( - _: ParseInput<'a, '_, Rule>, - ) -> ParseResult<&'a str> { + fn escaped_quote_pair<'a>(_: ParseInput<'a, Rule>) -> ParseResult<&'a str> { Ok("''") } fn escaped_interpolation<'a>( - _: ParseInput<'a, '_, Rule>, + _: ParseInput<'a, Rule>, ) -> ParseResult<&'a str> { Ok("${") } @@ -514,12 +521,12 @@ impl _ { } fn unquoted_path_component<'a>( - input: ParseInput<'a, '_, Rule>, + input: ParseInput<'a, Rule>, ) -> ParseResult<&'a str> { Ok(input.as_str()) } fn quoted_path_component<'a>( - input: ParseInput<'a, '_, Rule>, + input: ParseInput<'a, Rule>, ) -> ParseResult<&'a str> { Ok(input.as_str()) } @@ -662,7 +669,7 @@ impl _ { )) } fn posix_environment_variable_character<'a>( - input: ParseInput<'a, '_, Rule>, + input: ParseInput<'a, Rule>, ) -> ParseResult<Cow<'a, str>> { Ok(match input.as_str() { "\\\"" => Cow::Owned("\"".to_owned()), @@ -847,7 +854,7 @@ impl _ { Ok(()) } - #[prec_climb(application_expression, make_precclimber())] + #[prec_climb(application_expression, PRECCLIMBER)] fn operator_expression( input: ParseInput<Rule>, l: ParsedExpr, @@ -1076,8 +1083,6 @@ impl _ { } pub fn parse_expr(s: &str) -> ParseResult<ParsedExpr> { - let mut pairs = DhallParser::parse(Rule::final_expression, s)?; - let expr = EntryPoint::final_expression(s, pairs.next().unwrap())?; - assert_eq!(pairs.next(), None); - Ok(expr) + let input = ParseInput::parse(s, Rule::final_expression)?; + Parsers::final_expression(input) } |