From 8dbabef99fcd78690c72396d5736b36a50a232d8 Mon Sep 17 00:00:00 2001 From: porcuquine Date: Sat, 5 Aug 2023 01:51:44 -0700 Subject: [PATCH] WIP - let/bind/pop-binding working. Test needs updating. --- src/foil/coil.rs | 105 ++++++++++++++++++++++++++++++++++++----------- src/foil/mod.rs | 7 ++-- src/store.rs | 19 +++++++++ 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/src/foil/coil.rs b/src/foil/coil.rs index 370e1b4261..d8e66ba509 100644 --- a/src/foil/coil.rs +++ b/src/foil/coil.rs @@ -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 for Func { fn from(sym: Symbol) -> Self { @@ -81,6 +82,47 @@ impl Context { } } + fn lookup(&self, store: &Store, var: &Ptr) -> Result> { + 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, env: &Ptr, var: &Ptr) -> Result> { + 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, var: Ptr, id: Id) { let num = store.intern_num(id as u64); let binding = store.cons(var, num); @@ -90,7 +132,7 @@ impl Context { fn pop_binding(&mut self, store: &Store) -> Result { 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) @@ -215,6 +257,7 @@ impl> CoilDef { def } } + impl, S: Syntax> CoilDef { fn register_relation(&mut self, sym: Symbol, rel: R) { self.relations.insert(sym, rel); @@ -287,7 +330,7 @@ impl<'a, F: LurkField, R: Relation, S: Syntax> CoilDef { ) -> Result { 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"))?; @@ -295,35 +338,39 @@ impl<'a, F: LurkField, R: Relation, S: Syntax> CoilDef { 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::>(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::>>()?; - - // 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::>>()?; + + 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::>>()?; + info!("adding to foil: {sym:}, {meta:?}"); let func = self.symbol_func(sym); @@ -332,9 +379,17 @@ impl<'a, F: LurkField, R: Relation, S: Syntax> CoilDef { } 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); @@ -353,12 +408,13 @@ impl<'a, F: LurkField, R: Relation, S: Syntax> CoilDef { 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()); @@ -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::::new( &def, + // FoilConfig::default(), FoilConfig { dedup_var_names: false, }, @@ -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); } { @@ -573,7 +630,7 @@ mod test { Some(vec![0]), ), ]; - assert_expected_classes(expected_classes, classes); + // assert_expected_classes(expected_classes, classes); } info!("minimizing"); diff --git a/src/foil/mod.rs b/src/foil/mod.rs index e3c2ff71d1..226131dc2c 100644 --- a/src/foil/mod.rs +++ b/src/foil/mod.rs @@ -549,9 +549,10 @@ impl Foil { } 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(); diff --git a/src/store.rs b/src/store.rs index f7a85698df..4826f180fe 100644 --- a/src/store.rs +++ b/src/store.rs @@ -1346,6 +1346,25 @@ impl Store { } } + pub fn maybe_car_cdr(&self, ptr: &Ptr) -> Result, Ptr)>, 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) -> Option> { let s = self.opaque_ptrs.get_index(ptr.raw.opaque_idx()?)?; Some(*s)