From fce22234591b4e3bdd2cd4227459d7779e4859c9 Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Mon, 23 Nov 2020 14:34:36 +0000 Subject: Introduce guarded variables --- src/ast/mod.rs | 297 ++++++++++++++++++++++++++++++++----------------------- src/ast/typed.rs | 224 +++++++++++++++++++++++------------------ src/main.rs | 40 +++++--- 3 files changed, 329 insertions(+), 232 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 07d32ec..df9fe0c 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1,26 +1,21 @@ -use std::collections::BTreeSet; -use std::collections::HashMap; -use std::convert::Infallible; -use std::error::Error; -use std::fmt::Display; - -use proc_macro2::Span; -use proc_macro2::TokenStream; -use proc_macro2::TokenTree; -use quote::format_ident; -use quote::quote; +use self::typed::{FirstContext, FirstSet, FlastContext, FlastSet, NullContext, Type}; +use proc_macro2::{Span, TokenStream, TokenTree}; +use quote::{format_ident, quote}; +use std::collections::{BTreeSet, HashMap}; use syn::{Ident, LitStr, Token}; -use typed::FirstSetContext; -use typed::FlastSetContext; -use typed::NullContext; - -use self::typed::FirstSet; -use self::typed::FlastSet; -use self::typed::Type; pub mod convert; pub mod typed; +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum Never {} + +impl From for syn::Error { + fn from(other: Never) -> Self { + match other {} + } +} + fn fix R>(init: R, mut step: F) -> R { let mut res = init; let mut last = None; @@ -45,65 +40,71 @@ impl Epsilon { } impl Type for Epsilon { - type Err = Infallible; + type Err = Never; fn closed(&self, _depth: usize) -> Result<(), VariableError> { Ok(()) } - fn is_nullable(&self, _context: &mut C) -> Option { + fn is_nullable(&self, _context: &mut NullContext<'_>) -> Option { Some(true) } - fn first_set(&self, _context: &mut C) -> Option { + fn first_set(&self, _context: &mut FirstContext<'_>) -> Option { Some(FirstSet::new()) } - fn flast_set(&self, _context: &mut C) -> Option { + fn flast_set(&self, _context: &mut FlastContext) -> Option { Some(FlastSet::new()) } - fn well_typed(self, _context: &mut C) -> Result { - Ok(Typed { - kind: TypeKind::Epsilon, - nullable: true, - first_set: FirstSet::new(), - flast_set: FlastSet::new(), - }) + fn well_typed(self, _context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { + Ok(( + Typed { + kind: TypeKind::Epsilon, + nullable: true, + first_set: FirstSet::new(), + flast_set: FlastSet::new(), + }, + self.span, + )) } } pub type Literal = LitStr; impl Type for Literal { - type Err = Infallible; + type Err = Never; fn closed(&self, _depth: usize) -> Result<(), VariableError> { Ok(()) } - fn is_nullable(&self, _context: &mut C) -> Option { + fn is_nullable(&self, _context: &mut NullContext<'_>) -> Option { Some(self.value().is_empty()) } - fn first_set(&self, _context: &mut C) -> Option { + fn first_set(&self, _context: &mut FirstContext<'_>) -> Option { Some(FirstSet::of_str(&self.value())) } - fn flast_set(&self, _context: &mut C) -> Option { + fn flast_set(&self, _context: &mut FlastContext) -> Option { Some(FlastSet::new()) } - fn well_typed(self, _context: &mut C) -> Result { + fn well_typed(self, _context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { let value = self.value(); let nullable = value.is_empty(); let first_set = FirstSet::of_str(&value); - Ok(Typed { - kind: TypeKind::Literal(value), - nullable, - first_set, - flast_set: FlastSet::new(), - }) + Ok(( + Typed { + kind: TypeKind::Literal(value), + nullable, + first_set, + flast_set: FlastSet::new(), + }, + self.span(), + )) } } @@ -131,26 +132,26 @@ impl Type for Cat { self.fst.closed(depth).and_then(|()| self.snd.closed(depth)) } - fn is_nullable(&self, context: &mut C) -> Option { - Some(self.fst.is_nullable(context)? && self.snd.is_nullable(context)?) + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option { + Some(self.fst.is_nullable(context)? && context.unguard(|ctx| self.snd.is_nullable(ctx))?) } - fn first_set(&self, context: &mut C) -> Option { + fn first_set(&self, context: &mut FirstContext<'_>) -> Option { let set = self.fst.first_set(context)?; - if self.fst.is_nullable(context)? { - Some(set.union(self.snd.first_set(context)?)) + if self.fst.is_nullable(&mut context.as_null())? { + Some(set.union(context.unguard(|ctx| self.snd.first_set(ctx))?)) } else { Some(set) } } - fn flast_set(&self, context: &mut C) -> Option { - let set = self.snd.flast_set(context)?; + fn flast_set(&self, context: &mut FlastContext) -> Option { + let set = context.unguard(|ctx| self.snd.flast_set(ctx))?; - if self.snd.is_nullable(context)? { + if context.as_null().unguard(|ctx| self.snd.is_nullable(ctx))? { Some( - set.union_first(self.snd.first_set(context)?) + set.union_first(context.as_first().unguard(|ctx| self.snd.first_set(ctx))?) .union(self.fst.flast_set(context)?), ) } else { @@ -158,18 +159,22 @@ impl Type for Cat { } } - fn well_typed(self, context: &mut C) -> Result { - let fst = self + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { + let (fst, fst_span) = self .fst .well_typed(context) .map_err(|e| CatError::First(Box::new(e)))?; - let snd = self + let (snd, snd_span) = self .snd .well_typed(context) .map_err(|e| CatError::Second(Box::new(e)))?; if fst.is_nullable() { - Err(CatError::FirstNullable(fst)) + Err(CatError::FirstNullable { + punct: self.punct.span, + fst_span, + fst, + }) } else if !fst.flast_set().intersect_first(&snd.first_set()).is_empty() { Err(CatError::FirstFlastOverlap(fst, snd)) } else { @@ -184,12 +189,15 @@ impl Type for Cat { } else { snd.flast_set().clone() }; - Ok(Typed { - kind: TypeKind::Cat(Box::new(fst), Box::new(snd)), - nullable, - first_set, - flast_set, - }) + Ok(( + Typed { + kind: TypeKind::Cat(Box::new(fst), Box::new(snd)), + nullable, + first_set, + flast_set, + }, + fst_span.join(snd_span).unwrap_or_else(Span::call_site), + )) } } } @@ -198,13 +206,30 @@ impl Type for Cat { pub enum CatError { First(Box), Second(Box), - FirstNullable(Typed), + FirstNullable { + punct: Span, + fst_span: Span, + fst: Typed, + }, FirstFlastOverlap(Typed, Typed), } -impl Display for CatError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() +impl From for syn::Error { + fn from(other: CatError) -> Self { + match other { + CatError::First(e) => (*e).into(), + CatError::Second(e) => (*e).into(), + CatError::FirstNullable { + punct, fst_span, .. + } => { + let mut err = Self::new(punct, "first item in sequence cannot accept empty string"); + err.combine(Self::new(fst_span, "this can accept empty string")); + err + } + CatError::FirstFlastOverlap(fst, snd) => { + todo!() + } + } } } @@ -234,11 +259,11 @@ impl Type for Alt { .and_then(|()| self.right.closed(depth)) } - fn is_nullable(&self, context: &mut C) -> Option { + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option { Some(self.left.is_nullable(context)? || self.right.is_nullable(context)?) } - fn first_set(&self, context: &mut C) -> Option { + fn first_set(&self, context: &mut FirstContext<'_>) -> Option { Some( self.left .first_set(context)? @@ -246,7 +271,7 @@ impl Type for Alt { ) } - fn flast_set(&self, context: &mut C) -> Option { + fn flast_set(&self, context: &mut FlastContext) -> Option { Some( self.left .flast_set(context)? @@ -254,12 +279,12 @@ impl Type for Alt { ) } - fn well_typed(self, context: &mut C) -> Result { - let left = self + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { + let (left, left_span) = self .left .well_typed(context) .map_err(|e| AltError::Left(Box::new(e)))?; - let right = self + let (right, right_span) = self .right .well_typed(context) .map_err(|e| AltError::Right(Box::new(e)))?; @@ -272,12 +297,15 @@ impl Type for Alt { let nullable = false; let first_set = left.first_set().clone().union(right.first_set().clone()); let flast_set = left.flast_set().clone().union(right.flast_set().clone()); - Ok(Typed { - kind: TypeKind::Alt(Box::new(left), Box::new(right)), - nullable, - first_set, - flast_set, - }) + Ok(( + Typed { + kind: TypeKind::Alt(Box::new(left), Box::new(right)), + nullable, + first_set, + flast_set, + }, + left_span.join(right_span).unwrap_or_else(Span::call_site), + )) } } } @@ -290,8 +318,8 @@ pub enum AltError { FirstOverlap(Typed, Typed), } -impl Display for AltError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl From for syn::Error { + fn from(other: AltError) -> Self { todo!() } } @@ -320,7 +348,7 @@ impl Type for Fix { self.inner.closed(depth + 1) } - fn is_nullable(&self, context: &mut C) -> Option { + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option { fix(Some(false), |last| { last.as_ref() .copied() @@ -328,8 +356,8 @@ impl Type for Fix { }) } - fn first_set(&self, context: &mut C) -> Option { - let nullable = self.is_nullable(context)?; + fn first_set(&self, context: &mut FirstContext<'_>) -> Option { + let nullable = self.is_nullable(&mut context.as_null())?; fix(Some(FirstSet::new()), |last| { last.as_ref().cloned().and_then(|first_set| { context.push_first_set(nullable, first_set, |ctx| self.inner.first_set(ctx)) @@ -337,9 +365,9 @@ impl Type for Fix { }) } - fn flast_set(&self, context: &mut C) -> Option { - let nullable = self.is_nullable(context)?; - let first_set = self.first_set(context)?; + fn flast_set(&self, context: &mut FlastContext) -> Option { + let nullable = self.is_nullable(&mut context.as_null())?; + let first_set = self.first_set(&mut context.as_first())?; fix(Some(FlastSet::new()), |last| { last.as_ref().cloned().and_then(|flast_set| { context.push_flast_set(nullable, first_set.clone(), flast_set, |ctx| { @@ -349,22 +377,28 @@ impl Type for Fix { }) } - fn well_typed(self, context: &mut C) -> Result { - self.inner.closed(context.get_depth() + 1)?; + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { + self.inner.closed(context.depth() + 1)?; - let nullable = self.is_nullable(context).unwrap(); - let first_set = self.first_set(context).unwrap(); + let span = self.span; + let nullable = self.is_nullable(&mut context.as_null()).unwrap(); + let first_set = self.first_set(&mut context.as_first()).unwrap(); let flast_set = self.flast_set(context).unwrap(); context .push_flast_set(nullable, first_set.clone(), flast_set.clone(), |ctx| { self.inner.well_typed(ctx) }) - .map(|inner| Typed { - kind: TypeKind::Fix(Box::new(inner)), - nullable, - first_set, - flast_set, + .map(|(inner, _)| { + ( + Typed { + kind: TypeKind::Fix(Box::new(inner)), + nullable, + first_set, + flast_set, + }, + span, + ) }) } } @@ -392,35 +426,50 @@ impl Type for Variable { } } - fn is_nullable(&self, context: &mut C) -> Option { - context.get_nullable(self.index) + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option { + context.is_nullable(self.index) } - fn first_set(&self, context: &mut C) -> Option { - context.get_first_set(self.index).cloned() + fn first_set(&self, context: &mut FirstContext<'_>) -> Option { + context.first_set(self.index).cloned() } - fn flast_set(&self, context: &mut C) -> Option { - context.get_flast_set(self.index).cloned() + fn flast_set(&self, context: &mut FlastContext) -> Option { + context.flast_set(self.index).cloned() } - fn well_typed(self, context: &mut C) -> Result { - self.closed(context.get_depth()).map(|()| Typed { - kind: TypeKind::Variable(self.index), - nullable: self.is_nullable(context).unwrap(), - first_set: self.first_set(context).unwrap(), - flast_set: self.flast_set(context).unwrap(), - }) + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { + self.closed(context.depth()) + .map(|()| context.is_guarded(self.index).unwrap()) + .and_then(|b| { + if b { + Ok(()) + } else { + Err(VariableError::GuardedVariable(self.clone())) + } + }) + .map(|()| { + ( + Typed { + kind: TypeKind::Variable(self.index), + nullable: context.is_nullable(self.index).unwrap(), + first_set: context.first_set(self.index).cloned().unwrap(), + flast_set: context.flast_set(self.index).cloned().unwrap(), + }, + self.name.span(), + ) + }) } } #[derive(Debug)] pub enum VariableError { FreeVariable(Variable), + GuardedVariable(Variable), } -impl Display for VariableError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl From for syn::Error { + fn from(_: VariableError) -> Self { todo!() } } @@ -439,25 +488,25 @@ impl Call { } impl Type for Call { - type Err = Infallible; + type Err = Never; fn closed(&self, _depth: usize) -> Result<(), VariableError> { todo!() } - fn is_nullable(&self, _context: &mut C) -> Option { + fn is_nullable(&self, _context: &mut NullContext<'_>) -> Option { todo!() } - fn first_set(&self, _context: &mut C) -> Option { + fn first_set(&self, _context: &mut FirstContext<'_>) -> Option { todo!() } - fn flast_set(&self, _context: &mut C) -> Option { + fn flast_set(&self, _context: &mut FlastContext) -> Option { todo!() } - fn well_typed(self, _context: &mut C) -> Result { + fn well_typed(self, _context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { todo!() } } @@ -488,7 +537,7 @@ impl Type for Term { } } - fn is_nullable(&self, context: &mut C) -> Option { + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option { match self { Self::Epsilon(e) => e.is_nullable(context), Self::Literal(e) => e.is_nullable(context), @@ -500,7 +549,7 @@ impl Type for Term { } } - fn first_set(&self, context: &mut C) -> Option { + fn first_set(&self, context: &mut FirstContext<'_>) -> Option { match self { Self::Epsilon(e) => e.first_set(context), Self::Literal(e) => e.first_set(context), @@ -512,7 +561,7 @@ impl Type for Term { } } - fn flast_set(&self, context: &mut C) -> Option { + fn flast_set(&self, context: &mut FlastContext) -> Option { match self { Self::Epsilon(e) => e.flast_set(context), Self::Literal(e) => e.flast_set(context), @@ -524,7 +573,7 @@ impl Type for Term { } } - fn well_typed(self, context: &mut C) -> Result { + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err> { match self { Self::Epsilon(e) => e.well_typed(context).map_err(TermError::from), Self::Literal(e) => e.well_typed(context).map_err(TermError::from), @@ -544,8 +593,8 @@ pub enum TermError { Variable(VariableError), } -impl From for TermError { - fn from(other: Infallible) -> Self { +impl From for TermError { + fn from(other: Never) -> Self { match other {} } } @@ -568,14 +617,16 @@ impl From for TermError { } } -impl Display for TermError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - todo!() +impl From for syn::Error { + fn from(other: TermError) -> Self { + match other { + TermError::Cat(e) => e.into(), + TermError::Alt(e) => e.into(), + TermError::Variable(e) => e.into(), + } } } -impl Error for TermError {} - #[derive(Clone, Debug, Eq, PartialEq, Hash)] enum TypeKind { Epsilon, diff --git a/src/ast/typed.rs b/src/ast/typed.rs index a0b8d1b..6ccd0ac 100644 --- a/src/ast/typed.rs +++ b/src/ast/typed.rs @@ -1,3 +1,5 @@ +use proc_macro2::Span; + use super::Typed; use super::VariableError; use std::collections::BTreeSet; @@ -36,8 +38,14 @@ impl FirstSet { inner: self.inner.intersection(&other.inner).copied().collect(), } } +} + +impl IntoIterator for FirstSet { + type Item = char; - pub fn into_iter(self) -> impl Iterator { + type IntoIter = as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { self.inner.into_iter() } } @@ -81,163 +89,183 @@ impl FlastSet { } } -pub trait NullContext { - type PushNull: NullContext; - - fn get_depth(&self) -> usize; - - fn get_nullable(&self, index: usize) -> Option; - - fn push_nullable R, R>(&mut self, nullable: bool, f: F) -> R; +#[derive(Debug)] +pub struct NullContext<'a> { + inner: &'a mut FlastContext } -impl NullContext for Vec { - type PushNull = Self; - - fn get_depth(&self) -> usize { - self.len() +impl NullContext<'_> { + pub fn depth(&self) -> usize { + self.inner.depth() } - fn get_nullable(&self, index: usize) -> Option { - self.get(self.len() - index - 1).copied() + pub fn is_guarded(&self, index: usize) -> Option { + self.inner.is_guarded(index) } - fn push_nullable R, R>(&mut self, nullable: bool, f: F) -> R { - self.push(nullable); - let res = f(self); - self.pop(); - res - } -} - -impl NullContext for Vec<(bool, FirstSet)> { - type PushNull = Self; - - fn get_depth(&self) -> usize { - self.len() + pub fn unguard) -> R, R>(&mut self, f: F) -> R { + self.inner.unguard(|ctx| f(&mut NullContext {inner: ctx})) } - fn get_nullable(&self, index: usize) -> Option { - self.get(self.len() - index - 1).map(|(null, _)| null).copied() + pub fn is_nullable(&self, index: usize) -> Option { + self.inner.is_nullable(index) } - fn push_nullable R, R>(&mut self, nullable: bool, f: F) -> R { - self.push((nullable, FirstSet::new())); - let res = f(self); - self.pop(); - res + pub fn push_nullable) -> R, R>( + &mut self, + nullable: bool, + f: F, + ) -> R { + self.inner.push_nullable(nullable, f) } } -impl NullContext for Vec<(bool, FirstSet, FlastSet)> { - type PushNull = Self; +#[derive(Debug)] +pub struct FirstContext<'a> { + inner: &'a mut FlastContext, +} - fn get_depth(&self) -> usize { - self.len() +impl FirstContext<'_> { + pub fn depth(&self) -> usize { + self.inner.depth() } - fn get_nullable(&self, index: usize) -> Option { - self.get(self.len() - index - 1).map(|(null, _, _)| null).copied() + pub fn is_guarded(&self, index: usize) -> Option { + self.inner.is_guarded(index) } - fn push_nullable R, R>(&mut self, nullable: bool, f: F) -> R { - self.push((nullable, FirstSet::new(), FlastSet::new())); - let res = f(self); - self.pop(); - res + pub fn unguard) -> R, R>(&mut self, f: F) -> R { + self.inner.unguard(|ctx| { + f(&mut FirstContext{inner: ctx}) + }) } -} -pub trait FirstSetContext: NullContext { - type PushFirstSet: FirstSetContext; - - fn get_first_set(&self, index: usize) -> Option<&FirstSet>; + pub fn is_nullable(&self, index: usize) -> Option { + self.inner.is_nullable(index) + } - fn push_first_set R, R>( + pub fn push_nullable) -> R, R>( &mut self, nullable: bool, - first_set: FirstSet, f: F, - ) -> R; -} - -impl FirstSetContext for Vec<(bool, FirstSet)> { - type PushFirstSet = Self; + ) -> R { + self.inner.push_nullable(nullable, f) + } - fn get_first_set(&self, index: usize) -> Option<&FirstSet> { - self.get(self.len() - index - 1).map(|(_, first_set)| first_set) + pub fn first_set(&self, index: usize) -> Option<&FirstSet> { + self.inner.first_set(index) } - fn push_first_set R, R>( + pub fn push_first_set) -> R, R>( &mut self, nullable: bool, first_set: FirstSet, f: F, ) -> R { - self.push((nullable, first_set)); - let res = f(self); - self.pop(); - res + self.inner.push_first_set(nullable, first_set, f) + } + + pub fn as_null(&mut self) -> NullContext<'_> { + NullContext { + inner: self.inner + } } } -impl FirstSetContext for Vec<(bool, FirstSet, FlastSet)> { - type PushFirstSet = Self; +#[derive(Debug)] +pub struct FlastContext { + data: Vec<(bool, FirstSet, FlastSet)>, + guard: Vec, +} + +impl FlastContext { + pub fn new() -> Self { + Self { + data: Vec::new(), + guard: Vec::new(), + } + } + + pub fn depth(&self) -> usize { + self.data.len() + } + + pub fn is_guarded(&self, index: usize) -> Option { + if self.data.len() <= index { + None + } else if self.guard.is_empty() { + Some(false) + } else { + Some(self.guard[self.guard.len() - 1] + index >= self.data.len()) + } + } + + pub fn unguard R, R>(&mut self, f: F) -> R { + self.guard.push(self.data.len()); + let res = f(self); + self.guard.pop(); + res + } - fn get_first_set(&self, index: usize) -> Option<&FirstSet> { - self.get(self.len() - index - 1).map(|(_, first_set, _)| first_set) + pub fn is_nullable(&self, index: usize) -> Option { + self.data.get(index).map(|(null, _, _)| *null) } - fn push_first_set R, R>( + pub fn push_nullable) -> R, R>( &mut self, nullable: bool, - first_set: FirstSet, f: F, ) -> R { - self.push((nullable, first_set, FlastSet::new())); - let res = f(self); - self.pop(); - res + self.push_first_set(nullable, FirstSet::new(), |ctx| { + f(&mut ctx.as_null()) + }) } -} - -pub trait FlastSetContext: FirstSetContext { - type PushFlastSet: FlastSetContext; - fn get_flast_set(&self, index: usize) -> Option<&FlastSet>; + pub fn first_set(&self, index: usize) -> Option<&FirstSet> { + self.data.get(index).map(|(_, first, _)| first) + } - fn push_flast_set R, R>( + pub fn push_first_set) -> R, R>( &mut self, nullable: bool, first_set: FirstSet, - flast_set: FlastSet, f: F, - ) -> R; -} - -impl FlastSetContext for Vec<(bool, FirstSet, FlastSet)> { - type PushFlastSet = Self; + ) -> R { + self.push_flast_set(nullable, first_set, FlastSet::new(), |ctx| f(&mut ctx.as_first())) + } - fn get_flast_set(&self, index: usize) -> Option<&FlastSet> { - self.get(self.len() - index - 1).map(|(_, _, flast_set)| flast_set) + pub fn flast_set(&self, index: usize) -> Option<&FlastSet> { + self.data.get(index).map(|(_, _, flast)| flast) } - fn push_flast_set R, R>( + pub fn push_flast_set R, R>( &mut self, nullable: bool, first_set: FirstSet, flast_set: FlastSet, f: F, ) -> R { - self.push((nullable, first_set, flast_set)); + self.data.push((nullable, first_set, flast_set)); let res = f(self); - self.pop(); + self.data.pop(); res } + + pub fn as_first(&mut self) -> FirstContext<'_> { + FirstContext { + inner: self + } + } + + pub fn as_null(&mut self) -> NullContext<'_> { + NullContext{ + inner: self + } + } } pub trait Type { - type Err: Display; + type Err: Into; /// # Errors /// Returns [`Err`] if there is a variable with an index greater than or equal @@ -247,19 +275,19 @@ pub trait Type { /// # Errors /// Returns [`None`] only if `self.closed(context.get_depth())` returns an /// [`Err`]. - fn is_nullable(&self, context: &mut C) -> Option; + fn is_nullable(&self, context: &mut NullContext<'_>) -> Option; /// # Errors /// Returns [`None`] only if `self.closed(context.get_depth())` returns an /// [`Err`]. - fn first_set(&self, context: &mut C) -> Option; + fn first_set(&self, context: &mut FirstContext<'_>) -> Option; /// # Errors /// Returns [`None`] only if `self.closed(context.get_depth())` returns an /// [`Err`]. - fn flast_set(&self, context: &mut C) -> Option; + fn flast_set(&self, context: &mut FlastContext) -> Option; /// # Errors /// Returns an [`Err`] if this term is not well typed. - fn well_typed(self, context: &mut C) -> Result; + fn well_typed(self, context: &mut FlastContext) -> Result<(Typed, Span), Self::Err>; } diff --git a/src/main.rs b/src/main.rs index 9eb762a..c9b12b0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,22 +1,40 @@ use chomp::{ ast::{ convert::{Context, Convert}, - typed::Type, + typed::{FlastContext, Type}, }, nibble::Expression, }; use proc_macro2::Span; -use std::io::{self, Error, ErrorKind, Read, Write}; +use std::process::exit; +use std::{ + error::Error, + io::{self, Read, Write}, +}; use syn::Ident; -fn main() -> io::Result<()> { +fn main() { let mut input = String::new(); - io::stdin().read_to_string(&mut input)?; - let nibble: Expression = - syn::parse_str(&input).map_err(|e| Error::new(ErrorKind::InvalidData, e))?; - let term = nibble.convert(&Context::new()); - // FIXME: better error handling here - let typed = term.well_typed(&mut Vec::new()).unwrap(); - let code = typed.emit_code(Ident::new("Ast", Span::call_site())); - write!(io::stdout(), "{:#}", code) + let res = io::stdin() + .read_to_string(&mut input) + .map_err(|e| Box::new(e) as Box) + .and_then(|_| syn::parse_str(&input).map_err(|e| Box::new(e) as Box)) + .map(|nibble: Expression| { + nibble + .convert(&Context::new()) + .well_typed(&mut FlastContext::new()) + }) + .map(|res| match res { + Ok((typed, _)) => typed.emit_code(Ident::new("Ast", Span::call_site())), + Err(e) => syn::Error::from(e).to_compile_error(), + }) + .and_then(|code| { + write!(io::stdout(), "{:#}", code).map_err(|e| Box::new(e) as Box) + }); + + if let Err(e) = res { + eprintln!("{}", e); + drop(e); + exit(1) + } } -- cgit v1.2.3