From 5dde11c8ffb13fbaf5dbc9c2b544270c22a7d2f5 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 2 Sep 2019 22:50:16 +0200 Subject: Parse polymorphically in the Embed parameter --- dhall_proc_macros/src/make_parser.rs | 83 +++++++++++++-------- dhall_syntax/src/core/expr.rs | 9 +-- dhall_syntax/src/parser.rs | 140 +++++++++++++++++++---------------- 3 files changed, 130 insertions(+), 102 deletions(-) diff --git a/dhall_proc_macros/src/make_parser.rs b/dhall_proc_macros/src/make_parser.rs index 63ce779..268a639 100644 --- a/dhall_proc_macros/src/make_parser.rs +++ b/dhall_proc_macros/src/make_parser.rs @@ -2,26 +2,25 @@ use quote::quote; use syn::parse::{ParseStream, Result}; use syn::spanned::Spanned; use syn::{ - parse_quote, Error, Expr, Ident, ImplItem, ImplItemMethod, ItemImpl, - ReturnType, Token, + parse_quote, Error, Expr, FnArg, Ident, ImplItem, ImplItemMethod, ItemImpl, + Pat, Token, }; -fn apply_special_attrs( - rule_enum: &Ident, - function: &mut ImplItemMethod, -) -> Result<()> { +fn apply_special_attrs(function: &mut ImplItemMethod) -> Result<()> { + *function = parse_quote!( + #[allow(non_snake_case, dead_code)] + #function + ); + let recognized_attrs: Vec<_> = function .attrs .drain_filter(|attr| attr.path.is_ident("prec_climb")) .collect(); let name = function.sig.ident.clone(); - let output_type = match &function.sig.output { - ReturnType::Default => parse_quote!(()), - ReturnType::Type(_, t) => (**t).clone(), - }; if recognized_attrs.is_empty() { + // do nothing } else if recognized_attrs.len() > 1 { return Err(Error::new( recognized_attrs[1].span(), @@ -37,28 +36,50 @@ fn apply_special_attrs( Ok((child_rule, climber)) })?; - *function = parse_quote!( - fn #name<'a>( - input: ParseInput<'a, #rule_enum>, - ) -> #output_type { - #[allow(non_snake_case, dead_code)] - #function - - #climber.climb( - input.pair.clone().into_inner(), - |p| Self::#child_rule(input.with_pair(p)), - |l, op, r| { - #name(input.clone(), l?, op, r?) - }, - ) + // Get the name of the first (`input`) function argument + let first_arg = function.sig.inputs.first().ok_or_else(|| { + Error::new( + function.sig.inputs.span(), + "a prec_climb function needs 4 arguments", + ) + })?; + let first_arg = match &first_arg { + FnArg::Receiver(_) => return Err(Error::new( + first_arg.span(), + "a prec_climb function should not have a `self` argument", + )), + FnArg::Typed(first_arg) => match &*first_arg.pat{ + Pat::Ident(ident) => &ident.ident, + _ => return Err(Error::new( + first_arg.span(), + "this argument should be a plain identifier instead of a pattern", + )), } - ); - } + }; - *function = parse_quote!( - #[allow(non_snake_case, dead_code)] - #function - ); + function.block = parse_quote!({ + #function + + #climber.climb( + #first_arg.pair.clone().into_inner(), + |p| Self::#child_rule(#first_arg.with_pair(p)), + |l, op, r| { + #name(#first_arg.clone(), l?, op, r?) + }, + ) + }); + // Remove the 3 last arguments to keep only the `input` one + function.sig.inputs.pop(); + function.sig.inputs.pop(); + function.sig.inputs.pop(); + // Check that an argument remains + function.sig.inputs.first().ok_or_else(|| { + Error::new( + function.sig.inputs.span(), + "a prec_climb function needs 4 arguments", + ) + })?; + } Ok(()) } @@ -73,7 +94,7 @@ pub fn make_parser( imp.items .iter_mut() .map(|item| match item { - ImplItem::Method(m) => apply_special_attrs(&rule_enum, m), + ImplItem::Method(m) => apply_special_attrs(m), _ => Ok(()), }) .collect::>()?; diff --git a/dhall_syntax/src/core/expr.rs b/dhall_syntax/src/core/expr.rs index 51b6c47..eeee4d8 100644 --- a/dhall_syntax/src/core/expr.rs +++ b/dhall_syntax/src/core/expr.rs @@ -381,15 +381,10 @@ pub fn rc(x: RawExpr) -> Expr { Expr::from_expr_no_span(x) } -pub(crate) fn spanned( - span: Span, - x: crate::parser::ParsedRawExpr, -) -> crate::parser::ParsedExpr { +pub(crate) fn spanned(span: Span, x: RawExpr) -> Expr { Expr::new(x, span) } -pub(crate) fn unspanned( - x: crate::parser::ParsedRawExpr, -) -> crate::parser::ParsedExpr { +pub(crate) fn unspanned(x: RawExpr) -> Expr { Expr::from_expr_no_span(x) } diff --git a/dhall_syntax/src/parser.rs b/dhall_syntax/src/parser.rs index b1e429b..c2ba19a 100644 --- a/dhall_syntax/src/parser.rs +++ b/dhall_syntax/src/parser.rs @@ -18,10 +18,8 @@ use crate::*; // their own crate because they are quite general and useful. For now they // are here and hopefully you can figure out how they work. -pub(crate) type ParsedRawExpr = RawExpr; -pub(crate) type ParsedExpr = Expr; -type ParsedText = InterpolatedText; -type ParsedTextContents = InterpolatedTextContents; +type ParsedText = InterpolatedText>; +type ParsedTextContents = InterpolatedTextContents>; pub type ParseError = pest::error::Error; @@ -162,7 +160,7 @@ impl crate::Builtin { // 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) { +fn trim_indent(lines: &mut Vec>) { let is_indent = |c: char| c == ' ' || c == '\t'; // There is at least one line so this is safe @@ -250,9 +248,9 @@ impl Parsers { )) } - fn double_quote_literal( + fn double_quote_literal( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { Ok(parse_children!(input; [double_quote_chunk(chunks)..] => { chunks.collect() @@ -260,9 +258,9 @@ impl Parsers { )) } - fn double_quote_chunk( + fn double_quote_chunk( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { Ok(parse_children!(input; [interpolation(e)] => { InterpolatedTextContents::Expr(e) @@ -351,17 +349,17 @@ impl Parsers { Ok(input.as_str()) } - fn single_quote_literal( + fn single_quote_literal( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { Ok(parse_children!(input; [single_quote_continue(lines)] => { - let newline: ParsedText = "\n".to_string().into(); + let newline: ParsedText = "\n".to_string().into(); - let mut lines: Vec = lines + let mut lines: Vec> = lines .into_iter() .rev() - .map(|l| l.into_iter().rev().collect::()) + .map(|l| l.into_iter().rev().collect::>()) .collect(); trim_indent(&mut lines); @@ -370,7 +368,7 @@ impl Parsers { .into_iter() .intersperse(newline) .flat_map(InterpolatedText::into_iter) - .collect::() + .collect::>() } )) } @@ -387,16 +385,18 @@ impl Parsers { ) -> ParseResult<&'a str> { Ok("${") } - fn interpolation(input: ParseInput) -> ParseResult { + fn interpolation( + input: ParseInput, + ) -> ParseResult> { Ok(parse_children!(input; [expression(e)] => e )) } // Returns a vec of lines in reversed order, where each line is also in reversed order. - fn single_quote_continue( + fn single_quote_continue( input: ParseInput, - ) -> ParseResult>> { + ) -> ParseResult>>> { Ok(parse_children!(input; [interpolation(c), single_quote_continue(lines)] => { let c = InterpolatedTextContents::Expr(c); @@ -435,7 +435,7 @@ impl Parsers { )) } - fn builtin(input: ParseInput) -> ParseResult { + fn builtin(input: ParseInput) -> ParseResult> { let s = input.as_str(); let span = input.as_span(); Ok(spanned( @@ -506,7 +506,7 @@ impl Parsers { .map_err(|e| input.error(format!("{}", e))) } - fn identifier(input: ParseInput) -> ParseResult { + fn identifier(input: ParseInput) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [variable(v)] => { @@ -620,7 +620,9 @@ impl Parsers { }) } - fn http_raw(input: ParseInput) -> ParseResult> { + fn http_raw( + input: ParseInput, + ) -> ParseResult>> { Ok(parse_children!(input; [scheme(sch), authority(auth), path(p)] => URL { scheme: sch, @@ -647,7 +649,7 @@ impl Parsers { Ok(input.as_str().to_owned()) } - fn http(input: ParseInput) -> ParseResult> { + fn http(input: ParseInput) -> ParseResult>> { Ok(parse_children!(input; [http_raw(url)] => url, [http_raw(url), import_expression(e)] => @@ -696,9 +698,9 @@ impl Parsers { Ok(()) } - fn import_type( + fn import_type( input: ParseInput, - ) -> ParseResult> { + ) -> ParseResult>> { Ok(parse_children!(input; [missing(_)] => { ImportLocation::Missing @@ -725,9 +727,9 @@ impl Parsers { Ok(Hash::SHA256(hex::decode(hash).unwrap())) } - fn import_hashed( + fn import_hashed( input: ParseInput, - ) -> ParseResult> { + ) -> ParseResult>> { Ok(parse_children!(input; [import_type(location)] => crate::Import {mode: ImportMode::Code, location, hash: None }, @@ -743,7 +745,7 @@ impl Parsers { Ok(()) } - fn import(input: ParseInput) -> ParseResult { + fn import(input: ParseInput) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [import_hashed(imp)] => { @@ -792,7 +794,9 @@ impl Parsers { Ok(()) } - fn empty_list_literal(input: ParseInput) -> ParseResult { + fn empty_list_literal( + input: ParseInput, + ) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [application_expression(e)] => { @@ -801,7 +805,7 @@ impl Parsers { )) } - fn expression(input: ParseInput) -> ParseResult { + fn expression(input: ParseInput) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [lambda(()), label(l), expression(typ), @@ -843,9 +847,9 @@ impl Parsers { )) } - fn let_binding( + fn let_binding( input: ParseInput, - ) -> ParseResult<(Label, Option, ParsedExpr)> { + ) -> ParseResult<(Label, Option>, Expr)> { Ok(parse_children!(input; [label(name), expression(annot), expression(expr)] => (name, Some(annot), expr), @@ -862,12 +866,12 @@ impl Parsers { } #[prec_climb(application_expression, PRECCLIMBER)] - fn operator_expression( + fn operator_expression( input: ParseInput, - l: ParsedExpr, + l: Expr, op: Pair, - r: ParsedExpr, - ) -> ParseResult { + r: Expr, + ) -> ParseResult> { use crate::BinOp::*; use Rule::*; let op = match op.as_rule() { @@ -894,9 +898,9 @@ impl Parsers { Ok(()) } - fn application_expression( + fn application_expression( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { Ok(parse_children!(input; [first_application_expression(e)] => e, [first_application_expression(first), @@ -906,9 +910,9 @@ impl Parsers { )) } - fn first_application_expression( + fn first_application_expression( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [Some_(()), import_expression(e)] => { @@ -924,14 +928,18 @@ impl Parsers { )) } - fn import_expression(input: ParseInput) -> ParseResult { + fn import_expression( + input: ParseInput, + ) -> ParseResult> { Ok(parse_children!(input; [selector_expression(e)] => e, [import(e)] => e, )) } - fn selector_expression(input: ParseInput) -> ParseResult { + fn selector_expression( + input: ParseInput, + ) -> ParseResult> { Ok(parse_children!(input; [primitive_expression(e)] => e, [primitive_expression(first), selector(rest)..] => { @@ -949,7 +957,7 @@ impl Parsers { Ok(parse_children!(input; [label(l)] => Either::Left(l), [labels(ls)] => Either::Right(ls), - [expression(_e)] => unimplemented!("selection by expression"), // TODO + // [expression(_e)] => unimplemented!("selection by expression"), // TODO )) } @@ -959,9 +967,9 @@ impl Parsers { )) } - fn primitive_expression( + fn primitive_expression( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [double_literal(n)] => spanned(span, DoubleLit(n)), @@ -979,21 +987,23 @@ impl Parsers { )) } - fn empty_record_literal( + fn empty_record_literal( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { let span = input.as_span(); Ok(spanned(span, RecordLit(Default::default()))) } - fn empty_record_type(input: ParseInput) -> ParseResult { + fn empty_record_type( + input: ParseInput, + ) -> ParseResult> { let span = input.as_span(); Ok(spanned(span, RecordType(Default::default()))) } - fn non_empty_record_type_or_literal( + fn non_empty_record_type_or_literal( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [label(first_label), non_empty_record_type(rest)] => { @@ -1009,9 +1019,9 @@ impl Parsers { )) } - fn non_empty_record_type( + fn non_empty_record_type( input: ParseInput, - ) -> ParseResult<(ParsedExpr, DupTreeMap)> { + ) -> ParseResult<(Expr, DupTreeMap>)> { Ok(parse_children!(input; [expression(expr), record_type_entry(entries)..] => { (expr, entries.collect()) @@ -1019,17 +1029,17 @@ impl Parsers { )) } - fn record_type_entry( + fn record_type_entry( input: ParseInput, - ) -> ParseResult<(Label, ParsedExpr)> { + ) -> ParseResult<(Label, Expr)> { Ok(parse_children!(input; [label(name), expression(expr)] => (name, expr) )) } - fn non_empty_record_literal( + fn non_empty_record_literal( input: ParseInput, - ) -> ParseResult<(ParsedExpr, DupTreeMap)> { + ) -> ParseResult<(Expr, DupTreeMap>)> { Ok(parse_children!(input; [expression(expr), record_literal_entry(entries)..] => { (expr, entries.collect()) @@ -1037,15 +1047,15 @@ impl Parsers { )) } - fn record_literal_entry( + fn record_literal_entry( input: ParseInput, - ) -> ParseResult<(Label, ParsedExpr)> { + ) -> ParseResult<(Label, Expr)> { Ok(parse_children!(input; [label(name), expression(expr)] => (name, expr) )) } - fn union_type(input: ParseInput) -> ParseResult { + fn union_type(input: ParseInput) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [empty_union_type(_)] => { @@ -1061,18 +1071,18 @@ impl Parsers { Ok(()) } - fn union_type_entry( + fn union_type_entry( input: ParseInput, - ) -> ParseResult<(Label, Option)> { + ) -> ParseResult<(Label, Option>)> { Ok(parse_children!(input; [label(name), expression(expr)] => (name, Some(expr)), [label(name)] => (name, None), )) } - fn non_empty_list_literal( + fn non_empty_list_literal( input: ParseInput, - ) -> ParseResult { + ) -> ParseResult> { let span = input.as_span(); Ok(parse_children!(input; [expression(items)..] => spanned( @@ -1082,14 +1092,16 @@ impl Parsers { )) } - fn final_expression(input: ParseInput) -> ParseResult { + fn final_expression( + input: ParseInput, + ) -> ParseResult> { Ok(parse_children!(input; [expression(e), EOI(_)] => e )) } } -pub fn parse_expr(s: &str) -> ParseResult { +pub fn parse_expr(s: &str) -> ParseResult> { let input = ParseInput::parse(s, Rule::final_expression)?; Parsers::final_expression(input) } -- cgit v1.2.3