summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dhall_proc_macros/src/lib.rs1
-rw-r--r--dhall_proc_macros/src/parser.rs156
-rw-r--r--dhall_syntax/src/parser.rs91
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)
}