diff options
Diffstat (limited to 'src/nibble')
-rw-r--r-- | src/nibble/convert.rs | 165 | ||||
-rw-r--r-- | src/nibble/cst.rs | 294 | ||||
-rw-r--r-- | src/nibble/mod.rs | 539 |
3 files changed, 509 insertions, 489 deletions
diff --git a/src/nibble/convert.rs b/src/nibble/convert.rs new file mode 100644 index 0000000..3e47208 --- /dev/null +++ b/src/nibble/convert.rs @@ -0,0 +1,165 @@ +use std::collections::HashMap; + +use syn::punctuated::Pair; + +use crate::chomp::ast; + +use super::cst::{Alt, Call, Cat, Fix, Ident, ParenExpression, Term}; + +#[derive(Clone, Copy, Debug)] +pub enum Binding { + Variable(usize), + Parameter(usize), + Global, +} + +#[derive(Debug)] +pub struct Context { + names: HashMap<String, Binding>, + vars: usize, +} + +impl Context { + pub fn new<I: IntoIterator<Item = Ident>>(globals: &[Ident], 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 lookup(&self, name: &Ident) -> 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)), + x => x, + } + } + + pub fn with_variable<F: FnOnce(&mut Self) -> R, R>(&mut self, name: &Ident, f: F) -> R { + let old = self + .names + .insert(name.to_string(), Binding::Variable(self.vars)); + + // 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; + 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()); + } + + res + } +} + +pub trait Convert { + fn convert(self, context: &mut Context) -> Option<ast::Expression>; +} + +impl Convert for Ident { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + let span = self.span(); + + match context.lookup(&self)? { + Binding::Variable(index) => Some(ast::Variable::new(self, index).into()), + Binding::Parameter(index) => Some(ast::Parameter::new(self, index).into()), + Binding::Global => Some(ast::Call::new(self, Vec::new(), Some(span)).into()), + } + } +} + +impl Convert for Call { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + let span = self.span(); + let args = self + .args + .into_iter() + .map(|arg| arg.convert(context)) + .collect::<Option<_>>()?; + Some(ast::Call::new(self.name, args, span).into()) + } +} + +impl Convert for Fix { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + let span = self.span(); + let expr = self.expr; + let inner = context.with_variable(&self.arg, |context| expr.convert(context))?; + Some(ast::Fix::new(self.arg, inner, span).into()) + } +} + +impl Convert for ParenExpression { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + self.expr.convert(context) + } +} + +impl Convert for Term { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + match self { + Self::Epsilon(e) => Some(e.into()), + Self::Ident(i) => i.convert(context), + Self::Literal(l) => Some(l.into()), + Self::Call(c) => c.convert(context), + Self::Fix(f) => f.convert(context), + Self::Parens(p) => p.convert(context), + } + } +} + +impl Convert for Cat { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + let mut iter = self.0.into_pairs(); + let mut out = match iter.next().unwrap() { + Pair::Punctuated(t, p) => (t.convert(context)?, Some(p)), + Pair::End(t) => (t.convert(context)?, None), + }; + + for pair in iter { + let (fst, punct) = out; + out = match pair { + Pair::Punctuated(t, p) => ( + ast::Cat::new(fst, punct, t.convert(context)?).into(), + Some(p), + ), + Pair::End(t) => (ast::Cat::new(fst, punct, t.convert(context)?).into(), None), + }; + } + + Some(out.0) + } +} + +impl Convert for Alt { + fn convert(self, context: &mut Context) -> Option<ast::Expression> { + let mut iter = self.0.into_pairs(); + let mut out = match iter.next().unwrap() { + Pair::Punctuated(t, p) => (t.convert(context)?, Some(p)), + Pair::End(t) => (t.convert(context)?, None), + }; + + for pair in iter { + let (fst, punct) = out; + out = match pair { + Pair::Punctuated(t, p) => ( + ast::Alt::new(fst, punct, t.convert(context)?).into(), + Some(p), + ), + Pair::End(t) => (ast::Alt::new(fst, punct, t.convert(context)?).into(), None), + }; + } + + Some(out.0) + } +} diff --git a/src/nibble/cst.rs b/src/nibble/cst.rs new file mode 100644 index 0000000..383eae9 --- /dev/null +++ b/src/nibble/cst.rs @@ -0,0 +1,294 @@ +use proc_macro2::Span; +use syn::{ + bracketed, + ext::IdentExt, + parenthesized, + parse::{Parse, ParseStream}, + punctuated::Punctuated, + token::{Bracket, Comma, Let, Match, Paren}, + LitStr, Token, +}; + +use crate::chomp::ast; + +use super::convert::{Context, Convert}; + +pub type Epsilon = Token![_]; + +pub type Ident = syn::Ident; + +pub type Literal = LitStr; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ArgList<T> { + paren_token: Paren, + args: Punctuated<T, Comma>, +} + +impl<T> ArgList<T> { + 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<T> IntoIterator for ArgList<T> { + type Item = T; + + type IntoIter = <Punctuated<T, Comma> as IntoIterator>::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.args.into_iter() + } +} + +impl<T: Parse> Parse for ArgList<T> { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let args; + let paren_token = parenthesized!(args in input); + let args = args.call(Punctuated::parse_terminated)?; + Ok(Self { paren_token, args }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +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, Debug, Eq, PartialEq)] +pub struct Fix { + bracket_token: Bracket, + pub arg: Ident, + paren_token: Paren, + pub expr: Expression, +} + +impl Fix { + pub fn span(&self) -> Option<Span> { + self.bracket_token.span.join(self.paren_token.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, + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ParenExpression { + paren_token: Paren, + pub expr: Expression, +} + +impl Parse for ParenExpression { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let expr; + let paren_token = parenthesized!(expr in input); + let expr = expr.parse()?; + Ok(Self { paren_token, expr }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum Term { + Epsilon(Epsilon), + Ident(Ident), + Literal(Literal), + Call(Call), + Fix(Fix), + Parens(ParenExpression), +} + +impl Parse for Term { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let lookahead = input.lookahead1(); + + if lookahead.peek(Token![_]) { + input.parse().map(Self::Epsilon) + } else if lookahead.peek(LitStr) { + input.parse().map(Self::Literal) + } else if lookahead.peek(Bracket) { + 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)) + } + } else { + Err(lookahead.error()) + } + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Cat(pub Punctuated<Term, Token![.]>); + +impl Parse for Cat { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + input.call(Punctuated::parse_separated_nonempty).map(Self) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Alt(pub Punctuated<Cat, Token![|]>); + +impl Parse for Alt { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + input.call(Punctuated::parse_separated_nonempty).map(Self) + } +} + +pub type Expression = Alt; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct LetStatement { + let_token: Token![let], + name: Ident, + args: Option<ArgList<Ident>>, + eq_token: Token![=], + expr: Expression, + semi_token: Token![;], +} + +impl LetStatement { + pub fn span(&self) -> Option<Span> { + self.let_token.span.join(self.semi_token.span) + } +} + +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()?; + + Ok(Self { + let_token, + name, + args, + eq_token, + expr, + semi_token, + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct GoalStatement { + match_token: Token![match], + expr: Expression, + semi_token: Token![;], +} + +impl Parse for GoalStatement { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let match_token = input.parse()?; + let expr = input.parse()?; + let semi_token = input.parse()?; + + Ok(Self { + match_token, + expr, + semi_token, + }) + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct File { + lets: Vec<LetStatement>, + goal: GoalStatement, +} + +impl File { + pub fn convert(self) -> Option<(Vec<ast::Function>, ast::Expression)> { + let mut names = Vec::new(); + let mut map = Vec::new(); + for stmt in self.lets { + let count = stmt.args.as_ref().map(ArgList::len).unwrap_or_default(); + let span = stmt.span(); + let mut context = Context::new( + &names, + stmt.args.into_iter().flat_map(|args| args.into_iter()), + ); + names.push(stmt.name.clone()); + map.push(ast::Function::new( + stmt.name.clone(), + count, + stmt.expr.convert(&mut context)?, + span, + )); + } + + let mut context = Context::new(&names, Vec::new()); + let goal = self.goal.expr.convert(&mut context)?; + Some((map, goal)) + } +} + +impl Parse for File { + fn parse(input: ParseStream<'_>) -> syn::Result<Self> { + let mut lets = Vec::new(); + let mut lookahead = input.lookahead1(); + + while lookahead.peek(Let) { + lets.push(input.parse()?); + lookahead = input.lookahead1(); + } + + let goal = if lookahead.peek(Match) { + input.parse()? + } else { + return Err(lookahead.error()); + }; + + Ok(Self { lets, goal }) + } +} diff --git a/src/nibble/mod.rs b/src/nibble/mod.rs index 071b41a..14791fd 100644 --- a/src/nibble/mod.rs +++ b/src/nibble/mod.rs @@ -1,489 +1,50 @@ -use std::collections::HashMap; -use std::rc::Rc; - -use crate::ast::{ - self, - convert::{Context, Convert}, -}; -use proc_macro2::Span; -use syn::{ - ext::IdentExt, - parse::{Parse, ParseStream}, - punctuated::{Pair, Punctuated}, - token, Result, Token, -}; - -pub type Epsilon = Token![_]; - -impl Convert for Epsilon { - fn convert(&self, _: &mut Context) -> ast::Term { - ast::Term::Epsilon(*self) - } -} - -type Ident = syn::Ident; - -impl Convert for Ident { - fn convert(&self, context: &mut Context) -> ast::Term { - use ast::Term; - let name = self.to_string(); - - if let Some(binding) = context.get_binding(&name) { - Term::Binding(ast::Variable::new(self.clone(), binding)) - } else if let Some(variable) = context.get_variable(&name) { - Term::Variable(ast::Variable::new(self.clone(), variable)) - } else { - let span = self.span(); - Term::Call(ast::Call::new(self.clone(), Vec::new(), span)) - } - } -} - -type Literal = syn::LitStr; - -impl Convert for Literal { - fn convert(&self, _: &mut Context) -> ast::Term { - ast::Term::Literal(self.clone()) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ArgList<T> { - paren_token: token::Paren, - args: Punctuated<T, token::Comma>, -} - -impl<T> ArgList<T> { - fn span(&self) -> Span { - self.paren_token.span - } - - fn len(&self) -> usize { - self.args.len() - } -} - -impl<T> IntoIterator for ArgList<T> { - type Item = T; - type IntoIter = <Punctuated<T, Token![,]> as IntoIterator>::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.args.into_iter() - } -} - -impl<T: Parse> Parse for ArgList<T> { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let args; - let paren_token = syn::parenthesized!(args in input); - let args = args.call(Punctuated::parse_terminated)?; - Ok(Self { paren_token, args }) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Call { - name: Ident, - args: ArgList<Expression>, -} - -impl Call { - fn span(&self) -> Span { - self.name - .span() - .join(self.args.span()) - .unwrap_or_else(Span::call_site) - } -} - -impl Parse for Call { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let name = input.call(Ident::parse_any)?; - let args = input.parse()?; - Ok(Self { name, args }) - } -} - -impl Convert for Call { - fn convert(&self, context: &mut Context) -> ast::Term { - use ast::Term; - let args = self - .args - .clone() - .into_iter() - .map(|arg| arg.convert(context)) - .collect::<Vec<_>>(); - Term::Call(ast::Call::new(self.name.clone(), args, self.span())) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Fix { - bracket_token: token::Bracket, - arg: Ident, - paren_token: token::Paren, - expr: Expression, -} - -impl Fix { - fn span(&self) -> Span { - self.bracket_token - .span - .join(self.paren_token.span) - .unwrap_or_else(Span::call_site) - } -} - -impl Parse for Fix { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let arg; - let bracket_token = syn::bracketed!(arg in input); - let arg = arg.call(Ident::parse_any)?; - let expr; - let paren_token = syn::parenthesized!(expr in input); - let expr = expr.parse()?; - Ok(Self { - bracket_token, - arg, - paren_token, - expr, - }) - } -} - -impl Convert for Fix { - fn convert(&self, context: &mut Context) -> ast::Term { - use ast::Term; - let span = self.span(); - let expr = &self.expr; - let arg_name = self.arg.to_string(); - Term::Fix(ast::Fix::new( - self.arg.clone(), - context.with_binding(arg_name, |ctx| expr.convert(ctx)), - span, - )) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct ParenExpression { - paren_tok: token::Paren, - expr: Expression, -} - -impl ParenExpression { - pub fn span(&self) -> Span { - self.paren_tok.span - } -} - -impl Parse for ParenExpression { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let expr; - let paren_tok = syn::parenthesized!(expr in input); - let expr = expr.parse()?; - Ok(Self { paren_tok, expr }) - } -} - -impl Convert for ParenExpression { - fn convert(&self, context: &mut Context) -> ast::Term { - self.expr.convert(context) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub enum Term { - Epsilon(Epsilon), - Ident(Ident), - Literal(Literal), - Call(Call), - Fix(Fix), - Parens(ParenExpression), -} - -impl Term { - pub fn span(&self) -> Span { - match self { - Self::Epsilon(eps) => eps.span, - Self::Ident(ident) => ident.span(), - Self::Literal(lit) => lit.span(), - Self::Call(call) => call.span(), - Self::Fix(fix) => fix.span(), - Self::Parens(paren) => paren.span(), - } - } -} - -impl Parse for Term { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let lookahead = input.lookahead1(); - if lookahead.peek(Token![_]) { - input.parse().map(Self::Epsilon) - } else if lookahead.peek(syn::LitStr) { - input.parse().map(Self::Literal) - } else if lookahead.peek(token::Bracket) { - input.parse().map(Self::Fix) - } else if lookahead.peek(token::Paren) { - let content; - let paren_tok = syn::parenthesized!(content in input); - content - .parse() - .map(|expr| Self::Parens(ParenExpression { paren_tok, expr })) - } else if lookahead.peek(Ident::peek_any) { - let name = input.call(Ident::parse_any)?; - if input.peek(token::Paren) { - input.parse().map(|args| Self::Call(Call { name, args })) - } else { - Ok(Self::Ident(name)) - } - } else { - Err(lookahead.error()) - } - } -} - -impl Convert for Term { - fn convert(&self, context: &mut Context) -> ast::Term { - match self { - Self::Epsilon(e) => e.convert(context), - Self::Ident(i) => i.convert(context), - Self::Literal(l) => l.convert(context), - Self::Call(c) => c.convert(context), - Self::Fix(f) => f.convert(context), - Self::Parens(e) => e.convert(context), - } - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Cat { - terms: Punctuated<Term, Token![.]>, -} - -impl Cat { - pub fn span(&self) -> Span { - let mut pairs = self.terms.pairs(); - let mut span = pairs.next().and_then(|pair| match pair { - Pair::Punctuated(term, punct) => term.span().join(punct.span), - Pair::End(term) => Some(term.span()), - }); - - for pair in pairs { - span = span.and_then(|span| match pair { - Pair::Punctuated(term, punct) => { - span.join(term.span()).and_then(|s| s.join(punct.span)) - } - Pair::End(term) => span.join(term.span()), - }) - } - - span.unwrap_or_else(Span::call_site) - } -} - -impl Parse for Cat { - fn parse(input: ParseStream<'_>) -> Result<Self> { - Ok(Self { - terms: input.call(Punctuated::parse_separated_nonempty)?, - }) - } -} - -impl Convert for Cat { - fn convert(&self, context: &mut Context) -> ast::Term { - use ast::Term; - let mut iter = self.terms.pairs(); - let init = match iter.next().unwrap() { - Pair::Punctuated(t, p) => Ok((t.convert(context), p)), - Pair::End(t) => Err(t.convert(context)), - }; - iter.fold(init, |term, pair| { - let (fst, punct) = term.unwrap(); - match pair { - Pair::Punctuated(t, p) => { - Ok((Term::Cat(ast::Cat::new(fst, *punct, t.convert(context))), p)) - } - Pair::End(t) => Err(Term::Cat(ast::Cat::new(fst, *punct, t.convert(context)))), - } - }) - .unwrap_err() - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Alt { - cats: Punctuated<Cat, Token![|]>, -} - -impl Alt { - pub fn span(&self) -> Span { - let mut pairs = self.cats.pairs(); - let mut span = pairs.next().and_then(|pair| match pair { - Pair::Punctuated(cat, punct) => cat.span().join(punct.span), - Pair::End(cat) => Some(cat.span()), - }); - - for pair in pairs { - span = span.and_then(|span| match pair { - Pair::Punctuated(cat, punct) => { - span.join(cat.span()).and_then(|s| s.join(punct.span)) - } - Pair::End(cat) => span.join(cat.span()), - }) - } - - span.unwrap_or_else(Span::call_site) - } -} - -impl Parse for Alt { - fn parse(input: ParseStream<'_>) -> Result<Self> { - Ok(Self { - cats: input.call(Punctuated::parse_separated_nonempty)?, - }) - } -} - -impl Convert for Alt { - fn convert(&self, context: &mut Context) -> ast::Term { - use ast::Term; - let mut iter = self.cats.pairs(); - let init = match iter.next().unwrap() { - Pair::Punctuated(t, p) => Ok((t.convert(context), p)), - Pair::End(t) => Err(t.convert(context)), - }; - iter.fold(init, |cat, pair| { - let (left, punct) = cat.unwrap(); - match pair { - Pair::Punctuated(t, p) => Ok(( - Term::Alt(ast::Alt::new(left, *punct, t.convert(context))), - p, - )), - Pair::End(t) => Err(Term::Alt(ast::Alt::new(left, *punct, t.convert(context)))), - } - }) - .unwrap_err() - } -} - -pub type Expression = Alt; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct LetStatement { - let_token: Token![let], - name: Ident, - args: Option<ArgList<Ident>>, - eq_token: Token![=], - expr: Expression, - semi_token: Token![;], -} - -impl Parse for LetStatement { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let let_token = input.parse()?; - let name = input.call(Ident::parse_any)?; - let args = if input.peek(token::Paren) { - Some(input.parse()?) - } else { - None - }; - let eq_token = input.parse()?; - let expr = input.parse()?; - let semi_token = input.parse()?; - - Ok(Self { - let_token, - name, - args, - eq_token, - expr, - semi_token, - }) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Goal { - match_token: Token![match], - expr: Expression, - semi_token: Token![;], -} - -impl Parse for Goal { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let match_token = input.parse()?; - let expr = input.parse()?; - let semi_token = input.parse()?; - - Ok(Self { match_token, expr, semi_token }) - } -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct File { - lets: Vec<LetStatement>, - goal: Goal, -} - -impl File { - /// Returns function list and the goal. The function list consists of an - /// [`Ident`], the converted [`ast::Term`] and the number of arguments. - pub fn convert(self) -> (Vec<(Ident, ast::Term, usize)>, ast::Term) { - let mut context = Context::new(); - let map = self - .lets - .into_iter() - .map(|stmt| { - let count = stmt.args.as_ref().map(ArgList::len).unwrap_or_default(); - context.set_variables( - stmt.args - .into_iter() - .flat_map(|args| args.into_iter().map(|arg| arg.to_string())), - ); - (stmt.name, stmt.expr.convert(&mut context), count) - }) - .collect(); - let goal = self.goal.expr.convert(&mut context); - (map, goal) - } -} - -impl Parse for File { - fn parse(input: ParseStream<'_>) -> Result<Self> { - let mut lets = Vec::new(); - while input.peek(Token![let]) { - lets.push(input.parse()?); - } - - let goal = input.parse()?; - - Ok(Self { lets, goal }) - } -} - -#[cfg(test)] -mod tests { - use super::{Epsilon, Ident, Literal}; - use syn::parse_str; - - #[test] - fn parse_epsilon() { - assert!(parse_str::<Epsilon>("_").is_ok()); - } - - #[test] - fn parse_ident() { - assert_eq!(parse_str::<Ident>("x").unwrap().to_string(), "x"); - assert_eq!(parse_str::<Ident>("x_yz").unwrap().to_string(), "x_yz"); - assert_eq!(parse_str::<Ident>("a123").unwrap().to_string(), "a123"); - assert_eq!(parse_str::<Ident>("𝒢𝒢").unwrap().to_string(), "𝒢𝒢"); - assert!(parse_str::<Ident>("1").is_err()); - assert!(parse_str::<Ident>("_").is_err()); - } - - #[test] - fn parse_literal() { - assert_eq!(parse_str::<Literal>(r#""hello""#).unwrap().value(), "hello") - } -} +pub mod convert; +pub mod cst; +// impl File { +// /// Returns function list and the goal. The function list consists of an +// /// [`Ident`], the converted [`ast::Expression`] and the number of arguments. +// pub fn convert(self) -> (Vec<(Ident, ast::Expression, usize)>, ast::Expression) { +// let mut context = Context::new(); +// let map = self +// .lets +// .into_iter() +// .map(|stmt| { +// let count = stmt.args.as_ref().map(ArgList::len).unwrap_or_default(); +// context.set_variables( +// stmt.args +// .into_iter() +// .flat_map(|args| args.into_iter().map(|arg| arg.to_string())), +// ); +// (stmt.name, stmt.expr.convert(&mut context), count) +// }) +// .collect(); +// let goal = self.goal.expr.convert(&mut context); +// (map, goal) +// } +// } + +// #[cfg(test)] +// mod tests { +// use super::{Epsilon, Ident, Literal}; +// use syn::parse_str; + +// #[test] +// fn parse_epsilon() { +// assert!(parse_str::<Epsilon>("_").is_ok()); +// } + +// #[test] +// fn parse_ident() { +// assert_eq!(parse_str::<Ident>("x").unwrap().to_string(), "x"); +// assert_eq!(parse_str::<Ident>("x_yz").unwrap().to_string(), "x_yz"); +// assert_eq!(parse_str::<Ident>("a123").unwrap().to_string(), "a123"); +// assert_eq!(parse_str::<Ident>("𝒢𝒢").unwrap().to_string(), "𝒢𝒢"); +// assert!(parse_str::<Ident>("1").is_err()); +// assert!(parse_str::<Ident>("_").is_err()); +// } + +// #[test] +// fn parse_literal() { +// assert_eq!(parse_str::<Literal>(r#""hello""#).unwrap().value(), "hello") +// } +// } |