diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2021-01-21 09:42:02 +0000 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2021-01-21 17:45:02 +0000 |
commit | 1a93b1f82bc8c21d24e67031c5eca96830e928c7 (patch) | |
tree | 4c3fbfac9f0fbbc31defee03cd460e0400278d30 | |
parent | faa3f30deb32d0a1fd7cb196559762635b22ecfd (diff) |
Fix many warnings.
-rw-r--r-- | autochomp/src/lib.rs | 2 | ||||
-rw-r--r-- | src/chomp/ast/error.rs | 12 | ||||
-rw-r--r-- | src/chomp/ast/substitute.rs | 14 | ||||
-rw-r--r-- | src/chomp/typed/context.rs | 35 | ||||
-rw-r--r-- | src/chomp/typed/error.rs | 96 | ||||
-rw-r--r-- | src/chomp/typed/infer.rs | 37 | ||||
-rw-r--r-- | src/chomp/typed/mod.rs | 30 | ||||
-rw-r--r-- | src/lib.rs | 37 | ||||
-rw-r--r-- | src/lower/mod.rs | 30 | ||||
-rw-r--r-- | src/nibble/convert.rs | 115 | ||||
-rw-r--r-- | src/nibble/cst.rs | 103 |
11 files changed, 325 insertions, 186 deletions
diff --git a/autochomp/src/lib.rs b/autochomp/src/lib.rs index ebe18a6..545b28e 100644 --- a/autochomp/src/lib.rs +++ b/autochomp/src/lib.rs @@ -232,7 +232,7 @@ impl Convert for CallOrVariable1 { Opt26::None1(_) => { let binding = context .lookup(&name) - .ok_or_else(|| ConvertError::UndeclaredName(name.clone()))?; + .ok_or_else(|| ConvertError::UndeclaredName(Box::new(name.clone())))?; Ok(match binding { Binding::Variable(index) => NamedExpression { diff --git a/src/chomp/ast/error.rs b/src/chomp/ast/error.rs index 12d7b90..9e4282b 100644 --- a/src/chomp/ast/error.rs +++ b/src/chomp/ast/error.rs @@ -27,8 +27,8 @@ impl From<SubstituteError> for syn::Error { fn from(e: SubstituteError) -> Self { let msg = e.to_string(); let span = match e { - SubstituteError::FreeParameter { span, .. } => span, - SubstituteError::WrongArgCount { span, .. } => span, + SubstituteError::FreeParameter { span, .. } + | SubstituteError::WrongArgCount { span, .. } => span, }; Self::new(span.unwrap_or_else(Span::call_site), msg) @@ -38,18 +38,14 @@ impl From<SubstituteError> for syn::Error { impl Display for SubstituteError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self::FreeParameter { param, span, name } => { + Self::FreeParameter { param, name, .. } => { if let Some(name) = name { write!(f, "unbound parameter: `{}`", name) } else { write!(f, "unbound parameter: '{}", param.index) } } - Self::WrongArgCount { - call, - expected, - span, - } => { + Self::WrongArgCount { call, expected, .. } => { if call.args.len() == 1 { write!( f, diff --git a/src/chomp/ast/substitute.rs b/src/chomp/ast/substitute.rs index 1a622e1..c7cc03f 100644 --- a/src/chomp/ast/substitute.rs +++ b/src/chomp/ast/substitute.rs @@ -418,13 +418,7 @@ impl Folder for InlineCalls { expr: call.into(), span, }) - } else if call.args.len() != self.function.params.len() { - Err(SubstituteError::WrongArgCount { - call, - expected: self.function.params.len(), - span, - }) - } else { + } else if call.args.len() == self.function.params.len() { let mut expr = self .function .expr @@ -434,6 +428,12 @@ impl Folder for InlineCalls { expr.span = expr.span.or(span); Ok(expr) + } else { + Err(SubstituteError::WrongArgCount { + call, + expected: self.function.params.len(), + span, + }) } } } diff --git a/src/chomp/typed/context.rs b/src/chomp/typed/context.rs index 5c8d398..f3263ce 100644 --- a/src/chomp/typed/context.rs +++ b/src/chomp/typed/context.rs @@ -17,16 +17,6 @@ impl Context { self.vars.len() } - pub fn is_unguarded(&self, var: &Variable) -> Option<bool> { - if self.vars.len() <= var.index { - None - } else if self.unguard_points.is_empty() { - Some(false) - } else { - Some(self.unguard_points[self.unguard_points.len() - 1] + var.index >= self.vars.len()) - } - } - pub fn with_unguard<F: FnOnce(&mut Self) -> R, R>(&mut self, f: F) -> R { self.unguard_points.push(self.vars.len()); let res = f(self); @@ -34,12 +24,23 @@ impl Context { res } - pub fn get_variable_type(&self, var: &Variable) -> Result<&Type, GetVariableError> { - match self.is_unguarded(var) { - None => Err(GetVariableError::FreeVariable), - Some(false) => Err(GetVariableError::GuardedVariable), - Some(true) => Ok(&self.vars[self.vars.len() - var.index - 1]), - } + pub fn get_variable_type(&self, var: Variable) -> Result<&Type, GetVariableError> { + self.vars + .iter() + .nth_back(var.index) + .ok_or(GetVariableError::FreeVariable) + .and_then(|ty| { + self.unguard_points + .last() + .and_then(|point| { + if point + var.index >= self.vars.len() { + Some(ty) + } else { + None + } + }) + .ok_or(GetVariableError::GuardedVariable) + }) } pub fn with_variable_type<F: FnOnce(&mut Self) -> R, R>(&mut self, ty: Type, f: F) -> R { @@ -50,7 +51,7 @@ impl Context { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum GetVariableError { FreeVariable, GuardedVariable, diff --git a/src/chomp/typed/error.rs b/src/chomp/typed/error.rs index bb807fc..5c1e21e 100644 --- a/src/chomp/typed/error.rs +++ b/src/chomp/typed/error.rs @@ -18,91 +18,105 @@ pub struct VariableError { pub name: Option<Name>, } -impl PartialEq for VariableError { - fn eq(&self, other: &Self) -> bool { - todo!() - } -} - -impl Eq for VariableError {} - impl From<VariableError> for syn::Error { fn from(other: VariableError) -> Self { - todo!() + let msg = other.to_string(); + let span = other.span; + Self::new(span.unwrap_or_else(Span::call_site), msg) } } impl Display for VariableError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + match &self.inner { + GetVariableError::FreeVariable => write!(f, "unbound variable: "), + GetVariableError::GuardedVariable => write!(f, "usage of guarded variable: "), + }?; + + if let Some(name) = &self.name { + write!(f, "`{}`", name) + } else { + write!(f, "'{}", self.var.index) + } } } impl Error for VariableError {} -/// A type error when concatenating two terms. #[derive(Debug)] pub enum CatError { - /// The first term was unexpectedly nullable. - FirstNullable(TypedExpression, Option<Span>), - /// The flast set of the first term intersects the first set of the second. - FirstFlastOverlap(Vec<TypedExpression>, Option<Span>, TypedExpression), + FirstNullable { + expr: TypedExpression, + punct: Option<Span>, + }, + FirstFlastOverlap { + first: Vec<TypedExpression>, + punct: Option<Span>, + next: TypedExpression, + }, } -impl PartialEq for CatError { - fn eq(&self, other: &Self) -> bool { - todo!() - } -} - -impl Eq for CatError {} - impl From<CatError> for syn::Error { fn from(other: CatError) -> Self { - todo!() + let msg = other.to_string(); + let span = match other { + CatError::FirstNullable { punct, .. } | CatError::FirstFlastOverlap { punct, .. } => { + punct + } + }; + Self::new(span.unwrap_or_else(Span::call_site), msg) } } impl Display for CatError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + match self { + Self::FirstNullable { .. } => write!(f, "first part of concatenation is nullable"), + Self::FirstFlastOverlap { .. } => { + write!(f, "first set overlaps with preceding flast set") + } + } } } impl Error for CatError {} -/// A type error when alternating two terms. #[derive(Debug)] pub enum AltError { - /// Both terms are nullable. - BothNullable(Vec<TypedExpression>, Option<Span>, TypedExpression), - /// The first sets of the two terms intersect. - FirstOverlap(Vec<TypedExpression>, Option<Span>, TypedExpression), -} - -impl PartialEq for AltError { - fn eq(&self, other: &Self) -> bool { - todo!() - } + BothNullable { + left: Vec<TypedExpression>, + punct: Option<Span>, + right: TypedExpression, + }, + FirstOverlap { + left: Vec<TypedExpression>, + punct: Option<Span>, + right: TypedExpression, + }, } -impl Eq for AltError {} - impl From<AltError> for syn::Error { fn from(other: AltError) -> Self { - todo!() + let msg = other.to_string(); + let span = match other { + AltError::BothNullable { punct, .. } | AltError::FirstOverlap { punct, .. } => punct, + }; + Self::new(span.unwrap_or_else(Span::call_site), msg) } } impl Display for AltError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - todo!() + match self { + Self::BothNullable { .. } => write!(f, "both branches are nullable"), + Self::FirstOverlap { .. } => write!(f, "first sets of both branches overlap"), + } } } impl Error for AltError {} -#[derive(Debug, Eq, PartialEq)] +#[derive(Debug)] pub enum TypeError { Cat(CatError), Alt(AltError), diff --git a/src/chomp/typed/infer.rs b/src/chomp/typed/infer.rs index 8095103..44ea654 100644 --- a/src/chomp/typed/infer.rs +++ b/src/chomp/typed/infer.rs @@ -61,25 +61,18 @@ impl Folder for TypeInfer<'_> { fn fold_alt(&mut self, name: Option<Name>, span: Option<Span>, alt: Alt) -> Self::Out { let first = alt.first.fold(self)?; - let second = alt.second; - let rest = alt.rest; + let second = alt.second.fold(self)?; + let rest = alt + .rest + .into_iter() + .map(|(punct, term)| -> Result<_, TypeError> { Ok((punct, term.fold(self)?)) }) + .collect::<Result<Vec<_>, _>>()?; let punct = alt.punct; - self.context - .with_unguard(|context| -> Result<TypedExpression, TypeError> { - let mut infer = TypeInfer { context }; - let second = second.fold(&mut infer)?; - let rest = rest - .into_iter() - .map(|(punct, term)| -> Result<_, TypeError> { - Ok((punct, term.fold(&mut infer)?)) - }) - .collect::<Result<Vec<_>, _>>()?; - Ok(TypedExpression { - inner: super::Alt::new(first, punct, second, rest)?.into(), - name, - span, - }) - }) + Ok(TypedExpression { + inner: super::Alt::new(first, punct, second, rest)?.into(), + name, + span, + }) } fn fold_fix(&mut self, name: Option<Name>, span: Option<Span>, fix: Fix) -> Self::Out { @@ -111,7 +104,7 @@ impl Folder for TypeInfer<'_> { span: Option<Span>, var: Variable, ) -> Self::Out { - let ty = match self.context.get_variable_type(&var) { + let ty = match self.context.get_variable_type(var) { Ok(ty) => ty.clone(), Err(inner) => { return Err(VariableError { @@ -136,10 +129,10 @@ impl Folder for TypeInfer<'_> { _span: Option<Span>, _param: Parameter, ) -> Self::Out { - todo!() + unimplemented!() } - fn fold_call(&mut self, _name: Option<Name>,_span: Option<Span>, _call: Call) -> Self::Out { - todo!() + fn fold_call(&mut self, _name: Option<Name>, _span: Option<Span>, _call: Call) -> Self::Out { + unimplemented!() } } diff --git a/src/chomp/typed/mod.rs b/src/chomp/typed/mod.rs index e9aed79..2a9e365 100644 --- a/src/chomp/typed/mod.rs +++ b/src/chomp/typed/mod.rs @@ -14,8 +14,8 @@ pub mod lower; mod infer; -pub use self::infer::TypeInfer; use self::error::{AltError, CatError}; +pub use self::infer::TypeInfer; #[derive(Debug, Default, Clone, Eq, Hash, PartialEq)] pub struct Type { @@ -130,7 +130,7 @@ impl Cat { rest: I, ) -> Result<Self, CatError> { if first.get_type().nullable() { - return Err(CatError::FirstNullable(first, punct)); + return Err(CatError::FirstNullable { expr: first, punct }); } iter::once((punct, second)) @@ -138,16 +138,20 @@ impl Cat { .try_fold( (first.get_type().clone(), vec![first]), |(ty, mut terms), (punct, right)| { - if !ty + if ty .flast_set() .intersect_first(right.get_type().first_set()) .is_empty() { - Err(CatError::FirstFlastOverlap(terms, punct, right)) - } else { let ty = ty.cat(right.get_type().clone()); terms.push(right); Ok((ty, terms)) + } else { + Err(CatError::FirstFlastOverlap { + first: terms, + punct, + next: right, + }) } }, ) @@ -184,17 +188,25 @@ impl Alt { (first.get_type().clone(), vec![first]), |(ty, mut terms), (punct, right)| { if ty.nullable() && right.get_type().nullable() { - Err(AltError::BothNullable(terms, punct, right)) - } else if !ty + Err(AltError::BothNullable { + left: terms, + punct, + right, + }) + } else if ty .first_set() .intersect(right.get_type().first_set()) .is_empty() { - Err(AltError::FirstOverlap(terms, punct, right)) - } else { let ty = ty.alt(right.get_type().clone()); terms.push(right); Ok((ty, terms)) + } else { + Err(AltError::FirstOverlap { + left: terms, + punct, + right, + }) } }, ) @@ -8,8 +8,6 @@ #![warn(meta_variable_misuse)] #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] -#![allow(missing_docs)] -#![warn(missing_doc_code_examples)] #![warn(non_ascii_idents)] #![warn(private_doc_tests)] #![warn(single_use_lifetimes)] @@ -23,6 +21,41 @@ #![warn(unused_qualifications)] #![warn(variant_size_differences)] +#![warn(clippy::pedantic)] +#![allow(clippy::filter_map)] +#![allow(clippy::find_map)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::must_use_candidate)] + +#![warn(clippy::dbg_macro)] +#![deny(clippy::exit)] +#![warn(clippy::expect_used)] +#![deny(clippy::float_arithmetic)] +#![warn(clippy::get_unwrap)] +// #![warn(clippy::indexing_slicing)] +#![deny(clippy::integer_division)] +#![warn(clippy::let_underscore_must_use)] +#![warn(clippy::let_unit_value)] +#![warn(clippy::map_err_ignore)] +#![warn(clippy::mem_forget)] +#![deny(clippy::modulo_arithmetic)] +#![warn(clippy::multiple_inherent_impl)] +#![deny(clippy::panic)] +#![warn(clippy::panic_in_result_fn)] +#![deny(clippy::print_stderr)] +#![deny(clippy::print_stdout)] +#![warn(clippy::rest_pat_in_fully_bound_structs)] +#![warn(clippy::str_to_string)] +#![warn(clippy::string_add)] +#![warn(clippy::string_to_string)] +#![deny(clippy::todo)] +#![warn(clippy::unimplemented)] +#![warn(clippy::unneeded_field_pattern)] +#![warn(clippy::unwrap_in_result)] +#![warn(clippy::unwrap_used)] +#![warn(clippy::wildcard_enum_match_arm)] + pub mod chomp; pub mod lower; pub mod nibble; diff --git a/src/lower/mod.rs b/src/lower/mod.rs index aaa39ed..6ad1d0a 100644 --- a/src/lower/mod.rs +++ b/src/lower/mod.rs @@ -8,15 +8,10 @@ use proc_macro2::{Ident, Span, TokenStream, TokenTree}; use quote::{format_ident, quote, quote_spanned}; use syn::{Index, LitStr}; -use crate::chomp::{ - ast, - set::FirstSet, - typed::{ +use crate::chomp::{Name, ast, set::FirstSet, typed::{ lower::{Backend, GenerateCode}, Alt, Cat, Epsilon, Fix, Literal, Type, Typed, TypedExpression, Variable, - }, - Name, -}; + }}; #[derive(Clone, Debug)] struct Ty { @@ -110,7 +105,7 @@ impl RustBackend { None => format_ident!("{}{}", default, index + 1, span = span), Some(name) => { let name = name.to_snake_case().into_ident(span); - let count = name_map.entry(name.clone()).or_insert(0usize); + let count = name_map.entry(name.clone()).or_insert(0_usize); *count += 1; format_ident!("{}{}", name, count) } @@ -128,7 +123,7 @@ impl RustBackend { None => format_ident!("{}{}", default, index + 1, span = span), Some(name) => { let name = name.to_camel_case().into_ident(span); - let count = name_map.entry(name.clone()).or_insert(0usize); + let count = name_map.entry(name.clone()).or_insert(0_usize); *count += 1; format_ident!("{}{}", name, count) } @@ -202,15 +197,14 @@ impl Backend for RustBackend { } }; - if lit.value().len() == 1 { + if let Some(c) = lit.value().chars().next() { self.can_char.insert(id); - let c = lit.value().chars().next().unwrap(); rest.extend(quote_spanned! {span=> - impl From<#name> for char { - fn from(_: #name) -> Self { - #c - } - } + impl From<#name> for char { + fn from(_: #name) -> Self { + #c + } + } }); } @@ -308,7 +302,7 @@ impl Backend for RustBackend { .map(|(idx, _)| name_parts[idx].clone()); let (first_alts, firsts): (Vec<_>, Vec<_>) = tys .iter() - .map(|ty| ty.first_set()) + .map(Type::first_set) .cloned() .enumerate() .filter(|(_, fs)| !fs.is_empty()) @@ -319,7 +313,7 @@ impl Backend for RustBackend { .unzip(); let all_firsts = tys .iter() - .map(|ty| ty.first_set()) + .map(Type::first_set) .cloned() .flat_map(FirstSet::into_iter); diff --git a/src/nibble/convert.rs b/src/nibble/convert.rs index 3310b2a..bfa0be2 100644 --- a/src/nibble/convert.rs +++ b/src/nibble/convert.rs @@ -1,7 +1,7 @@ -use std::{collections::HashMap, fmt}; +use std::{collections::HashMap, fmt, mem}; use proc_macro2::Span; -use syn::punctuated::Pair; +use syn::{punctuated::Pair, Token}; use crate::chomp::{ ast::{self, NamedExpression}, @@ -41,7 +41,9 @@ impl Context { // we make variable binding cheaper by inserting wrong and pulling right. match self.names.get(&name.to_string()).copied() { Some(Binding::Variable(index)) => Some(Binding::Variable(self.vars - index - 1)), - x => x, + Some(Binding::Parameter(index)) => Some(Binding::Parameter(index)), + Some(Binding::Global) => Some(Binding::Global), + None => None, } } @@ -68,7 +70,9 @@ impl Context { #[derive(Clone, Debug)] pub enum ConvertError { - UndeclaredName(Name), + UndeclaredName(Box<Name>), + EmptyCat(Option<Span>), + EmptyAlt(Option<Span>), } impl From<ConvertError> for syn::Error { @@ -76,6 +80,7 @@ impl From<ConvertError> for syn::Error { let msg = e.to_string(); let span = match e { ConvertError::UndeclaredName(name) => name.span(), + ConvertError::EmptyCat(span) | ConvertError::EmptyAlt(span) => span, }; Self::new(span.unwrap_or_else(Span::call_site), msg) @@ -88,6 +93,12 @@ impl fmt::Display for ConvertError { Self::UndeclaredName(name) => { write!(f, "undeclared name: `{}`", name) } + Self::EmptyCat(_) => { + write!(f, "concatenation has no elements") + } + Self::EmptyAlt(_) => { + write!(f, "alternation has no elements") + } } } } @@ -105,7 +116,7 @@ impl Convert for Ident { let binding = context .lookup(&name) - .ok_or_else(|| ConvertError::UndeclaredName(name.clone()))?; + .ok_or_else(|| ConvertError::UndeclaredName(Box::new(name.clone())))?; Ok(match binding { Binding::Variable(index) => NamedExpression { @@ -198,42 +209,37 @@ impl Convert for Term { impl Convert for Cat { fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> { + fn convert_pair( + pair: Pair<Term, Token![.]>, + context: &mut Context, + ) -> Result<(NamedExpression, Option<Span>), ConvertError> { + match pair { + Pair::Punctuated(t, p) => t.convert(context).map(|expr| (expr, Some(p.span))), + Pair::End(t) => t.convert(context).map(|expr| (expr, None)), + } + } + + let span = self.span(); let mut iter = self.0.into_pairs(); - let (first, punct) = match iter.next().unwrap() { - Pair::Punctuated(t, p) => (t.convert(context)?, Some(p.span)), - Pair::End(t) => (t.convert(context)?, None), - }; + let (first, mut punct) = iter + .next() + .ok_or(ConvertError::EmptyCat(span)) + .and_then(|pair| convert_pair(pair, context))?; - let mut rest = Vec::new(); - let (span, _) = iter.try_fold( - ( - first.span.and_then(|s| punct.and_then(|p| s.join(p))), - punct, - ), - |(span, punct), pair| { - let (snd, p) = match pair { - Pair::Punctuated(t, p) => (t.convert(context)?, Some(p.span)), - Pair::End(t) => (t.convert(context)?, None), - }; - - let span = span - .and_then(|s| snd.span.and_then(|t| s.join(t))) - .and_then(|s| p.and_then(|p| s.join(p))); - rest.push((punct, snd)); - Ok((span, p)) - }, - )?; + let mut rest = iter.map(|pair| { + convert_pair(pair, context).map(|(snd, p)| (mem::replace(&mut punct, p), snd)) + }); - let mut iter = rest.into_iter(); - if let Some((punct, second)) = iter.next() { + if let Some(res) = rest.next() { + let (punct, second) = res?; Ok(NamedExpression { name: None, expr: ast::Cat { first: Box::new(first), punct, second: Box::new(second), - rest: iter.collect(), + rest: rest.collect::<Result<_, _>>()?, } .into(), span, @@ -260,42 +266,37 @@ impl Convert for Labelled { impl Convert for Alt { fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> { +fn convert_pair( + pair: Pair<Labelled, Token![|]>, + context: &mut Context, + ) -> Result<(NamedExpression, Option<Span>), ConvertError> { + match pair { + Pair::Punctuated(t, p) => t.convert(context).map(|expr| (expr, Some(p.span))), + Pair::End(t) => t.convert(context).map(|expr| (expr, None)), + } + } + + let span = self.span(); let mut iter = self.0.into_pairs(); - let (first, punct) = match iter.next().unwrap() { - Pair::Punctuated(t, p) => (t.convert(context)?, Some(p.span)), - Pair::End(t) => (t.convert(context)?, None), - }; + let (first, mut punct) = iter + .next() + .ok_or(ConvertError::EmptyAlt(span)) + .and_then(|pair| convert_pair(pair, context))?; - let mut rest = Vec::new(); - let (span, _) = iter.try_fold( - ( - first.span.and_then(|s| punct.and_then(|p| s.join(p))), - punct, - ), - |(span, punct), pair| { - let (snd, p) = match pair { - Pair::Punctuated(t, p) => (t.convert(context)?, Some(p.span)), - Pair::End(t) => (t.convert(context)?, None), - }; - - let span = span - .and_then(|s| snd.span.and_then(|t| s.join(t))) - .and_then(|s| p.and_then(|p| s.join(p))); - rest.push((punct, snd)); - Ok((span, p)) - }, - )?; + let mut rest = iter.map(|pair| { + convert_pair(pair, context).map(|(snd, p)| (mem::replace(&mut punct, p), snd)) + }); - let mut iter = rest.into_iter(); - if let Some((punct, second)) = iter.next() { + if let Some(res) = rest.next() { + let (punct, second) = res?; Ok(NamedExpression { name: None, expr: ast::Alt { first: Box::new(first), punct, second: Box::new(second), - rest: iter.collect(), + rest: rest.collect::<Result<_, _>>()?, } .into(), span, diff --git a/src/nibble/cst.rs b/src/nibble/cst.rs index fc698e8..d8b71b7 100644 --- a/src/nibble/cst.rs +++ b/src/nibble/cst.rs @@ -1,3 +1,5 @@ +use std::fmt; + use proc_macro2::Span; use syn::{ bracketed, @@ -58,7 +60,14 @@ impl<T: Parse> Parse for ArgList<T> { } } -#[derive(Clone)] +impl<T: fmt::Debug> fmt::Debug for ArgList<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ArgList")?; + f.debug_list().entries(self.args.iter()).finish() + } +} + +#[derive(Clone, Debug)] pub struct Call { pub name: Ident, pub args: ArgList<Expression>, @@ -109,6 +118,15 @@ impl Parse for Fix { } } +impl fmt::Debug for Fix { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Fix") + .field("arg", &self.arg) + .field("expr", &self.expr) + .finish() + } +} + #[derive(Clone)] pub struct ParenExpression { paren_token: Paren, @@ -124,6 +142,14 @@ impl Parse for ParenExpression { } } +impl fmt::Debug for ParenExpression { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ParenExpression") + .field("expr", &self.expr) + .finish() + } +} + #[derive(Clone)] pub enum Term { Epsilon(Epsilon), @@ -173,6 +199,19 @@ impl Parse for Term { } } +impl fmt::Debug for Term { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Term::Epsilon(_) => write!(f, "Term::Epsilon"), + Term::Ident(i) => write!(f, "Term::Ident({:?})", i), + Term::Literal(l) => write!(f, "Term::Literal({:?})", l.value()), + Term::Call(c) => write!(f, "Term::Call({:?})", c), + Term::Fix(x) => write!(f, "Term::Fix({:?})", x), + Term::Parens(p) => write!(f, "Term::Parens({:?})", p), + } + } +} + #[derive(Clone)] pub struct Cat(pub Punctuated<Term, Token![.]>); @@ -200,6 +239,13 @@ impl Cat { } } +impl fmt::Debug for Cat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Cat")?; + f.debug_list().entries(self.0.iter()).finish() + } +} + #[derive(Clone)] pub struct Label { colon_tok: Token![:], @@ -220,7 +266,13 @@ impl Parse for Label { } } -#[derive(Clone)] +impl fmt::Debug for Label { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Label").field("label", &self.label).finish() + } +} + +#[derive(Clone, Debug)] pub struct Labelled { pub cat: Cat, pub label: Option<Label>, @@ -251,12 +303,37 @@ impl Parse for Labelled { #[derive(Clone)] pub struct Alt(pub Punctuated<Labelled, Token![|]>); +impl Alt { + pub fn span(&self) -> Option<Span> { + let mut iter = self.0.pairs(); + let span = match iter.next()? { + Pair::Punctuated(t, p) => t.span().and_then(|s| s.join(p.span)), + Pair::End(t) => t.span(), + }?; + + iter.try_fold(span, |span, pair| match pair { + Pair::Punctuated(t, p) => t + .span() + .and_then(|s| span.join(s)) + .and_then(|s| s.join(p.span)), + Pair::End(t) => t.span().and_then(|s| span.join(s)), + }) + } +} + impl Parse for Alt { fn parse(input: ParseStream<'_>) -> syn::Result<Self> { input.call(Punctuated::parse_separated_nonempty).map(Self) } } +impl fmt::Debug for Alt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Alt")?; + f.debug_list().entries(self.0.iter()).finish() + } +} + pub type Expression = Alt; #[derive(Clone)] @@ -299,6 +376,16 @@ impl Parse for LetStatement { } } +impl fmt::Debug for LetStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("LetStatement") + .field("name", &self.name) + .field("args", &self.args) + .field("expr", &self.expr) + .finish() + } +} + #[derive(Clone)] pub struct GoalStatement { match_token: Token![match], @@ -320,7 +407,15 @@ impl Parse for GoalStatement { } } -#[derive(Clone)] +impl fmt::Debug for GoalStatement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("GoalStatement") + .field("expr", &self.expr) + .finish() + } +} + +#[derive(Clone, Debug)] pub struct File { lets: Vec<LetStatement>, goal: GoalStatement, @@ -336,7 +431,7 @@ impl File { let params = stmt .args .into_iter() - .flat_map(|args| args.into_iter()) + .flat_map(ArgList::into_iter) .map(Name::from); let mut context = Context::new(&names, params.clone()); let mut expr = stmt.expr.convert(&mut context)?; |