summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2021-01-14 14:37:27 +0000
committerGreg Brown <gmb60@cam.ac.uk>2021-01-14 14:37:27 +0000
commit24ff5f311f6c797681be1cff0fb2d0b75c0f848f (patch)
treee4cc216813f2a9c40dc496148dbd4eeed83fb87c
parent3d13ff5a0f40b750f754898ab4568d4afc0f1a9e (diff)
Finish AutoChomp
-rw-r--r--autochomp/Cargo.toml1
-rw-r--r--autochomp/src/main.rs36
-rw-r--r--autochomp/src/nibble.rs531
-rw-r--r--src/main.rs25
-rw-r--r--src/nibble/convert.rs36
-rw-r--r--src/nibble/cst.rs14
-rw-r--r--src/nibble/mod.rs48
7 files changed, 609 insertions, 82 deletions
diff --git a/autochomp/Cargo.toml b/autochomp/Cargo.toml
index 6dfd491..4d5aaef 100644
--- a/autochomp/Cargo.toml
+++ b/autochomp/Cargo.toml
@@ -10,4 +10,5 @@ features = ["extra-traits"]
[dependencies]
chewed = {path = "../chewed"}
+chomp = {path = "../"}
chomp-macro = {path = "../chomp-macro"}
diff --git a/autochomp/src/main.rs b/autochomp/src/main.rs
index 493204d..ec50a92 100644
--- a/autochomp/src/main.rs
+++ b/autochomp/src/main.rs
@@ -5,6 +5,18 @@ use std::{
};
use chewed::{IterWrapper, Parser};
+use chomp::{
+ chomp::{
+ ast::substitute::InlineCalls,
+ typed::{
+ context::Context,
+ lower::{Backend, GenerateCode},
+ TypeInfer,
+ },
+ visit::Visitable,
+ },
+ lower::RustBackend,
+};
mod nibble;
@@ -18,8 +30,28 @@ fn main() {
.parse::<nibble::Ast>()
.map_err(|e| Box::new(e) as Box<dyn Error>)
})
- .and_then(|ast| {
- write!(io::stdout(), "{:?}", ast).map_err(|e| Box::new(e) as Box<dyn Error>)
+ .and_then(|ast| ast.convert().map_err(|e| Box::new(e) as Box<dyn Error>))
+ .and_then(|(funs, goal)| {
+ funs.into_iter()
+ .try_rfold(goal, |goal, function| {
+ goal.fold(&mut InlineCalls { function })
+ })
+ .map_err(|e| Box::new(e) as Box<dyn Error>)
+ })
+ .and_then(|term| {
+ let mut context = Context::default();
+ term.fold(&mut TypeInfer {
+ context: &mut context,
+ })
+ .map_err(|e| Box::new(e) as Box<dyn Error>)
+ })
+ .map(|typed| {
+ let mut backend = RustBackend::default();
+ let id = typed.gen(&mut backend);
+ backend.emit_code(None, None, id)
+ })
+ .and_then(|code| {
+ write!(io::stdout(), "{:#}", code).map_err(|e| Box::new(e) as Box<dyn Error>)
});
if let Err(e) = res {
diff --git a/autochomp/src/nibble.rs b/autochomp/src/nibble.rs
index 657a20f..ebe18a6 100644
--- a/autochomp/src/nibble.rs
+++ b/autochomp/src/nibble.rs
@@ -1,3 +1,13 @@
+use std::convert::TryInto;
+
+use chomp::{
+ chomp::{
+ ast::{self, Alt, Call, Cat, Fix, Function, NamedExpression, Parameter, Variable},
+ Name,
+ },
+ nibble::convert::{Binding, Context, Convert, ConvertError},
+};
+
chomp_macro::nibble! {
let opt(x) = _ : None | x : Some;
let plus(x) = [plus]((x : First) . (opt(plus) : Next));
@@ -75,3 +85,524 @@ chomp_macro::nibble! {
match star_(star_(goal : Goal, let : Let), Pattern_Whitespace);
}
+
+impl Ast {
+ pub fn convert(self) -> Result<(Vec<Function>, NamedExpression), ConvertError> {
+ let content = Star2::from(self.0);
+ let mut names = Vec::new();
+ let mut map = Vec::new();
+
+ let mut iter = content.into_iter();
+
+ for stmt in &mut iter {
+ let name: Name = stmt.ident1.into();
+ let params = Option::from(stmt.opt2)
+ .into_iter()
+ .flat_map(List2::into_iter)
+ .map(Name::from);
+ let mut context = Context::new(&names, params.clone());
+ let mut expr = stmt.expr1.convert(&mut context)?;
+ names.push(name.clone());
+ expr.name = Some(name.clone());
+ map.push(Function {
+ name,
+ params: params.map(Some).collect(),
+ expr,
+ span: None,
+ });
+ }
+
+ let mut context = Context::new(&names, Vec::new());
+ let goal = iter.consume().expr1.convert(&mut context)?;
+
+ Ok((map, goal))
+ }
+}
+
+impl Convert for Expr1 {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let mut iter = self.0.into_iter();
+ let first = iter.next().unwrap().convert(context)?;
+ let rest = iter
+ .map(|term| Ok((None, term.convert(context)?)))
+ .collect::<Result<Vec<_>, _>>()?;
+
+ let mut iter = rest.into_iter();
+ if let Some((punct, second)) = iter.next() {
+ Ok(NamedExpression {
+ name: None,
+ expr: Alt {
+ first: Box::new(first),
+ punct,
+ second: Box::new(second),
+ rest: iter.collect(),
+ }
+ .into(),
+ span: None,
+ })
+ } else {
+ Ok(first)
+ }
+ }
+}
+
+impl Convert for First1 {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let named = self.punctuated1.convert(context)?;
+ let name = Option::from(self.opt1).or(named.name);
+
+ Ok(NamedExpression {
+ name,
+ expr: named.expr,
+ span: named.span,
+ })
+ }
+}
+
+impl Convert for Punctuated2 {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let mut iter = self.into_iter();
+ let first = iter.next().unwrap().convert(context)?;
+ let rest = iter
+ .map(|term| Ok((None, term.convert(context)?)))
+ .collect::<Result<Vec<_>, _>>()?;
+
+ let mut iter = rest.into_iter();
+ if let Some((punct, second)) = iter.next() {
+ Ok(NamedExpression {
+ name: None,
+ expr: Cat {
+ first: Box::new(first),
+ punct,
+ second: Box::new(second),
+ rest: iter.collect(),
+ }
+ .into(),
+ span: None,
+ })
+ } else {
+ Ok(first)
+ }
+ }
+}
+
+impl Convert for Term1 {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ match self {
+ Self::Epsilon1(_) => Ok(NamedExpression {
+ name: None,
+ expr: ast::Epsilon.into(),
+ span: None,
+ }),
+ Self::Literal1(l) => Ok(NamedExpression {
+ name: None,
+ expr: l.value().into(),
+ span: None,
+ }),
+ Self::Parens1(p) => p.parens1.expr1.convert(context),
+ Self::Fix1(f) => f.fix1.convert(context),
+ Self::CallOrVariable1(c) => c.convert(context),
+ }
+ }
+}
+
+impl Convert for Fix1 {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let arg = self.ident1.into();
+ let expr = *self.parens1.expr1;
+ let inner = context.with_variable(&arg, |context| expr.convert(context))?;
+
+ Ok(NamedExpression {
+ name: None,
+ expr: Fix {
+ arg: Some(arg),
+ inner: Box::new(inner),
+ }
+ .into(),
+ span: None,
+ })
+ }
+}
+
+impl Convert for CallOrVariable1 {
+ fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
+ let name = self.ident1.into();
+
+ match self.opt2 {
+ Opt26::None1(_) => {
+ let binding = context
+ .lookup(&name)
+ .ok_or_else(|| ConvertError::UndeclaredName(name.clone()))?;
+
+ Ok(match binding {
+ Binding::Variable(index) => NamedExpression {
+ name: Some(name),
+ expr: Variable { index }.into(),
+ span: None,
+ },
+ Binding::Parameter(index) => NamedExpression {
+ name: Some(name),
+ expr: Parameter { index }.into(),
+ span: None,
+ },
+ Binding::Global => NamedExpression {
+ name: None,
+ expr: Call {
+ name,
+ args: Vec::new(),
+ }
+ .into(),
+ span: None,
+ },
+ })
+ }
+ Opt26::Some1(s) => {
+ let args = s
+ .list1
+ .into_iter()
+ .map(|arg| arg.convert(context))
+ .collect::<Result<_, _>>()?;
+ Ok(NamedExpression {
+ name: None,
+ expr: Call { name, args }.into(),
+ span: None,
+ })
+ }
+ }
+ }
+}
+
+impl Literal3 {
+ pub fn value(self) -> String {
+ self.literal1
+ .plus1
+ .into_iter()
+ .map(LiteralChar1::value)
+ .collect()
+ }
+}
+
+impl LiteralChar1 {
+ pub fn value(self) -> char {
+ match self {
+ Self::Literal1(c) => c.into(),
+ Self::Escape1(e) => e.1.value(),
+ }
+ }
+}
+
+impl Alt143 {
+ pub fn value(self) -> char {
+ match self {
+ Self::Ascii1(a) => a.value(),
+ Self::Oct1(o) => o.value(),
+ Self::Unicode1(u) => u.value(),
+ }
+ }
+}
+
+impl Ascii1 {
+ pub fn value(self) -> char {
+ match self {
+ Self::Branch1(_) => '\"',
+ Self::Branch2(_) => '\'',
+ Self::Branch3(_) => '\n',
+ Self::Branch4(_) => '\r',
+ Self::Branch5(_) => '\t',
+ Self::Branch6(_) => '\\',
+ Self::Branch7(_) => '\0',
+ }
+ }
+}
+
+impl Oct1 {
+ pub fn value(self) -> char {
+ let s: String = [char::from(self.oct_digit1), char::from(self.hex_digit1)]
+ .iter()
+ .collect();
+ u32::from_str_radix(&s, 16).unwrap().try_into().unwrap()
+ }
+}
+
+impl Unicode1 {
+ pub fn value(self) -> char {
+ let s: String = [self.hex_digit1.to_string(), self.opt1.to_string()]
+ .iter()
+ .map::<&str, _>(|s| s)
+ .collect();
+ u32::from_str_radix(&s, 16).unwrap().try_into().unwrap()
+ }
+}
+
+impl IntoIterator for Punctuated1 {
+ type Item = First1;
+
+ type IntoIter = Punct1Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Punct1Iter(Some(self))
+ }
+}
+
+pub struct Punct1Iter(Option<Punctuated1>);
+
+impl Iterator for Punct1Iter {
+ type Item = First1;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let cat = self.0.take()?.0;
+ let first = cat.first1;
+ self.0 = cat.opt1.into();
+ Some(first)
+ }
+}
+
+impl IntoIterator for Punctuated2 {
+ type Item = Term1;
+
+ type IntoIter = Punct2Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Punct2Iter(Some(self))
+ }
+}
+
+pub struct Punct2Iter(Option<Punctuated2>);
+
+impl Iterator for Punct2Iter {
+ type Item = Term1;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let cat = self.0.take()?.0;
+ let term = cat.term1;
+ self.0 = cat.opt1.into();
+ Some(term)
+ }
+}
+
+impl IntoIterator for Plus2 {
+ type Item = LiteralChar1;
+
+ type IntoIter = Plus2Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Plus2Iter(Some(self))
+ }
+}
+
+pub struct Plus2Iter(Option<Plus2>);
+
+impl Iterator for Plus2Iter {
+ type Item = LiteralChar1;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let cat = self.0.take()?.0;
+ let lit = cat.literal_char1;
+ self.0 = cat.opt1.into();
+ Some(lit)
+ }
+}
+
+impl IntoIterator for List1 {
+ type Item = Expr1;
+
+ type IntoIter = Fix192Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Fix192Iter(Some(self.part3))
+ }
+}
+
+pub struct Fix192Iter(Option<Fix192>);
+
+impl Iterator for Fix192Iter {
+ type Item = Expr1;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let cat = self.0.take()?.0;
+ let expr = *cat.expr1;
+ self.0 = cat.opt1.into();
+ Some(expr)
+ }
+}
+
+impl IntoIterator for Star2 {
+ type Item = Let1;
+
+ type IntoIter = Star2Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Star2Iter(Some(self))
+ }
+}
+
+pub struct Star2Iter(Option<Star2>);
+
+impl Star2Iter {
+ pub fn consume(self) -> Goal1 {
+ let mut star = self.0.unwrap();
+
+ loop {
+ match star.0 {
+ Alt274::Step1(step) => star = *step.rec1,
+ Alt274::Goal1(goal) => return goal,
+ }
+ }
+ }
+}
+
+impl Iterator for Star2Iter {
+ type Item = Let1;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let star = self.0.take().unwrap();
+
+ // You can probably be safer about this and use `mem::swap` or similar.
+ // I cannot think of a way how, so this will do.
+ if let Alt274::Step1(step) = star.0 {
+ let stmt = step.let1;
+ self.0 = Some(*step.rec1);
+ Some(stmt)
+ } else {
+ self.0 = Some(star);
+ None
+ }
+ }
+}
+
+impl IntoIterator for List2 {
+ type Item = Ident5;
+
+ type IntoIter = Fix246Iter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ Fix246Iter(Some(self.part3))
+ }
+}
+
+#[derive(Clone)]
+pub struct Fix246Iter(Option<Fix246>);
+
+impl Iterator for Fix246Iter {
+ type Item = Ident5;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let cat = self.0.take()?.0;
+ let expr = cat.first1.ident1;
+ self.0 = cat.opt1.into();
+ Some(expr)
+ }
+}
+
+impl From<Opt34> for Option<Punctuated1> {
+ fn from(o: Opt34) -> Self {
+ match o {
+ Opt34::None1(_) => None,
+ Opt34::Some1(s) => Some(*s.rec1),
+ }
+ }
+}
+
+impl From<Opt32> for Option<Name> {
+ fn from(o: Opt32) -> Self {
+ match o {
+ Opt32::None1(_) => None,
+ Opt32::Label1(l) => Some(l.ident1.into()),
+ }
+ }
+}
+
+impl From<Opt28> for Option<Punctuated2> {
+ fn from(o: Opt28) -> Self {
+ match o {
+ Opt28::None1(_) => None,
+ Opt28::Some1(s) => Some(*s.rec1),
+ }
+ }
+}
+
+impl From<Opt8> for Option<Plus2> {
+ fn from(o: Opt8) -> Self {
+ match o {
+ Opt8::None1(_) => None,
+ Opt8::Plus1(s) => Some(*s),
+ }
+ }
+}
+
+impl From<Opt24> for Option<Fix192> {
+ fn from(o: Opt24) -> Self {
+ match o {
+ Opt24::None1(_) => None,
+ Opt24::Some1(s) => match s.opt2 {
+ Opt23::None1(_) => None,
+ Opt23::Rec1(e) => Some(*e),
+ },
+ }
+ }
+}
+
+impl From<Opt45> for Option<List2> {
+ fn from(o: Opt45) -> Self {
+ match o {
+ Opt45::None1(_) => None,
+ Opt45::Some1(s) => Some(s.list1),
+ }
+ }
+}
+
+impl From<Opt43> for Option<Fix246> {
+ fn from(o: Opt43) -> Self {
+ match o {
+ Opt43::None1(_) => None,
+ Opt43::Some1(s) => match s.opt2 {
+ Opt42::None1(_) => None,
+ Opt42::Rec1(e) => Some(*e),
+ },
+ }
+ }
+}
+
+impl From<Ident3> for Name {
+ fn from(i: Ident3) -> Self {
+ i.to_string().into()
+ }
+}
+
+impl From<Ident2> for Name {
+ fn from(i: Ident2) -> Self {
+ i.to_string().into()
+ }
+}
+
+impl From<Ident1> for Name {
+ fn from(i: Ident1) -> Self {
+ i.to_string().into()
+ }
+}
+
+impl From<Ident5> for Name {
+ fn from(i: Ident5) -> Self {
+ i.to_string().into()
+ }
+}
+
+impl From<Ident4> for Name {
+ fn from(i: Ident4) -> Self {
+ i.to_string().into()
+ }
+}
+
+impl From<Alt277> for Star2 {
+ fn from(mut a: Alt277) -> Self {
+ while let Alt277::Step1(step) = a {
+ a = (*step.rec1).0;
+ }
+
+ if let Alt277::Star1(s) = a {
+ s
+ } else {
+ unreachable!()
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 100bb68..10156e6 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,21 +1,22 @@
use std::{
error::Error,
- fmt::Display,
io::{self, Read, Write},
process::exit,
};
-use chomp::{chomp::{ast::substitute::InlineCalls, typed::{TypeInfer, context::Context, lower::{Backend, GenerateCode}}, visit::Visitable}, lower::RustBackend, nibble::cst::File};
-
-#[derive(Debug)]
-struct UndecVar;
-
-impl Display for UndecVar {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "Undeclared variable somewhere.")
- }
-}
-impl Error for UndecVar {}
+use chomp::{
+ chomp::{
+ ast::substitute::InlineCalls,
+ typed::{
+ context::Context,
+ lower::{Backend, GenerateCode},
+ TypeInfer,
+ },
+ visit::Visitable,
+ },
+ lower::RustBackend,
+ nibble::cst::File,
+};
fn main() {
let mut input = String::new();
diff --git a/src/nibble/convert.rs b/src/nibble/convert.rs
index 5cbf5e2..e3c8bfc 100644
--- a/src/nibble/convert.rs
+++ b/src/nibble/convert.rs
@@ -1,8 +1,12 @@
use std::{collections::HashMap, fmt};
+use proc_macro2::Span;
use syn::punctuated::Pair;
-use crate::chomp::ast::{self, NamedExpression};
+use crate::chomp::{
+ ast::{self, NamedExpression},
+ Name,
+};
use super::cst::{Alt, Call, Cat, Fix, Ident, Labelled, ParenExpression, Term};
@@ -20,7 +24,7 @@ pub struct Context {
}
impl Context {
- pub fn new<I: IntoIterator<Item = Ident>>(globals: &[Ident], params: I) -> Self {
+ 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);
@@ -33,7 +37,7 @@ impl Context {
Self { names, vars: 0 }
}
- pub fn lookup(&self, name: &Ident) -> Option<Binding> {
+ 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)),
@@ -41,7 +45,7 @@ impl Context {
}
}
- pub fn with_variable<F: FnOnce(&mut Self) -> R, R>(&mut self, name: &Ident, f: F) -> R {
+ 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));
@@ -64,13 +68,14 @@ impl Context {
#[derive(Clone, Debug)]
pub enum ConvertError {
- UndeclaredName(Ident),
+ UndeclaredName(Name),
}
impl From<ConvertError> for syn::Error {
fn from(e: ConvertError) -> Self {
match e {
- ConvertError::UndeclaredName(ident) => {
+ ConvertError::UndeclaredName(name) => {
+ let ident = name.into_ident(Span::call_site());
Self::new(ident.span(), "undeclared name")
}
}
@@ -80,12 +85,12 @@ impl From<ConvertError> for syn::Error {
impl fmt::Display for ConvertError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
- Self::UndeclaredName(i) => {
- let start = i.span().start();
+ Self::UndeclaredName(name) => {
+ let start = name.span().unwrap_or_else(Span::call_site).start();
write!(
f,
"{}:{}: undeclared name `{}'",
- start.line, start.column, i
+ start.line, start.column, name
)
}
}
@@ -101,12 +106,12 @@ pub trait Convert {
impl Convert for Ident {
fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
let span = Some(self.span());
- let binding = match context.lookup(&self) {
- Some(b) => b,
- None => return Err(ConvertError::UndeclaredName(self)),
- };
let name = self.into();
+ let binding = context
+ .lookup(&name)
+ .ok_or_else(|| ConvertError::UndeclaredName(name.clone()))?;
+
Ok(match binding {
Binding::Variable(index) => NamedExpression {
name: Some(name),
@@ -155,11 +160,12 @@ impl Convert for Fix {
fn convert(self, context: &mut Context) -> Result<NamedExpression, ConvertError> {
let span = self.span();
let expr = self.expr;
- let inner = context.with_variable(&self.arg, |context| expr.convert(context))?;
+ let arg = self.arg.into();
+ let inner = context.with_variable(&arg, |context| expr.convert(context))?;
Ok(NamedExpression {
name: None,
expr: ast::Fix {
- arg: Some(self.arg.into()),
+ arg: Some(arg),
inner: Box::new(inner),
}
.into(),
diff --git a/src/nibble/cst.rs b/src/nibble/cst.rs
index f6fa51b..2fcc99f 100644
--- a/src/nibble/cst.rs
+++ b/src/nibble/cst.rs
@@ -9,7 +9,7 @@ use syn::{
LitStr, Token,
};
-use crate::chomp::{Name, ast};
+use crate::chomp::{ast, Name};
use super::convert::{Context, Convert, ConvertError};
@@ -332,15 +332,19 @@ impl File {
let mut map = Vec::new();
for stmt in self.lets {
let span = stmt.span();
- let params = stmt.args.into_iter().flat_map(|args| args.into_iter());
+ let name: Name = stmt.name.into();
+ let params = stmt
+ .args
+ .into_iter()
+ .flat_map(|args| args.into_iter())
+ .map(Name::from);
let mut context = Context::new(&names, params.clone());
- names.push(stmt.name.clone());
let mut expr = stmt.expr.convert(&mut context)?;
- let name: Name = stmt.name.into();
+ names.push(name.clone());
expr.name = Some(name.clone());
map.push(ast::Function {
name,
- params: params.map(|name| Some(name.into())).collect(),
+ params: params.map(Some).collect(),
expr,
span,
});
diff --git a/src/nibble/mod.rs b/src/nibble/mod.rs
index 14791fd..41e895c 100644
--- a/src/nibble/mod.rs
+++ b/src/nibble/mod.rs
@@ -1,50 +1,2 @@
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")
-// }
-// }