summaryrefslogtreecommitdiff
path: root/src/nibble
diff options
context:
space:
mode:
Diffstat (limited to 'src/nibble')
-rw-r--r--src/nibble/convert.rs210
-rw-r--r--src/nibble/cst.rs322
2 files changed, 299 insertions, 233 deletions
diff --git a/src/nibble/convert.rs b/src/nibble/convert.rs
index cef3159..f79e1be 100644
--- a/src/nibble/convert.rs
+++ b/src/nibble/convert.rs
@@ -1,4 +1,4 @@
-use std::{collections::HashMap, fmt, mem};
+use std::{fmt, mem};
use proc_macro2::Span;
use syn::{punctuated::Pair, Token};
@@ -8,62 +8,42 @@ use crate::chomp::{
Name,
};
-use super::cst::{Alt, Call, Cat, Fix, Ident, Labelled, ParenExpression, Term};
-
-#[derive(Clone, Copy, Debug)]
-pub enum Binding {
- Variable(usize),
- Parameter(usize),
- Global,
-}
+use super::cst::{Alt, Call, Cat, Expression, Fix, Ident, Labelled, Lambda, ParenExpression, Term};
#[derive(Debug, Default)]
pub struct Context {
- names: HashMap<String, Binding>,
- vars: usize,
+ bindings: Vec<Name>,
}
impl Context {
- pub fn new<I: IntoIterator<Item = Name>>(globals: &[Name], params: I) -> Self {
- let mut names = HashMap::new();
- for global in globals {
- names.insert(global.to_string(), Binding::Global);
- }
-
- for (index, param) in params.into_iter().enumerate() {
- names.insert(param.to_string(), Binding::Parameter(index));
- }
-
- Self { names, vars: 0 }
+ pub fn new() -> Self {
+ Self::default()
}
- pub fn lookup(&self, name: &Name) -> Option<Binding> {
- // 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)),
- Some(Binding::Parameter(index)) => Some(Binding::Parameter(index)),
- Some(Binding::Global) => Some(Binding::Global),
- None => None,
- }
+ pub fn lookup(&self, name: &Name) -> Option<usize> {
+ self.bindings
+ .iter()
+ .enumerate()
+ .rfind(|(_, n)| *n == name)
+ .map(|(idx, _)| idx)
}
- pub fn with_variable<F: FnOnce(&mut Self) -> R, R>(&mut self, name: &Name, f: F) -> R {
- let old = self
- .names
- .insert(name.to_string(), Binding::Variable(self.vars));
+ pub fn push_variable(&mut self, name: Name) {
+ self.bindings.push(name);
+ }
- // we make variable binding cheaper by inserting wrong and pulling right.
- // we should increment all values in names instead, but that's slow
- self.vars += 1;
+ pub fn with_variable<F: FnOnce(&mut Self) -> R, R>(&mut self, name: Name, f: F) -> R {
+ self.bindings.push(name);
let res = f(self);
- self.vars -= 1;
-
- if let Some(val) = old {
- self.names.insert(name.to_string(), val);
- } else {
- self.names.remove(&name.to_string());
- }
+ self.bindings.pop();
+ res
+ }
+ pub fn with_variables<I: IntoIterator<Item = Name>, F: FnOnce(&mut Self) -> R, R>(&mut self, names: I, f: F) -> R {
+ let len = self.bindings.len();
+ self.bindings.extend(names);
+ let res = f(self);
+ self.bindings.resize_with(len, || unreachable!());
res
}
}
@@ -73,6 +53,8 @@ pub enum ConvertError {
UndeclaredName(Box<Name>),
EmptyCat(Option<Span>),
EmptyAlt(Option<Span>),
+ EmptyCall(Option<Span>),
+ MissingArgs(Option<Span>),
}
impl From<ConvertError> for syn::Error {
@@ -80,7 +62,10 @@ 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,
+ ConvertError::EmptyCat(span)
+ | ConvertError::EmptyAlt(span)
+ | ConvertError::EmptyCall(span)
+ | ConvertError::MissingArgs(span) => span,
};
Self::new(span.unwrap_or_else(Span::call_site), msg)
@@ -99,6 +84,12 @@ impl fmt::Display for ConvertError {
Self::EmptyAlt(_) => {
write!(f, "alternation has no elements")
}
+ Self::EmptyCall(_) => {
+ write!(f, "call has no function")
+ }
+ Self::MissingArgs(_) => {
+ write!(f, "call has no arguments")
+ }
}
}
}
@@ -114,49 +105,13 @@ impl Convert for Ident {
let span = Some(self.span());
let name = self.into();
- let binding = context
+ let index = context
.lookup(&name)
.ok_or_else(|| ConvertError::UndeclaredName(Box::new(name.clone())))?;
- Ok(match binding {
- Binding::Variable(index) => NamedExpression {
- name: Some(name),
- expr: ast::Variable { index }.into(),
- span,
- },
- Binding::Parameter(index) => NamedExpression {
- name: Some(name),
- expr: ast::Parameter { index }.into(),
- span,
- },
- Binding::Global => NamedExpression {
- name: None,
- expr: ast::Call {
- name,
- args: Vec::new(),
- }
- .into(),
- span,
- },
- })
- }
-}
-
-impl Convert for Call {
- fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
- let span = self.span();
- let args = self
- .args
- .into_iter()
- .map(|arg| arg.convert(context))
- .collect::<Result<_, _>>()?;
Ok(NamedExpression {
- name: None,
- expr: ast::Call {
- name: self.name.into(),
- args,
- }
- .into(),
+ name: Some(name),
+ expr: ast::Variable { index }.into(),
span,
})
}
@@ -165,13 +120,10 @@ impl Convert for Call {
impl Convert for Fix {
fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
let span = self.span();
- let expr = self.expr;
- let arg = self.arg.into();
- let inner = context.with_variable(&arg, |context| expr.convert(context))?;
+ let inner = self.expr.convert(context)?;
Ok(NamedExpression {
name: None,
expr: ast::Fix {
- arg: Some(arg),
inner: Box::new(inner),
}
.into(),
@@ -200,17 +152,43 @@ impl Convert for Term {
expr: l.value().into(),
span: Some(l.span()),
}),
- Self::Call(c) => c.convert(context),
Self::Fix(f) => f.convert(context),
Self::Parens(p) => p.convert(context),
}
}
}
+impl Convert for Call {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let span = self.span();
+ let mut iter = self.0.into_iter();
+ let on = iter
+ .next()
+ .ok_or_else(|| ConvertError::EmptyCall(span))?
+ .convert(context)?;
+ let args = iter
+ .map(|arg| arg.convert(context))
+ .collect::<Result<Vec<_>, _>>()?;
+ if args.is_empty() {
+ Err(ConvertError::MissingArgs(span))
+ } else {
+ Ok(NamedExpression {
+ name: None,
+ expr: ast::Call {
+ on: Box::new(on),
+ args,
+ }
+ .into(),
+ span,
+ })
+ }
+ }
+}
+
impl Convert for Cat {
fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
fn convert_pair(
- pair: Pair<Term, Token![.]>,
+ pair: Pair<Call, Token![.]>,
context: &mut Context,
) -> Result<(NamedExpression, Option<Span>), ConvertError> {
match pair {
@@ -227,18 +205,17 @@ impl Convert for Cat {
.ok_or(ConvertError::EmptyCat(span))
.and_then(|pair| convert_pair(pair, context))?;
- let mut rest = iter.map(|pair| {
- convert_pair(pair, context).map(|(snd, p)| (mem::replace(&mut punct, p), snd))
- });
+ let mut rest = iter
+ .map(|pair| {
+ convert_pair(pair, context).map(|(snd, p)| (mem::replace(&mut punct, p), snd))
+ })
+ .peekable();
- if let Some(res) = rest.next() {
- let (punct, second) = res?;
+ if let Some(_) = rest.peek() {
Ok(NamedExpression {
name: None,
expr: ast::Cat {
first: Box::new(first),
- punct,
- second: Box::new(second),
rest: rest.collect::<Result<_, _>>()?,
}
.into(),
@@ -284,18 +261,17 @@ impl Convert for Alt {
.ok_or(ConvertError::EmptyAlt(span))
.and_then(|pair| convert_pair(pair, context))?;
- let mut rest = iter.map(|pair| {
- convert_pair(pair, context).map(|(snd, p)| (mem::replace(&mut punct, p), snd))
- });
+ let mut rest = iter
+ .map(|pair| {
+ convert_pair(pair, context).map(|(snd, p)| (mem::replace(&mut punct, p), snd))
+ })
+ .peekable();
- if let Some(res) = rest.next() {
- let (punct, second) = res?;
+ if let Some(_) = rest.peek() {
Ok(NamedExpression {
name: None,
expr: ast::Alt {
first: Box::new(first),
- punct,
- second: Box::new(second),
rest: rest.collect::<Result<_, _>>()?,
}
.into(),
@@ -306,3 +282,29 @@ impl Convert for Alt {
}
}
}
+
+impl Convert for Lambda {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let span = self.span();
+ let mut names = self.args.into_iter().map(Name::from);
+ let expr = self.expr;
+ let inner = context.with_variables(names.clone(), |ctx| expr.convert(ctx))?;
+ let first = names.next().unwrap();
+ let rest = names.collect();
+ Ok(NamedExpression {
+ name: None,
+ expr: ast::Lambda { first, rest, inner: Box::new(inner)}.into(),
+ span,
+ })
+
+ }
+}
+
+impl Convert for Expression {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ match self {
+ Expression::Alt(a) => a.convert(context),
+ Expression::Lambda(l) => l.convert(context),
+ }
+ }
+}
diff --git a/src/nibble/cst.rs b/src/nibble/cst.rs
index d8b71b7..6137640 100644
--- a/src/nibble/cst.rs
+++ b/src/nibble/cst.rs
@@ -2,16 +2,18 @@ use std::fmt;
use proc_macro2::Span;
use syn::{
- bracketed,
ext::IdentExt,
parenthesized,
parse::{Parse, ParseStream},
punctuated::{Pair, Punctuated},
- token::{Bracket, Comma, Let, Match, Paren},
+ token::{Comma, Let, Match, Paren},
LitStr, Token,
};
-use crate::chomp::{ast, Name};
+use crate::chomp::{
+ ast::{self, TopLevel},
+ Name,
+};
use super::convert::{Context, Convert, ConvertError};
@@ -67,63 +69,29 @@ impl<T: fmt::Debug> fmt::Debug for ArgList<T> {
}
}
-#[derive(Clone, Debug)]
-pub struct Call {
- pub name: Ident,
- pub args: ArgList<Expression>,
-}
-
-impl Call {
- pub fn span(&self) -> Option<Span> {
- self.name.span().join(self.args.span())
- }
-}
-
-impl Parse for Call {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let name = input.call(Ident::parse_any)?;
- let args = input.parse()?;
- Ok(Self { name, args })
- }
-}
-
#[derive(Clone)]
pub struct Fix {
- bracket_token: Bracket,
- pub arg: Ident,
- paren_token: Paren,
- pub expr: Expression,
+ bang_token: Token![!],
+ pub expr: Box<Term>,
}
impl Fix {
pub fn span(&self) -> Option<Span> {
- self.bracket_token.span.join(self.paren_token.span)
+ self.bang_token.span.join(self.expr.span()?)
}
}
impl Parse for Fix {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let arg;
- let bracket_token = bracketed!(arg in input);
- let arg = arg.call(Ident::parse_any)?;
- let expr;
- let paren_token = parenthesized!(expr in input);
- let expr = expr.parse()?;
- Ok(Self {
- bracket_token,
- arg,
- paren_token,
- expr,
- })
+ let bang_token = input.parse()?;
+ let expr = input.parse()?;
+ Ok(Self { bang_token, expr })
}
}
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()
+ f.debug_struct("Fix").field("expr", &self.expr).finish()
}
}
@@ -155,7 +123,6 @@ pub enum Term {
Epsilon(Epsilon),
Ident(Ident),
Literal(Literal),
- Call(Call),
Fix(Fix),
Parens(ParenExpression),
}
@@ -166,7 +133,6 @@ impl Term {
Self::Epsilon(e) => Some(e.span),
Self::Ident(i) => Some(i.span()),
Self::Literal(l) => Some(l.span()),
- Self::Call(c) => c.span(),
Self::Fix(f) => f.span(),
Self::Parens(p) => Some(p.paren_token.span),
}
@@ -181,18 +147,12 @@ impl Parse for Term {
input.parse().map(Self::Epsilon)
} else if lookahead.peek(LitStr) {
input.parse().map(Self::Literal)
- } else if lookahead.peek(Bracket) {
+ } else if lookahead.peek(Token![!]) {
input.parse().map(Self::Fix)
} else if lookahead.peek(Paren) {
input.parse().map(Self::Parens)
} else if lookahead.peek(Ident::peek_any) {
- let name = input.call(Ident::parse_any)?;
-
- if input.peek(Paren) {
- input.parse().map(|args| Self::Call(Call { name, args }))
- } else {
- Ok(Self::Ident(name))
- }
+ input.call(Ident::parse_any).map(Self::Ident)
} else {
Err(lookahead.error())
}
@@ -205,15 +165,47 @@ impl fmt::Debug for Term {
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, Debug)]
+pub struct Call(pub Vec<Term>);
+
+impl Call {
+ pub fn span(&self) -> Option<Span> {
+ 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 Parse for Call {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let mut out = Vec::new();
+ out.push(input.parse()?);
+ loop {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(Token![_])
+ || lookahead.peek(LitStr)
+ || lookahead.peek(Token![!])
+ || lookahead.peek(Paren)
+ || lookahead.peek(Ident::peek_any)
+ {
+ out.push(input.parse()?);
+ } else {
+ break;
+ }
+ }
+
+ Ok(Self(out))
+ }
+}
+
#[derive(Clone)]
-pub struct Cat(pub Punctuated<Term, Token![.]>);
+pub struct Cat(pub Punctuated<Call, Token![.]>);
impl Parse for Cat {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
@@ -334,58 +326,60 @@ impl fmt::Debug for Alt {
}
}
-pub type Expression = Alt;
-
#[derive(Clone)]
-pub struct LetStatement {
- let_token: Token![let],
- name: Ident,
- args: Option<ArgList<Ident>>,
- eq_token: Token![=],
- expr: Expression,
- semi_token: Token![;],
+pub struct Lambda {
+ slash_tok_left: Token![/],
+ pub args: ArgList<Ident>,
+ slash_tok_right: Token![/],
+ pub expr: Alt,
}
-impl LetStatement {
+impl Lambda {
pub fn span(&self) -> Option<Span> {
- self.let_token.span.join(self.semi_token.span)
+ self.slash_tok_left.span.join(self.expr.span()?)
}
}
-impl Parse for LetStatement {
+impl Parse for Lambda {
fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let let_token = input.parse()?;
- let name = input.call(Ident::parse_any)?;
- let args = if input.peek(Paren) {
- Some(input.parse()?)
- } else {
- None
- };
- let eq_token = input.parse()?;
+ let slash_tok_left = input.parse()?;
+ let args = input.parse()?;
+ let slash_tok_right = input.parse()?;
let expr = input.parse()?;
- let semi_token = input.parse()?;
-
Ok(Self {
- let_token,
- name,
+ slash_tok_left,
args,
- eq_token,
+ slash_tok_right,
expr,
- semi_token,
})
}
}
-impl fmt::Debug for LetStatement {
+impl fmt::Debug for Lambda {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("LetStatement")
- .field("name", &self.name)
+ f.debug_struct("Lambda")
.field("args", &self.args)
.field("expr", &self.expr)
.finish()
}
}
+#[derive(Clone, Debug)]
+pub enum Expression {
+ Alt(Alt),
+ Lambda(Lambda),
+}
+
+impl Parse for Expression {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ if input.peek(Token![/]) {
+ input.parse().map(Self::Lambda)
+ } else {
+ input.parse().map(Self::Alt)
+ }
+ }
+}
+
#[derive(Clone)]
pub struct GoalStatement {
match_token: Token![match],
@@ -415,58 +409,128 @@ impl fmt::Debug for GoalStatement {
}
}
-#[derive(Clone, Debug)]
-pub struct File {
- lets: Vec<LetStatement>,
- goal: GoalStatement,
-}
-
-impl File {
- pub fn convert(self) -> Result<(Vec<ast::Function>, ast::NamedExpression), ConvertError> {
- let mut names = Vec::new();
- let mut map = Vec::new();
- for stmt in self.lets {
- let span = stmt.span();
- let name: Name = stmt.name.into();
- let params = stmt
- .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)?;
- names.push(name.clone());
- expr.name = Some(name.clone());
- map.push(ast::Function {
- name,
- params: params.map(Some).collect(),
- expr,
- span,
- });
- }
+#[derive(Clone)]
+pub struct LetStatement {
+ let_token: Token![let],
+ name: Ident,
+ args: Option<ArgList<Ident>>,
+ eq_token: Token![=],
+ expr: Expression,
+ semi_token: Token![;],
+ next: Box<Statement>,
+}
- let mut context = Context::new(&names, Vec::new());
- let goal = self.goal.expr.convert(&mut context)?;
- Ok((map, goal))
+impl Parse for LetStatement {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let let_token = input.parse()?;
+ let name = input.call(Ident::parse_any)?;
+ let args = if input.peek(Paren) {
+ Some(input.parse()?)
+ } else {
+ None
+ };
+ let eq_token = input.parse()?;
+ let expr = input.parse()?;
+ let semi_token = input.parse()?;
+ let next = Box::new(input.parse()?);
+
+ Ok(Self {
+ let_token,
+ name,
+ args,
+ eq_token,
+ expr,
+ semi_token,
+ next,
+ })
}
}
-impl Parse for File {
- fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
- let mut lets = Vec::new();
- let mut lookahead = input.lookahead1();
+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)
+ .field("next", &self.next)
+ .finish()
+ }
+}
- while lookahead.peek(Let) {
- lets.push(input.parse()?);
- lookahead = input.lookahead1();
+#[derive(Clone, Debug)]
+pub enum Statement {
+ Goal(GoalStatement),
+ Let(LetStatement),
+}
+
+impl Statement {
+ pub fn convert(self) -> Result<TopLevel, ConvertError> {
+ let mut stmt = self;
+ let mut context = Context::new();
+ let mut name_val = Vec::new();
+ while let Self::Let(let_stmt) = stmt {
+ let mut val = match let_stmt.args {
+ Some(args) => {
+ todo!()
+ }
+ None => let_stmt.expr.convert(&mut context),
+ }?;
+ let name: Name = let_stmt.name.into();
+ val.name = val.name.or_else(|| Some(name.clone()));
+ context.push_variable(name.clone());
+ name_val.push((name, val));
+ stmt = *let_stmt.next;
}
- let goal = if lookahead.peek(Match) {
- input.parse()?
- } else {
- return Err(lookahead.error());
+ let goal = match stmt {
+ Statement::Goal(goal) => TopLevel::Goal(goal.expr.convert(&mut context)?),
+ Statement::Let(_) => unreachable!(),
};
- Ok(Self { lets, goal })
+ Ok(name_val.into_iter().rfold(goal, |inner, (name, val)| {
+ TopLevel::Let(ast::Let {
+ name,
+ val,
+ inner: Box::new(inner),
+ })
+ }))
+ // let mut map = Vec::new();
+ // for stmt in self.lets {
+ // let span = stmt.span();
+ // let name: Name = stmt.name.into();
+ // let params = stmt
+ // .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)?;
+ // names.push(name.clone());
+ // expr.name = Some(name.clone());
+ // map.push(ast::Function {
+ // name,
+ // params: params.map(Some).collect(),
+ // expr,
+ // span,
+ // });
+ // }
+
+ // let mut context = Context::new(&names, Vec::new());
+ // let goal = self.goal.expr.convert(&mut context)?;
+ // Ok((map, goal))
+ }
+}
+
+impl Parse for Statement {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let mut lookahead = input.lookahead1();
+
+ if lookahead.peek(Let) {
+ input.parse().map(Self::Let)
+ } else if lookahead.peek(Match) {
+ input.parse().map(Self::Goal)
+ } else {
+ Err(lookahead.error())
+ }
}
}