# HG changeset patch # User Simon Heath # Date 1742585740 14400 # Fri Mar 21 15:35:40 2025 -0400 # Branch devel # Node ID ba29cf9e5f49b0b0c27404401638faf01841a1d8 # Parent 7b52c0b79f45f0098dda7a142def70b4eacc4a36 bleh diff --git a/src/hir2.rs b/src/hir2.rs --- a/src/hir2.rs +++ b/src/hir2.rs @@ -19,6 +19,7 @@ use crate::*; pub mod lower; +pub mod shift; pub mod visit; /// The types.rs types turn out to not be *exactly* what I want for NbE, since there's some diff --git a/src/hir2/lower.rs b/src/hir2/lower.rs --- a/src/hir2/lower.rs +++ b/src/hir2/lower.rs @@ -643,10 +643,13 @@ } /// For debugging + /// + /// BUGGO: This is ALMOST an exact copy of nbe::trace_value_bindings() fn trace_value_bindings(&self) { trace!("Name bindings:"); - for (i, val) in self.bindings.iter().enumerate() { - trace!(" {i} = {val:?}") + // We print out in reverse order so they're DB indices + for (i, val) in self.bindings.iter().rev().enumerate() { + trace!(" Idx({i}) = {val}") } } diff --git a/src/hir2/shift.rs b/src/hir2/shift.rs new file mode 100644 --- /dev/null +++ b/src/hir2/shift.rs @@ -0,0 +1,33 @@ +//! Implementation of the irritating de Bruijn index +//! shift operations, which I was really hoping to avoid. +//! Sigh. + +use std::convert::TryFrom; + +use crate::hir2::visit; +use crate::hir2::*; + +pub fn shift_expr(expr: ENode, amount: i64) -> ENode { + use visit::Visit; + let mut v = ShiftVisitor::new(amount); + v.visit_exprnode(&expr) +} + +struct ShiftVisitor { + amount: i64, +} + +impl ShiftVisitor { + fn new(amount: i64) -> Self { + Self { amount } + } +} + +impl visit::Visit for ShiftVisitor { + fn visit_var(&mut self, name: Sym, idx: Idx) -> Expr { + let new_idx = i64::try_from(idx.0).expect("How did this happen") + self.amount; + assert!(new_idx >= 0, "negative de bruijn index, aieeee"); + let idx = Idx(new_idx as usize); + Expr::Var { name, idx } + } +} diff --git a/src/nbe.rs b/src/nbe.rs --- a/src/nbe.rs +++ b/src/nbe.rs @@ -101,6 +101,25 @@ Lambda(ENode, NType), } +impl fmt::Display for ValBinding { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ValBinding::Var(t, name, false) => { + let valtype = quote(0, t.clone()).unwrap(); + write!(f, "let {}: {}", name, valtype) + } + ValBinding::Var(t, name, true) => { + let valtype = quote(0, t.clone()).unwrap(); + write!(f, "mut {}: {}", name, valtype) + } + ValBinding::Lambda(expr, arg) => { + let argtype = quote(0, arg.clone()).unwrap(); + write!(f, "lambda {}: {:?}", expr, argtype) + } + } + } +} + /// A type-closure in the "evaluation" portion of our NbE setup. /// The values are the args, captured environment, and body. #[derive(Debug, Clone, PartialEq, PartialOrd)] @@ -232,8 +251,9 @@ /// For debugging fn trace_value_bindings(&self) { trace!("Name bindings:"); - for (i, val) in self.vals.iter().enumerate() { - trace!(" {i} = {val:?}") + // We print out in reverse order so they're DB indices + for (i, val) in self.vals.iter().rev().enumerate() { + trace!(" Idx({i}) = {val}") } } diff --git a/src/passes2/lambda_lift.rs b/src/passes2/lambda_lift.rs --- a/src/passes2/lambda_lift.rs +++ b/src/passes2/lambda_lift.rs @@ -18,31 +18,33 @@ } impl Visit for LambdaLiftVisitor { - fn visit_expr(&mut self, e: &Expr) -> Expr { - match e { - Expr::Lambda { signature, body } => { - // This is actually the only important bit. - // TODO: Make a more informative name, maybe including the file and line number or - // such. - let lambda_name = INT.gensym("__lambda"); - trace!("Lambda-lifting expr {} into {}", e, lambda_name); - let body = visit::walk_exprnodes(self, body); - let function_decl = Function { - name: lambda_name, - signature: signature.clone(), - body, - }; - self.output_funcs.push(function_decl); - // TODO: We have to generate valid var indices here, but, how? - // Re-do the hir2::lower::IndexRenamer pass? - // Keep them as levels everywhere, and convert them to indices - // on-demand in the NbE stuff? - Expr::Var { - name: lambda_name, - idx: Idx::invalid(), - } - } - x => visit::walk_expr(self, x), + fn visit_lambda(&mut self, sig: &Sig, body: &[ENode]) -> Expr { + // This is actually the only important bit. + // TODO: Make a more informative name, maybe including the file and line number or + // such. + let lambda_name = INT.gensym("__lambda"); + trace!( + "Lambda-lifting expr {} into {}", + Expr::Lambda { + signature: sig.clone(), + body: body.to_vec() + }, + lambda_name + ); + let body = visit::walk_exprnodes(self, body); + let function_decl = Function { + name: lambda_name, + signature: sig.clone(), + body, + }; + self.output_funcs.push(function_decl); + // TODO: We have to generate valid var indices here, but, how? + // Re-do the hir2::lower::IndexRenamer pass? + // Keep them as levels everywhere, and convert them to indices + // on-demand in the NbE stuff? + Expr::Var { + name: lambda_name, + idx: Idx::invalid(), } } } diff --git a/tests/programs/exprs.gt b/tests/programs/exprs.gt --- a/tests/programs/exprs.gt +++ b/tests/programs/exprs.gt @@ -18,7 +18,7 @@ __println(3 * 3 + 2) let mut test fn(I32) I32 = fn(x I32) I32 = 3 * x + 2 end - --__println(test(3)) + __println(test(3)) --test = fn(x I32) I32 = if true then x else 3 * 2 end end --__println(test(3))