Skip to content

Commit

Permalink
WIP - let/bind/pop-binding working. Test needs updating.
Browse files Browse the repository at this point in the history
  • Loading branch information
porcuquine committed Aug 5, 2023
1 parent d82789a commit 8dbabef
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 27 deletions.
105 changes: 81 additions & 24 deletions src/foil/coil.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::store::Store;
use crate::sym;
use crate::symbol::Symbol;
use crate::tag::ExprTag;
use crate::writer::Write;

impl From<Symbol> for Func<CoilMeta> {
fn from(sym: Symbol) -> Self {
Expand Down Expand Up @@ -81,6 +82,47 @@ impl<F: LurkField> Context<F> {
}
}

fn lookup(&self, store: &Store<F>, var: &Ptr<F>) -> Result<Option<Id>> {
info!(
"looking up {} in env: {}",
var.fmt_to_string(store),
self.env.fmt_to_string(store)
);
self.lookup_aux(store, &self.env, var)
}

fn lookup_aux(&self, store: &Store<F>, env: &Ptr<F>, var: &Ptr<F>) -> Result<Option<Id>> {
if let Some((binding, rest_env)) = store
.maybe_car_cdr(env)
.map_err(|_| anyhow!("env not a list"))?
{
if let Some((bound_var, id)) = store
.maybe_car_cdr(&binding)
.map_err(|_| anyhow!("binding not a pair"))?
{
if *var == bound_var {
match store.fetch_num(&id) {
Some(crate::num::Num::U64(n)) => {
info!("found {n}");
Ok(((*n) as Id).into())
}
_ => {
bail!("binding Id could not be fetched");
}
}
} else {
self.lookup_aux(store, &rest_env, var)
}
} else {
info!("unbound");
Ok(None)
}
} else {
info!("unbound");
Ok(None)
}
}

fn push_binding(&mut self, store: &mut Store<F>, var: Ptr<F>, id: Id) {
let num = store.intern_num(id as u64);
let binding = store.cons(var, num);
Expand All @@ -90,7 +132,7 @@ impl<F: LurkField> Context<F> {
fn pop_binding(&mut self, store: &Store<F>) -> Result<Id> {
let (car, cdr) = store
.car_cdr(&self.env)
.map_err(|_| anyhow!("failed to destrcture env"))?;
.map_err(|_| anyhow!("failed to destructure env"))?;
self.env = cdr;
let (var, id) = store
.car_cdr(&car)
Expand Down Expand Up @@ -215,6 +257,7 @@ impl<F: LurkField, R: Relation<F>> CoilDef<F, R, CoilSyntax> {
def
}
}

impl<F: LurkField, R: Relation<F>, S: Syntax<F>> CoilDef<F, R, S> {
fn register_relation(&mut self, sym: Symbol, rel: R) {
self.relations.insert(sym, rel);
Expand Down Expand Up @@ -287,43 +330,47 @@ impl<'a, F: LurkField, R: Relation<F>, S: Syntax<F>> CoilDef<F, R, S> {
) -> Result<Vert> {
match expr.tag {
ExprTag::Cons => {
info!("adding sexp");
info!("adding sexp: {}", expr.fmt_to_string(store));

let list = store.fetch_list(expr).expect("sexps must be proper lists");
let head = list.get(0).ok_or(anyhow!("missing head"))?;
let sym = store.fetch_sym(head).ok_or(anyhow!("sym not in store"))?;
let rest = &list[1..];
let meta = CoilMeta::from(sym.clone());

// TODO:
// Check for bind forms and push binding of var and its allocated vertex onto context env.
// context needs to be passed to `add_to_foil`.
//
// Check for pop-env forms and remove one binding from env.
// Alternately, save and restore envs explicitly, but popping is probably simplest, at least for now.

if let Some(syntax) = AsSyntax::<CoilDef<F, R, S>>(self).find(&meta) {
let expanded = syntax.expand(foil, store, head, rest)?;

let mut last = None;
for x in expanded.iter() {
// FIXME: Add a way for expanded expressions to signal which of their sub-values' resultant
// vertices should be returned. Here, we take the value of the last. However, in the case of
// Let, for example, the last form will be a pop-binding (assuming there were any bindings).
// Moreover, it will be the *first* binding. The value of the first binding is not the intuitive
// or correct return value for an expanded form. In the case of Let, it should be the last body
// form -- which will preced the first pop-binding. There should be a general mechanism for this.
last = Some(self.add_to_foil(foil, store, context, x));
}
last.ok_or(anyhow!("result Vert missing"))?
} else {
let successor_verts = rest
.iter()
.map(|succ| self.add_to_foil(foil, store, context, succ))
.collect::<Result<Vec<_>>>()?;

// TODO: don't actually create this symbol here.
// TODO: don't actually create these literal symbols here.
if sym == sym!("coil", "bind") {
self.handle_bind(store, context, rest, &successor_verts)?;
let rest_successor_verts = rest
.iter()
.skip(1)
.map(|succ| self.add_to_foil(foil, store, context, succ))
.collect::<Result<Vec<_>>>()?;

self.handle_bind(store, context, rest, &rest_successor_verts)?;
} else if sym == sym!("coil", "pop-binding") {
//return Ok(Vert::from(1));
return self.handle_pop_binding(store, context, rest);
}

let successor_verts = rest
.iter()
.map(|succ| self.add_to_foil(foil, store, context, succ))
.collect::<Result<Vec<_>>>()?;

info!("adding to foil: {sym:}, {meta:?}");
let func = self.symbol_func(sym);

Expand All @@ -332,9 +379,17 @@ impl<'a, F: LurkField, R: Relation<F>, S: Syntax<F>> CoilDef<F, R, S> {
}
ExprTag::Sym => {
info!("adding symbol");
let sym = store.fetch_sym(expr).expect("missing sym");

Ok(foil.intern_var_by_label(sym).1)
if let Some(bound_id) = context
.lookup(store, expr)
.map_err(|_| anyhow!("lookup error"))?
{
Ok(Vert::new(bound_id))
} else {
let sym = store.fetch_sym(expr).expect("missing sym");

Ok(foil.alloc(sym))
}
}
x => {
dbg!(x);
Expand All @@ -353,12 +408,13 @@ impl<'a, F: LurkField, R: Relation<F>, S: Syntax<F>> CoilDef<F, R, S> {
if args.len() != 2 {
bail!("bind needs exactly two args")
};
if successors.len() != 2 {
if successors.len() != 1 {
bail!("bind needs exactly two successors")
};

let var = args[0];
let vert = successors[0];
info!("binding {} to {}", var.fmt_to_string(store), vert.id());

context.push_binding(store, var, vert.id());

Expand Down Expand Up @@ -501,15 +557,16 @@ mod test {

let_store!(); // TODO: take field type parameter. This macro currently hard-codes Fr.

let prog = lurk!((let ()
let prog = lurk!((let ((y (cons q r)))
(let ((x (cons a b)))
(car x))
(car x)
(car y)
))
.unwrap();

let mut foil = Foil::<Fr, CoilMeta>::new(
&def,
// FoilConfig::default(),
FoilConfig {
dedup_var_names: false,
},
Expand All @@ -533,7 +590,7 @@ mod test {
(6, vec!["lurk.car: 6"], Some(vec![0])),
];

assert_expected_classes(expected_classes, classes);
//assert_expected_classes(expected_classes, classes);
}

{
Expand Down Expand Up @@ -573,7 +630,7 @@ mod test {
Some(vec![0]),
),
];
assert_expected_classes(expected_classes, classes);
// assert_expected_classes(expected_classes, classes);
}

info!("minimizing");
Expand Down
7 changes: 4 additions & 3 deletions src/foil/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,10 @@ impl<T: PartialEq + Clone, M: MetaData> Foil<T, M> {
}

pub fn finalize_for_schema(&mut self) {
// TODO: We might not want to do this, or to make it configurable.
// See comment in test, `constructors::test_var_equivalence`.
self.enqueue_var_equivalences_for_merge();
// See comment in test, [crate::foil::constructors::test_var_equivalence].
if self.config.dedup_var_names {
self.enqueue_var_equivalences_for_merge();
}

self.add_all_missing_constructors();
self.process_all_constructors();
Expand Down
19 changes: 19 additions & 0 deletions src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,25 @@ impl<F: LurkField> Store<F> {
}
}

pub fn maybe_car_cdr(&self, ptr: &Ptr<F>) -> Result<Option<(Ptr<F>, Ptr<F>)>, Error> {
match ptr.tag {
ExprTag::Nil => Ok(None),
ExprTag::Cons => match self.fetch(ptr) {
Some(Expression::Cons(car, cdr)) => Ok(Some((car, cdr))),
e => Err(Error(format!(
"Can only extract car_cdr from known Cons, instead got {:?} {:?}",
ptr, e,
))),
},
ExprTag::Str => match self.fetch(ptr) {
Some(Expression::Str(car, cdr)) => Ok(Some((car, cdr))),
Some(Expression::EmptyStr) => Ok(Some((self.get_nil(), self.strnil()))),
_ => unreachable!(),
},
_ => Err(Error("Can only extract car_cdr from Cons".into())),
}
}

pub fn get_opaque_ptr(&self, ptr: Ptr<F>) -> Option<ZExprPtr<F>> {
let s = self.opaque_ptrs.get_index(ptr.raw.opaque_idx()?)?;
Some(*s)
Expand Down

0 comments on commit 8dbabef

Please sign in to comment.