summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2021-01-21 09:42:02 +0000
committerGreg Brown <gmb60@cam.ac.uk>2021-01-21 17:45:02 +0000
commit1a93b1f82bc8c21d24e67031c5eca96830e928c7 (patch)
tree4c3fbfac9f0fbbc31defee03cd460e0400278d30
parentfaa3f30deb32d0a1fd7cb196559762635b22ecfd (diff)
Fix many warnings.
-rw-r--r--autochomp/src/lib.rs2
-rw-r--r--src/chomp/ast/error.rs12
-rw-r--r--src/chomp/ast/substitute.rs14
-rw-r--r--src/chomp/typed/context.rs35
-rw-r--r--src/chomp/typed/error.rs96
-rw-r--r--src/chomp/typed/infer.rs37
-rw-r--r--src/chomp/typed/mod.rs30
-rw-r--r--src/lib.rs37
-rw-r--r--src/lower/mod.rs30
-rw-r--r--src/nibble/convert.rs115
-rw-r--r--src/nibble/cst.rs103
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,
+ })
}
},
)
diff --git a/src/lib.rs b/src/lib.rs
index cd8a43a..a94e08c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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)?;