From dfc08ff2c6580bbeb3951b223e0332546ba3b0d9 Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Thu, 6 May 2021 19:40:59 +0100 Subject: Introduce lambda expressions. --- src/nibble/convert.rs | 133 ++++++++++++++++++------- src/nibble/mod.rs | 269 +++++++++++++++++++++----------------------------- 2 files changed, 207 insertions(+), 195 deletions(-) (limited to 'src/nibble') diff --git a/src/nibble/convert.rs b/src/nibble/convert.rs index e5e8c5d..ca6c95a 100644 --- a/src/nibble/convert.rs +++ b/src/nibble/convert.rs @@ -1,18 +1,18 @@ use std::{fmt, mem}; use proc_macro2::Span; -use syn::{punctuated::Pair, Token}; +use syn::{punctuated::Pair, spanned::Spanned, Token}; -use crate::chomp::{ - ast::{self, NamedExpression}, - Name, -}; +use crate::chomp::{ast::{self, NamedExpression}, name::{Content, Name}}; -use super::{Alt, Call, Cat, Expression, Fix, Ident, Labelled, Lambda, ParenExpression, Term}; +use super::{ + Alt, Call, Cat, Expression, Fix, GoalStatement, Ident, Labelled, Lambda, LetStatement, + ParenExpression, Statement, Term, +}; #[derive(Debug, Default)] pub struct Context { - bindings: Vec, + bindings: Vec, } impl Context { @@ -20,20 +20,24 @@ impl Context { Self::default() } + /// Get the De Bruijn index of `name`, if it is defined. pub fn lookup(&self, name: &Name) -> Option { self.bindings .iter() + .rev() .enumerate() - .rfind(|(_, n)| *n == name) + .find(|(_, n)| *n == &name.content) .map(|(idx, _)| idx) } + /// Permanently add the variable `name` to the top of the stack. pub fn push_variable(&mut self, name: Name) { - self.bindings.push(name); + self.bindings.push(name.content); } + /// Call `f` with the variable `name` pushed to the top of the stack. pub fn with_variable R, R>(&mut self, name: Name, f: F) -> R { - self.bindings.push(name); + self.bindings.push(name.content); let res = f(self); self.bindings.pop(); res @@ -45,7 +49,7 @@ impl Context { f: F, ) -> R { let len = self.bindings.len(); - self.bindings.extend(names); + self.bindings.extend(names.into_iter().map(|n| n.content)); let res = f(self); self.bindings.resize_with(len, || unreachable!()); res @@ -55,10 +59,9 @@ impl Context { #[derive(Clone, Debug)] pub enum ConvertError { UndeclaredName(Box), - EmptyCat(Option), - EmptyAlt(Option), - EmptyCall(Option), - MissingArgs(Option), + EmptyCat(Span), + EmptyAlt(Span), + EmptyCall(Span), } impl From for syn::Error { @@ -68,11 +71,10 @@ impl From for syn::Error { ConvertError::UndeclaredName(name) => name.span(), ConvertError::EmptyCat(span) | ConvertError::EmptyAlt(span) - | ConvertError::EmptyCall(span) - | ConvertError::MissingArgs(span) => span, + | ConvertError::EmptyCall(span) => span, }; - Self::new(span.unwrap_or_else(Span::call_site), msg) + Self::new(span, msg) } } @@ -91,9 +93,6 @@ impl fmt::Display for ConvertError { Self::EmptyCall(_) => { write!(f, "call has no function") } - Self::MissingArgs(_) => { - write!(f, "call has no arguments") - } } } } @@ -106,8 +105,8 @@ pub trait Convert { impl Convert for Ident { fn convert(self, context: &mut Context) -> Result { - let span = Some(self.span()); - let name = self.into(); + let span = self.span(); + let name = Name::new_variable(self); let index = context .lookup(&name) @@ -148,13 +147,13 @@ impl Convert for Term { Self::Epsilon(e) => Ok(NamedExpression { name: None, expr: ast::Epsilon.into(), - span: Some(e.span), + span: e.span, }), Self::Ident(i) => i.convert(context), Self::Literal(l) => Ok(NamedExpression { name: None, expr: l.value().into(), - span: Some(l.span()), + span: l.span(), }), Self::Fix(f) => f.convert(context), Self::Parens(p) => p.convert(context), @@ -168,13 +167,13 @@ impl Convert for Call { let mut iter = self.0.into_iter(); let on = iter .next() - .ok_or_else(|| ConvertError::EmptyCall(span))? + .ok_or(ConvertError::EmptyCall(span))? .convert(context)?; let args = iter .map(|arg| arg.convert(context)) .collect::, _>>()?; if args.is_empty() { - Err(ConvertError::MissingArgs(span)) + Ok(on) } else { Ok(NamedExpression { name: None, @@ -194,10 +193,10 @@ impl Convert for Cat { fn convert_pair( pair: Pair, context: &mut Context, - ) -> Result<(NamedExpression, Option), ConvertError> { + ) -> Result<(NamedExpression, 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)), + Pair::Punctuated(t, p) => t.convert(context).map(|expr| (expr, p.span)), + Pair::End(t) => t.convert(context).map(|expr| (expr, Span::call_site())), } } @@ -215,7 +214,7 @@ impl Convert for Cat { }) .peekable(); - if let Some(_) = rest.peek() { + if rest.peek().is_some() { Ok(NamedExpression { name: None, expr: ast::Cat { @@ -235,7 +234,8 @@ impl Convert for Labelled { fn convert(self, context: &mut Context) -> Result { let span = self.span(); let named = self.cat.convert(context)?; - let name = self.label.map(|l| l.label.into()).or(named.name); + let label = self.label.map(|l| Name::new_label(l.label)); + let name = Name::merge(label, named.name); Ok(NamedExpression { name, @@ -250,10 +250,10 @@ impl Convert for Alt { fn convert_pair( pair: Pair, context: &mut Context, - ) -> Result<(NamedExpression, Option), ConvertError> { + ) -> Result<(NamedExpression, 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)), + Pair::Punctuated(t, p) => t.convert(context).map(|expr| (expr, p.span)), + Pair::End(t) => t.convert(context).map(|expr| (expr, Span::call_site())), } } @@ -271,7 +271,7 @@ impl Convert for Alt { }) .peekable(); - if let Some(_) = rest.peek() { + if rest.peek().is_some() { Ok(NamedExpression { name: None, expr: ast::Alt { @@ -290,7 +290,7 @@ impl Convert for Alt { impl Convert for Lambda { fn convert(self, context: &mut Context) -> Result { let span = self.span(); - let mut args: Vec<_> = self.args.into_iter().map(Name::from).collect(); + let args: Vec<_> = self.args.into_iter().map(Name::new_variable).collect(); let expr = self.expr; let inner = context.with_variables(args.clone(), |ctx| expr.convert(ctx))?; Ok(NamedExpression { @@ -313,3 +313,62 @@ impl Convert for Expression { } } } + +impl Convert for GoalStatement { + fn convert(self, context: &mut Context) -> Result { + let span = self.span(); + let inner = self.expr.convert(context)?; + Ok(NamedExpression { + name: Name::merge(inner.name, Some(Name::new_variable("Ast".to_owned()))), + expr: inner.expr, + span, + }) + } +} + +impl Convert for LetStatement { + fn convert(self, context: &mut Context) -> Result { + let span = self.span(); + let bound = if self.args.is_empty() { + self.expr.convert(context)? + } else { + let args: Vec<_> = self.args.into_iter().map(Name::new_variable).collect(); + let expr = self.expr; + let inner = context.with_variables(args.clone(), |ctx| expr.convert(ctx))?; + NamedExpression { + name: None, + expr: ast::Lambda { + args, + inner: Box::new(inner), + } + .into(), + span, + } + }; + let name = Name::new_let(self.name); + context.push_variable(name.clone()); + let body = self.next.convert(context)?; + Ok(NamedExpression { + name: None, + expr: ast::Let { + name: name.clone(), + bound: Box::new(NamedExpression { + name: Some(name), + ..bound + }), + body: Box::new(body), + } + .into(), + span, + }) + } +} + +impl Convert for Statement { + fn convert(self, context: &mut Context) -> Result { + match self { + Self::Goal(g) => g.convert(context), + Self::Let(l) => l.convert(context), + } + } +} diff --git a/src/nibble/mod.rs b/src/nibble/mod.rs index dbb05b0..f5417db 100644 --- a/src/nibble/mod.rs +++ b/src/nibble/mod.rs @@ -2,82 +2,33 @@ pub mod convert; use std::fmt; -use proc_macro2::Span; +use proc_macro2::TokenStream; +use quote::{ToTokens, TokenStreamExt}; use syn::{ - bracketed, ext::IdentExt, parenthesized, parse::{Parse, ParseStream}, - punctuated::{Pair, Punctuated}, - token::{Bracket, Comma, Let, Match, Paren}, + punctuated::Punctuated, + token::{Let, Match, Paren}, LitStr, Token, }; -use crate::chomp::{Name, ast::{self, TopLevel}}; - -use convert::{Context, Convert, ConvertError}; - pub type Epsilon = Token![_]; pub type Ident = syn::Ident; pub type Literal = LitStr; -#[derive(Clone)] -pub struct ArgList { - paren_token: Paren, - args: Punctuated, -} - -impl ArgList { - pub fn span(&self) -> Span { - self.paren_token.span - } - - pub fn len(&self) -> usize { - self.args.len() - } - - pub fn is_empty(&self) -> bool { - self.args.is_empty() - } -} - -impl IntoIterator for ArgList { - type Item = T; - - type IntoIter = as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.args.into_iter() - } -} - -impl Parse for ArgList { - fn parse(input: ParseStream<'_>) -> syn::Result { - let args; - let paren_token = parenthesized!(args in input); - let args = args.call(Punctuated::parse_terminated)?; - Ok(Self { paren_token, args }) - } -} - -impl fmt::Debug for ArgList { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ArgList")?; - f.debug_list().entries(self.args.iter()).finish() - } -} - #[derive(Clone)] pub struct Fix { bang_token: Token![!], pub expr: Box, } -impl Fix { - pub fn span(&self) -> Option { - self.bang_token.span.join(self.expr.span()?) +impl ToTokens for Fix { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.bang_token.to_tokens(tokens); + self.expr.to_tokens(tokens); } } @@ -101,6 +52,12 @@ pub struct ParenExpression { pub expr: Expression, } +impl ToTokens for ParenExpression { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.paren_token.surround(tokens, |tokens| self.expr.to_tokens(tokens)) + } +} + impl Parse for ParenExpression { fn parse(input: ParseStream<'_>) -> syn::Result { let expr; @@ -127,14 +84,14 @@ pub enum Term { Parens(ParenExpression), } -impl Term { - pub fn span(&self) -> Option { +impl ToTokens for Term { + fn to_tokens(&self, tokens: &mut TokenStream) { match self { - Self::Epsilon(e) => Some(e.span), - Self::Ident(i) => Some(i.span()), - Self::Literal(l) => Some(l.span()), - Self::Fix(f) => f.span(), - Self::Parens(p) => Some(p.paren_token.span), + Self::Epsilon(e) => e.to_tokens(tokens), + Self::Ident(i) => i.to_tokens(tokens), + Self::Literal(l) => l.to_tokens(tokens), + Self::Fix(f) => f.to_tokens(tokens), + Self::Parens(p) => p.to_tokens(tokens), } } } @@ -174,18 +131,15 @@ impl fmt::Debug for Term { #[derive(Clone, Debug)] pub struct Call(pub Vec); -impl Call { - pub fn span(&self) -> Option { - let mut iter = self.0.iter(); - let first = iter.next()?.span()?; - iter.try_fold(first, |span, t| t.span().and_then(|s| span.join(s))) +impl ToTokens for Call { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.append_all(&self.0) } } impl Parse for Call { fn parse(input: ParseStream<'_>) -> syn::Result { - let mut out = Vec::new(); - out.push(input.parse()?); + let mut out = vec![input.parse()?]; loop { let lookahead = input.lookahead1(); if lookahead.peek(Token![_]) @@ -207,34 +161,22 @@ impl Parse for Call { #[derive(Clone)] pub struct Cat(pub Punctuated); -impl Parse for Cat { - fn parse(input: ParseStream<'_>) -> syn::Result { - input.call(Punctuated::parse_separated_nonempty).map(Self) +impl ToTokens for Cat { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.0.to_tokens(tokens) } } -impl Cat { - pub fn span(&self) -> Option { - 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 Cat { + fn parse(input: ParseStream<'_>) -> syn::Result { + input.call(Punctuated::parse_separated_nonempty).map(Self) } } 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() + f.debug_list().entries(&self.0).finish() } } @@ -244,9 +186,10 @@ pub struct Label { pub label: Ident, } -impl Label { - pub fn span(&self) -> Option { - self.colon_tok.span.join(self.label.span()) +impl ToTokens for Label { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.colon_tok.to_tokens(tokens); + self.label.to_tokens(tokens); } } @@ -270,13 +213,12 @@ pub struct Labelled { pub label: Option