From fc8fce6facee9bd50958e78f3b177e16ed065c19 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 10 Sep 2019 13:55:35 +0200 Subject: Generalize parse_children and change its invocation --- dhall_syntax/src/parser.rs | 72 +++++++++++------------ pest_consume/src/lib.rs | 95 ++++++++++++++++++++++++++++++- pest_consume_macros/src/parse_children.rs | 27 +++------ 3 files changed, 139 insertions(+), 55 deletions(-) diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index 6c47de4..d86e35a 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -168,7 +168,7 @@ impl Parsers { fn double_quote_literal( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [double_quote_chunk(chunks)..] => { chunks.collect() } @@ -178,7 +178,7 @@ impl Parsers { fn double_quote_chunk( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(e)] => { InterpolatedTextContents::Expr(e) }, @@ -265,7 +265,7 @@ impl Parsers { fn single_quote_literal( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [single_quote_continue(lines)] => { let newline: ParsedText = "\n".to_string().into(); @@ -308,7 +308,7 @@ impl Parsers { fn single_quote_continue( input: ParseInput, ) -> ParseResult>>> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(e), single_quote_continue(lines)] => { let c = InterpolatedTextContents::Expr(e); let mut lines = lines; @@ -393,7 +393,7 @@ impl Parsers { #[alias(expression, shortcut = true)] fn identifier(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [variable(v)] => { spanned(input, Var(v)) }, @@ -402,7 +402,7 @@ impl Parsers { } fn variable(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(l), natural_literal(idx)] => { V(l, idx) }, @@ -444,7 +444,7 @@ impl Parsers { .collect()) } fn path(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [path_component(components)..] => { components.collect() } @@ -455,7 +455,7 @@ impl Parsers { fn local( input: ParseInput, ) -> ParseResult>> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [local_path((prefix, p))] => ImportLocation::Local(prefix, p), )) } @@ -464,19 +464,19 @@ impl Parsers { fn parent_path( input: ParseInput, ) -> ParseResult<(FilePrefix, Vec)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [path(p)] => (FilePrefix::Parent, p) )) } #[alias(local_path)] fn here_path(input: ParseInput) -> ParseResult<(FilePrefix, Vec)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [path(p)] => (FilePrefix::Here, p) )) } #[alias(local_path)] fn home_path(input: ParseInput) -> ParseResult<(FilePrefix, Vec)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [path(p)] => (FilePrefix::Home, p) )) } @@ -484,7 +484,7 @@ impl Parsers { fn absolute_path( input: ParseInput, ) -> ParseResult<(FilePrefix, Vec)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [path(p)] => (FilePrefix::Absolute, p) )) } @@ -498,7 +498,7 @@ impl Parsers { } fn http_raw(input: ParseInput) -> ParseResult>> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [scheme(sch), authority(auth), path(p)] => URL { scheme: sch, authority: auth, @@ -528,7 +528,7 @@ impl Parsers { fn http( input: ParseInput, ) -> ParseResult>> { - Ok(ImportLocation::Remote(parse_children!(input; + Ok(ImportLocation::Remote(parse_children!(input.children(); [http_raw(url)] => url, [http_raw(url), expression(e)] => URL { headers: Some(e), ..url }, ))) @@ -538,7 +538,7 @@ impl Parsers { fn env( input: ParseInput, ) -> ParseResult>> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [environment_variable(v)] => ImportLocation::Env(v), )) } @@ -548,7 +548,7 @@ impl Parsers { } #[alias(environment_variable)] fn posix_environment_variable(input: ParseInput) -> ParseResult { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [posix_environment_variable_character(chars)..] => { chars.collect() }, @@ -593,7 +593,7 @@ impl Parsers { ) -> ParseResult>> { use crate::Import; let mode = ImportMode::Code; - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [import_type(location)] => Import { mode, location, hash: None }, [import_type(location), hash(h)] => Import { mode, location, hash: Some(h) }, )) @@ -611,7 +611,7 @@ impl Parsers { #[alias(expression)] fn import(input: ParseInput) -> ParseResult> { use crate::Import; - let import = parse_children!(input; + let import = parse_children!(input.children(); [import_hashed(imp)] => { Import { mode: ImportMode::Code, ..imp } }, @@ -646,13 +646,13 @@ impl Parsers { #[alias(expression)] fn empty_list_literal(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(e)] => spanned(input, EmptyListLit(e)), )) } fn expression(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [lambda(()), label(l), expression(typ), arrow(()), expression(body)] => { spanned(input, Lam(l, typ, body)) @@ -699,7 +699,7 @@ impl Parsers { fn let_binding( input: ParseInput, ) -> ParseResult<(Label, Option>, Expr, Span)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(name), expression(annot), expression(expr)] => (name, Some(annot), expr, input_to_span(input)), [label(name), expression(expr)] => @@ -749,7 +749,7 @@ impl Parsers { fn application_expression( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(e)] => e, [expression(first), expression(rest)..] => { rest.fold( @@ -770,7 +770,7 @@ impl Parsers { fn first_application_expression( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [Some_(()), expression(e)] => { spanned(input, SomeLit(e)) }, @@ -788,7 +788,7 @@ impl Parsers { fn selector_expression( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(e)] => e, [expression(first), selector(rest)..] => { rest.fold( @@ -811,7 +811,7 @@ impl Parsers { fn selector( input: ParseInput, ) -> ParseResult<(Either>, Span)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(l)] => (Either::Left(l), input_to_span(input)), [labels(ls)] => (Either::Right(ls), input_to_span(input)), // [expression(_e)] => unimplemented!("selection by expression"), // TODO @@ -819,7 +819,7 @@ impl Parsers { } fn labels(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(ls)..] => ls.collect(), )) } @@ -828,7 +828,7 @@ impl Parsers { fn primitive_expression( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [double_literal(n)] => spanned(input, DoubleLit(n)), [natural_literal(n)] => spanned(input, NaturalLit(n)), [integer_literal(n)] => spanned(input, IntegerLit(n)), @@ -854,7 +854,7 @@ impl Parsers { fn non_empty_record_type_or_literal( input: ParseInput, ) -> ParseResult> { - let e = parse_children!(input; + let e = parse_children!(input.children(); [label(first_label), non_empty_record_type(rest)] => { let (first_expr, mut map) = rest; map.insert(first_label, first_expr); @@ -872,7 +872,7 @@ impl Parsers { fn non_empty_record_type( input: ParseInput, ) -> ParseResult<(Expr, DupTreeMap>)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(expr), record_type_entry(entries)..] => { (expr, entries.collect()) } @@ -882,7 +882,7 @@ impl Parsers { fn record_type_entry( input: ParseInput, ) -> ParseResult<(Label, Expr)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(name), expression(expr)] => (name, expr) )) } @@ -890,7 +890,7 @@ impl Parsers { fn non_empty_record_literal( input: ParseInput, ) -> ParseResult<(Expr, DupTreeMap>)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(expr), record_literal_entry(entries)..] => { (expr, entries.collect()) } @@ -900,14 +900,14 @@ impl Parsers { fn record_literal_entry( input: ParseInput, ) -> ParseResult<(Label, Expr)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(name), expression(expr)] => (name, expr) )) } #[alias(expression)] fn union_type(input: ParseInput) -> ParseResult> { - let map = parse_children!(input; + let map = parse_children!(input.children(); [empty_union_type(_)] => Default::default(), [union_type_entry(entries)..] => entries.collect(), ); @@ -921,7 +921,7 @@ impl Parsers { fn union_type_entry( input: ParseInput, ) -> ParseResult<(Label, Option>)> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [label(name), expression(expr)] => (name, Some(expr)), [label(name)] => (name, None), )) @@ -931,7 +931,7 @@ impl Parsers { fn non_empty_list_literal( input: ParseInput, ) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(items)..] => spanned( input, NEListLit(items.collect()) @@ -940,7 +940,7 @@ impl Parsers { } fn final_expression(input: ParseInput) -> ParseResult> { - Ok(parse_children!(input; + Ok(parse_children!(input.children(); [expression(e), EOI(_)] => e )) } diff --git a/pest_consume/src/lib.rs b/pest_consume/src/lib.rs index 6e4b2e3..70aee56 100644 --- a/pest_consume/src/lib.rs +++ b/pest_consume/src/lib.rs @@ -5,7 +5,7 @@ use pest::Span; pub use pest_consume_macros::{make_parser, parse_children}; /// Carries a pest Pair alongside custom user data. -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ParseInput<'input, 'data, Rule, Data> where Rule: pest::RuleType, @@ -14,6 +14,16 @@ where user_data: &'data Data, } +/// Iterator over `ParseInput`s. It is created by `ParseInput::children`. +#[derive(Debug)] +pub struct ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + input: ParseInput<'input, 'data, Rule, Data>, + pairs: pest::iterators::Pairs<'input, Rule>, +} + impl<'input, 'data, Rule, Data> ParseInput<'input, 'data, Rule, Data> where Rule: pest::RuleType, @@ -50,6 +60,15 @@ where } None } + /// Return an iterator over the children of this input + // Can't use `-> impl Iterator` because of weird lifetime limitations + // (see https://github.com/rust-lang/rust/issues/61997). + pub fn children(&self) -> ParseInputs<'input, 'data, Rule, Data> { + ParseInputs { + input: self.clone(), + pairs: self.as_pair().clone().into_inner(), + } + } pub fn user_data(&self) -> &'data Data { self.user_data @@ -66,6 +85,28 @@ where pub fn as_rule(&self) -> Rule { self.pair.as_rule() } + pub fn as_rule_alias(&self) -> String + where + T: PestConsumer, + { + T::rule_alias(self.as_rule()) + } +} + +impl<'input, 'data, Rule, Data> ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + /// Create an error that points to the span of the input. + pub fn error(&self, message: String) -> Error { + self.input.error(message) + } + pub fn aliased_rules(&self) -> Vec + where + T: PestConsumer, + { + self.clone().map(|p| p.as_rule_alias::()).collect() + } } /// Used by the macros. @@ -121,3 +162,55 @@ fn debug_pair(pair: Pair) -> String { aux(&mut s, 0, "".into(), pair); s } + +impl<'input, 'data, Rule, Data> Iterator + for ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + type Item = ParseInput<'input, 'data, Rule, Data>; + + fn next(&mut self) -> Option { + let child_pair = self.pairs.next()?; + let child = self.input.with_pair(child_pair); + Some(child) + } +} + +impl<'input, 'data, Rule, Data> DoubleEndedIterator + for ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + fn next_back(&mut self) -> Option { + let child_pair = self.pairs.next_back()?; + let child = self.input.with_pair(child_pair); + Some(child) + } +} + +// Manual impl to avoid stupid `Data: Clone` trait bound +impl<'input, 'data, Rule, Data> Clone for ParseInput<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + fn clone(&self) -> Self { + ParseInput { + pair: self.pair.clone(), + user_data: self.user_data, + } + } +} + +// Manual impl to avoid stupid `Data: Clone` trait bound +impl<'input, 'data, Rule, Data> Clone for ParseInputs<'input, 'data, Rule, Data> +where + Rule: pest::RuleType, +{ + fn clone(&self) -> Self { + ParseInputs { + input: self.input.clone(), + pairs: self.pairs.clone(), + } + } +} diff --git a/pest_consume_macros/src/parse_children.rs b/pest_consume_macros/src/parse_children.rs index d6474a7..8feef03 100644 --- a/pest_consume_macros/src/parse_children.rs +++ b/pest_consume_macros/src/parse_children.rs @@ -175,7 +175,7 @@ pub fn parse_children( ) -> Result { let input: ParseChildrenInput = syn::parse(input)?; - let i_children_rules = Ident::new("___children_rules", Span::call_site()); + let i_input_rules = Ident::new("___input_rules", Span::call_site()); let i_inputs = Ident::new("___inputs", Span::call_site()); let input_expr = &input.input_expr; @@ -186,29 +186,20 @@ pub fn parse_children( .collect::>>()?; Ok(quote!({ - let #i_children_rules: Vec<_> = #input_expr.as_pair() - .clone() - .into_inner() - .map(|p| p.as_rule()) - .map(::rule_alias) - .collect(); - let #i_children_rules: Vec<&str> = #i_children_rules + #[allow(unused_mut)] + let mut #i_inputs = #input_expr; + + let #i_input_rules = #i_inputs.aliased_rules::(); + let #i_input_rules: Vec<&str> = #i_input_rules .iter() .map(String::as_str) .collect(); - #[allow(unused_mut)] - let mut #i_inputs = #input_expr - .as_pair() - .clone() - .into_inner() - .map(|p| #input_expr.with_pair(p)); - #[allow(unreachable_code)] - match #i_children_rules.as_slice() { + match #i_input_rules.as_slice() { #(#branches,)* - [..] => return Err(#input_expr.error( - format!("Unexpected children: {:?}", #i_children_rules) + [..] => return Err(#i_inputs.error( + format!("Unexpected children: {:?}", #i_input_rules) )), } })) -- cgit v1.2.3