summaryrefslogtreecommitdiff
path: root/src/chomp/ast/substitute.rs
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2021-05-06 19:40:59 +0100
committerGreg Brown <gmb60@cam.ac.uk>2021-05-06 19:40:59 +0100
commitdfc08ff2c6580bbeb3951b223e0332546ba3b0d9 (patch)
tree60597dd9492b9c2dfa10ea610289f143dd3e41b7 /src/chomp/ast/substitute.rs
parentef485d6f3e4df6e1a424ba3797388fa0bba6eb2e (diff)
Introduce lambda expressions.
Diffstat (limited to 'src/chomp/ast/substitute.rs')
-rw-r--r--src/chomp/ast/substitute.rs229
1 files changed, 149 insertions, 80 deletions
diff --git a/src/chomp/ast/substitute.rs b/src/chomp/ast/substitute.rs
index 80df588..c6d3ef6 100644
--- a/src/chomp/ast/substitute.rs
+++ b/src/chomp/ast/substitute.rs
@@ -1,24 +1,32 @@
+use std::array;
+
use super::{
- error::TranslateError, Alt, Call, Cat, Epsilon, Fix, Lambda, Literal, NamedExpression, Variable,
+ error::ReductionError, Alt, Call, Cat, Epsilon, Expression, Fix, Lambda, Let, Literal,
+ NamedExpression, Variable,
};
use crate::chomp::{
+ name::Name,
visit::{Folder, Mapper, Visitable},
- Name,
};
use proc_macro2::Span;
-struct Deepen {
- pub depth: usize,
- pub by: usize,
+enum Direction {
+ Deepen,
+ Shallow,
+}
+struct RenameVars {
+ depth: usize,
+ by: usize,
+ direction: Direction,
}
-impl Mapper for Deepen {
+impl Mapper for RenameVars {
type Out = ();
fn map_epsilon(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
_eps: &mut Epsilon,
) -> Self::Out {
}
@@ -26,7 +34,7 @@ impl Mapper for Deepen {
fn map_literal(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
_lit: &mut Literal,
) -> Self::Out {
}
@@ -34,7 +42,7 @@ impl Mapper for Deepen {
fn map_cat(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
cat: &mut Cat,
) -> Self::Out {
cat.first.map(self);
@@ -46,7 +54,7 @@ impl Mapper for Deepen {
fn map_alt(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
alt: &mut Alt,
) -> Self::Out {
alt.first.map(self);
@@ -58,7 +66,7 @@ impl Mapper for Deepen {
fn map_fix(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
fix: &mut Fix,
) -> Self::Out {
fix.inner.map(self);
@@ -67,18 +75,21 @@ impl Mapper for Deepen {
fn map_variable(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
var: &mut Variable,
) -> Self::Out {
if var.index >= self.depth {
- var.index += self.by;
+ match self.direction {
+ Direction::Deepen => var.index += self.by,
+ Direction::Shallow => var.index -= self.by,
+ }
}
}
fn map_call(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
call: &mut Call,
) -> Self::Out {
call.on.map(self);
@@ -90,24 +101,56 @@ impl Mapper for Deepen {
fn map_lambda(
&mut self,
_name: &mut Option<Name>,
- _span: Option<Span>,
+ _span: Span,
lambda: &mut Lambda,
) -> Self::Out {
self.depth += lambda.args.len();
lambda.inner.map(self);
self.depth -= lambda.args.len();
}
+
+ fn map_let(
+ &mut self,
+ _name: &mut Option<Name>,
+ _span: Span,
+ stmt: &mut Let,
+ ) -> Self::Out {
+ stmt.bound.map(self);
+ self.depth += 1;
+ stmt.body.map(self);
+ self.depth -= 1;
+ }
}
+#[derive(Debug)]
pub struct Substitute {
pub index: usize,
pub expr: NamedExpression,
}
+impl Substitute {
+ fn with_args<V: Visitable>(&mut self, args: usize, visitable: V) -> <Self as Folder>::Out {
+ self.index += args;
+ self.expr.map(&mut RenameVars {
+ depth: 0,
+ by: args,
+ direction: Direction::Deepen,
+ });
+ let out = visitable.fold(self);
+ self.expr.map(&mut RenameVars {
+ depth: 0,
+ by: args,
+ direction: Direction::Shallow,
+ });
+ self.index -= args;
+ out
+ }
+}
+
impl Folder for Substitute {
type Out = NamedExpression;
- fn fold_epsilon(&mut self, name: Option<Name>, span: Option<Span>, eps: Epsilon) -> Self::Out {
+ fn fold_epsilon(&mut self, name: Option<Name>, span: Span, eps: Epsilon) -> Self::Out {
NamedExpression {
name,
expr: eps.into(),
@@ -115,7 +158,7 @@ impl Folder for Substitute {
}
}
- fn fold_literal(&mut self, name: Option<Name>, span: Option<Span>, lit: Literal) -> Self::Out {
+ fn fold_literal(&mut self, name: Option<Name>, span: Span, lit: Literal) -> Self::Out {
NamedExpression {
name,
expr: lit.into(),
@@ -123,7 +166,7 @@ impl Folder for Substitute {
}
}
- fn fold_cat(&mut self, name: Option<Name>, span: Option<Span>, mut cat: Cat) -> Self::Out {
+ fn fold_cat(&mut self, name: Option<Name>, span: Span, mut cat: Cat) -> Self::Out {
cat.first = Box::new(cat.first.fold(self));
cat.rest = cat
.rest
@@ -137,7 +180,7 @@ impl Folder for Substitute {
}
}
- fn fold_alt(&mut self, name: Option<Name>, span: Option<Span>, mut alt: Alt) -> Self::Out {
+ fn fold_alt(&mut self, name: Option<Name>, span: Span, mut alt: Alt) -> Self::Out {
alt.first = Box::new(alt.first.fold(self));
alt.rest = alt
.rest
@@ -151,7 +194,7 @@ impl Folder for Substitute {
}
}
- fn fold_fix(&mut self, name: Option<Name>, span: Option<Span>, mut fix: Fix) -> Self::Out {
+ fn fold_fix(&mut self, name: Option<Name>, span: Span, mut fix: Fix) -> Self::Out {
fix.inner = Box::new(fix.inner.fold(self));
NamedExpression {
name,
@@ -163,11 +206,13 @@ impl Folder for Substitute {
fn fold_variable(
&mut self,
name: Option<Name>,
- span: Option<Span>,
+ span: Span,
var: Variable,
) -> Self::Out {
if var.index == self.index {
- self.expr.clone()
+ let mut out = self.expr.clone();
+ out.name = Name::merge(out.name, name);
+ out
} else {
NamedExpression {
name,
@@ -184,7 +229,7 @@ impl Folder for Substitute {
}
}
- fn fold_call(&mut self, name: Option<Name>, span: Option<Span>, mut call: Call) -> Self::Out {
+ fn fold_call(&mut self, name: Option<Name>, span: Span, mut call: Call) -> Self::Out {
call.on = Box::new(call.on.fold(self));
call.args = call.args.into_iter().map(|e| e.fold(self)).collect();
NamedExpression {
@@ -197,40 +242,36 @@ impl Folder for Substitute {
fn fold_lambda(
&mut self,
name: Option<Name>,
- span: Option<Span>,
+ span: Span,
mut lambda: Lambda,
) -> Self::Out {
- self.index += lambda.args.len();
- lambda.inner = Box::new(lambda.inner.fold(self));
- self.index -= lambda.args.len();
+ let depth = lambda.args.len();
+ lambda.inner = Box::new(self.with_args(depth, lambda.inner));
NamedExpression {
name,
expr: lambda.into(),
span,
}
}
-}
-pub struct Translate {
- changed: bool,
-}
-
-impl Translate {
- pub fn new() -> Self {
- Self { changed: false }
+ fn fold_let(&mut self, name: Option<Name>, span: Span, mut stmt: Let) -> Self::Out {
+ stmt.bound = Box::new(stmt.bound.fold(self));
+ stmt.body = Box::new(self.with_args(1, stmt.body));
+ NamedExpression {
+ name,
+ expr: stmt.into(),
+ span,
+ }
}
}
-impl Default for Translate {
- fn default() -> Self {
- Self::new()
- }
-}
+#[derive(Copy, Clone, Debug)]
+pub struct Reduce;
-impl Folder for Translate {
- type Out = Result<NamedExpression, TranslateError>;
+impl Folder for Reduce {
+ type Out = Result<NamedExpression, ReductionError>;
- fn fold_epsilon(&mut self, name: Option<Name>, span: Option<Span>, eps: Epsilon) -> Self::Out {
+ fn fold_epsilon(&mut self, name: Option<Name>, span: Span, eps: Epsilon) -> Self::Out {
Ok(NamedExpression {
name,
expr: eps.into(),
@@ -238,7 +279,7 @@ impl Folder for Translate {
})
}
- fn fold_literal(&mut self, name: Option<Name>, span: Option<Span>, lit: Literal) -> Self::Out {
+ fn fold_literal(&mut self, name: Option<Name>, span: Span, lit: Literal) -> Self::Out {
Ok(NamedExpression {
name,
expr: lit.into(),
@@ -246,7 +287,13 @@ impl Folder for Translate {
})
}
- fn fold_cat(&mut self, name: Option<Name>, span: Option<Span>, cat: Cat) -> Self::Out {
+ fn fold_cat(&mut self, name: Option<Name>, span: Span, mut cat: Cat) -> Self::Out {
+ cat.first = Box::new(cat.first.fold(self)?);
+ cat.rest = cat
+ .rest
+ .into_iter()
+ .map(|(p, e)| Ok((p, e.fold(self)?)))
+ .collect::<Result<_, _>>()?;
Ok(NamedExpression {
name,
expr: cat.into(),
@@ -254,7 +301,13 @@ impl Folder for Translate {
})
}
- fn fold_alt(&mut self, name: Option<Name>, span: Option<Span>, alt: Alt) -> Self::Out {
+ fn fold_alt(&mut self, name: Option<Name>, span: Span, mut alt: Alt) -> Self::Out {
+ alt.first = Box::new(alt.first.fold(self)?);
+ alt.rest = alt
+ .rest
+ .into_iter()
+ .map(|(p, e)| Ok((p, e.fold(self)?)))
+ .collect::<Result<_, _>>()?;
Ok(NamedExpression {
name,
expr: alt.into(),
@@ -262,7 +315,13 @@ impl Folder for Translate {
})
}
- fn fold_fix(&mut self, name: Option<Name>, span: Option<Span>, fix: Fix) -> Self::Out {
+ fn fold_fix(&mut self, name: Option<Name>, span: Span, mut fix: Fix) -> Self::Out {
+ let mut inner = fix.inner.fold(self)?;
+ if let Expression::Lambda(mut l) = inner.expr {
+ l.inner = Box::new(l.inner.fold(self)?);
+ inner.expr = Expression::Lambda(l);
+ }
+ fix.inner = Box::new(inner);
Ok(NamedExpression {
name,
expr: fix.into(),
@@ -273,7 +332,7 @@ impl Folder for Translate {
fn fold_variable(
&mut self,
name: Option<Name>,
- span: Option<Span>,
+ span: Span,
var: Variable,
) -> Self::Out {
Ok(NamedExpression {
@@ -283,21 +342,16 @@ impl Folder for Translate {
})
}
- fn fold_call(&mut self, name: Option<Name>, span: Option<Span>, call: Call) -> Self::Out {
- let mut on = *call.on;
- self.changed = true;
- while self.changed {
- self.changed = false;
- on = on.fold(self)?;
- }
+ fn fold_call(&mut self, name: Option<Name>, span: Span, call: Call) -> Self::Out {
+ let on = call.on.fold(self)?;
let lambda = on
.expr
.try_into_lambda()
- .map_err(|on| TranslateError::CallNotAFunction { on, span })?;
+ .map_err(|on| ReductionError::CallNotAFunction { on, span })?;
if lambda.args.len() != call.args.len() {
- return Err(TranslateError::WrongArgCount {
+ return Err(ReductionError::WrongArgCount {
lambda,
args: call.args,
span,
@@ -307,33 +361,44 @@ impl Folder for Translate {
let mut out = *lambda.inner;
for ((i, mut arg), name) in call.args.into_iter().enumerate().zip(lambda.args).rev() {
- arg.name = arg.name.or(Some(name));
- arg.map(&mut Deepen { depth: 0, by: i });
+ arg.name = Name::merge(arg.name, Some(name));
+ arg.map(&mut RenameVars {
+ depth: 0,
+ by: i,
+ direction: Direction::Deepen,
+ });
out = out.fold(&mut Substitute {
index: 0,
expr: arg,
});
}
- self.changed = true;
- while self.changed {
- self.changed = false;
- out = out.fold(self)?;
- }
-
- self.changed = true;
- out.name = name.or(out.name);
- out.span = span.or(out.span);
+ out = out.fold(self)?;
+ out.name = Name::merge_all(array::IntoIter::new([name, on.name, out.name]));
+ out.span = span;
Ok(out)
}
- fn fold_lambda(&mut self, name: Option<Name>, span: Option<Span>, lambda: Lambda) -> Self::Out {
+ fn fold_lambda(&mut self, name: Option<Name>, span: Span, lambda: Lambda) -> Self::Out {
Ok(NamedExpression {
name,
expr: lambda.into(),
span,
})
}
+
+ fn fold_let(&mut self, name: Option<Name>, span: Span, stmt: Let) -> Self::Out {
+ let mut out = stmt
+ .body
+ .fold(&mut Substitute {
+ index: 0,
+ expr: *stmt.bound,
+ })
+ .fold(self)?;
+ out.name = Name::merge(out.name, name);
+ out.span = span;
+ Ok(out)
+ }
}
#[cfg(test)]
@@ -345,23 +410,23 @@ mod tests {
let var = NamedExpression {
name: None,
expr: Variable { index: 0 }.into(),
- span: None,
+ span: Span::call_site(),
};
let lambda = NamedExpression {
name: None,
expr: Lambda {
- args: vec!["x".to_owned().into()],
+ args: vec![Name::new_variable("x".to_owned())],
inner: Box::new(var),
}
.into(),
- span: None,
+ span: Span::call_site(),
};
let var = NamedExpression {
name: None,
expr: Variable { index }.into(),
- span: None,
+ span: Span::call_site(),
};
NamedExpression {
@@ -371,14 +436,18 @@ mod tests {
args: vec![var],
}
.into(),
- span: None,
+ span: Span::call_site(),
}
}
#[test]
fn deepen_lambda() {
let mut expr = make_expr(0);
- expr.map(&mut Deepen { depth: 0, by: 1 });
+ expr.map(&mut RenameVars {
+ depth: 0,
+ by: 1,
+ direction: Direction::Deepen,
+ });
assert_eq!(expr, make_expr(1))
}
@@ -390,22 +459,22 @@ mod tests {
expr: NamedExpression {
name: None,
expr: Epsilon.into(),
- span: None,
+ span: Span::call_site(),
},
});
assert_eq!(expr, make_expr(0))
}
#[test]
- fn translate_lambda() {
+ fn reduce_lambda() {
let expr = make_expr(1);
- let expr = expr.fold(&mut Translate::new()).unwrap();
+ let expr = expr.fold(&mut Reduce).unwrap();
assert_eq!(
expr,
NamedExpression {
- name: Some("x".to_owned().into()),
+ name: Some(Name::new_variable("x".to_owned())),
expr: Variable { index: 1 }.into(),
- span: None
+ span: Span::call_site(),
}
)
}