feat: stack var (WIP)
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
use derive_more::{IsVariant, TryUnwrap, Unwrap};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use nixjit_error::{Error, Result};
|
||||
use nixjit_hir as hir;
|
||||
use nixjit_ir::*;
|
||||
@@ -38,19 +39,20 @@ ir! {
|
||||
Str,
|
||||
Var,
|
||||
Path,
|
||||
PrimOp,
|
||||
Arg,
|
||||
PrimOp(PrimOpId),
|
||||
StackRef(StackIdx),
|
||||
ExprRef(ExprId),
|
||||
FuncRef(ExprId),
|
||||
ArgRef(ArgIdx),
|
||||
Thunk(ExprId),
|
||||
}
|
||||
|
||||
/// Represents the result of a variable lookup within the `ResolveContext`.
|
||||
#[derive(Debug)]
|
||||
pub enum LookupResult {
|
||||
Stack(StackIdx),
|
||||
/// The variable was found and resolved to a specific expression.
|
||||
Expr(ExprId),
|
||||
/// The variable was found and resolved to a function argument.
|
||||
Arg(ArgIdx),
|
||||
/// The variable could not be resolved statically, likely due to a `with` expression.
|
||||
/// The lookup must be performed dynamically at evaluation time.
|
||||
Unknown,
|
||||
@@ -63,30 +65,36 @@ pub enum LookupResult {
|
||||
/// This trait abstracts the environment in which expressions are resolved, managing
|
||||
/// scopes, dependencies, and the resolution of expressions themselves.
|
||||
pub trait ResolveContext {
|
||||
/// Records a dependency of one expression on another.
|
||||
fn new_dep(&mut self, expr: ExprId, dep: ExprId);
|
||||
|
||||
/// Creates a new function, associating a parameter specification with a body expression.
|
||||
fn new_func(&mut self, body: ExprId, param: Param);
|
||||
|
||||
/// Triggers the resolution of a given expression.
|
||||
fn resolve(&mut self, expr: ExprId) -> Result<()>;
|
||||
|
||||
fn resolve_root(self, expr: ExprId) -> Result<()>;
|
||||
|
||||
/// Looks up a variable by name in the current scope.
|
||||
fn lookup(&self, name: &str) -> LookupResult;
|
||||
fn lookup(&mut self, name: &str) -> LookupResult;
|
||||
|
||||
fn lookup_arg(&mut self) -> StackIdx;
|
||||
|
||||
/// Enters a `with` scope for the duration of a closure.
|
||||
fn with_with_env<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> (bool, T);
|
||||
|
||||
/// Enters a `let` scope with a given set of bindings for the duration of a closure.
|
||||
fn with_let_env<'a, T>(
|
||||
fn with_let_env<T>(
|
||||
&mut self,
|
||||
bindings: impl Iterator<Item = (&'a String, &'a ExprId)>,
|
||||
bindings: HashMap<String, ExprId>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
|
||||
/// Enters a function parameter scope for the duration of a closure.
|
||||
fn with_param_env<T>(&mut self, ident: Option<String>, f: impl FnOnce(&mut Self) -> T) -> T;
|
||||
fn with_param_env<T>(
|
||||
&mut self,
|
||||
func: ExprId,
|
||||
ident: Option<String>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
}
|
||||
|
||||
/// A trait for converting (resolving) an HIR node into an LIR expression.
|
||||
@@ -117,10 +125,11 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Hir {
|
||||
Var(x) => x.resolve(ctx),
|
||||
Path(x) => x.resolve(ctx),
|
||||
Let(x) => x.resolve(ctx),
|
||||
// The `Arg` in HIR is a placeholder. During resolution, it's replaced by
|
||||
// a reference to the *current* function's argument. We assume index 0
|
||||
// here, as the context manages the actual argument index.
|
||||
Arg(_) => unsafe { Ok(Lir::ArgRef(ArgIdx::from(0))) },
|
||||
Thunk(x) => {
|
||||
ctx.resolve(x)?;
|
||||
Ok(Lir::Thunk(x))
|
||||
}
|
||||
Arg(_) => Ok(Lir::StackRef(ctx.lookup_arg()))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,28 +137,14 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Hir {
|
||||
/// Resolves an `AttrSet` by resolving all key and value expressions.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for AttrSet {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
if self.rec {
|
||||
ctx.with_let_env(self.stcs.iter(), |ctx| {
|
||||
for &id in self.stcs.values() {
|
||||
ctx.resolve(id)?;
|
||||
}
|
||||
for &(k, v) in self.dyns.iter() {
|
||||
ctx.resolve(k)?;
|
||||
ctx.resolve(v)?;
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
Ok(self.to_lir())
|
||||
} else {
|
||||
for (_, &v) in self.stcs.iter() {
|
||||
ctx.resolve(v)?;
|
||||
}
|
||||
for &(k, v) in self.dyns.iter() {
|
||||
ctx.resolve(k)?;
|
||||
ctx.resolve(v)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
for (_, &v) in self.stcs.iter() {
|
||||
ctx.resolve(v)?;
|
||||
}
|
||||
for &(k, v) in self.dyns.iter() {
|
||||
ctx.resolve(k)?;
|
||||
ctx.resolve(v)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,7 +219,7 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for If {
|
||||
/// It then registers the function with the context.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_param_env(self.param.ident.clone(), |ctx| ctx.resolve(self.body))?;
|
||||
ctx.with_param_env(self.body, self.param.ident.clone(), |ctx| ctx.resolve(self.body))?;
|
||||
ctx.new_func(self.body, self.param);
|
||||
Ok(Lir::FuncRef(self.body))
|
||||
}
|
||||
@@ -234,9 +229,7 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Call {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.func)?;
|
||||
for &arg in self.args.iter() {
|
||||
ctx.resolve(arg)?;
|
||||
}
|
||||
ctx.resolve(self.arg)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
@@ -282,10 +275,10 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Var {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
use LookupResult::*;
|
||||
match ctx.lookup(&self.sym) {
|
||||
Stack(idx) => Ok(Lir::StackRef(idx)),
|
||||
Expr(expr) => Ok(Lir::ExprRef(expr)),
|
||||
Arg(arg) => Ok(Lir::ArgRef(arg)),
|
||||
Unknown => Ok(self.to_lir()),
|
||||
NotFound => Err(Error::ResolutionError(format!(
|
||||
NotFound => Err(Error::resolution_error(format!(
|
||||
"undefined variable '{}'",
|
||||
format_symbol(&self.sym)
|
||||
))),
|
||||
@@ -305,7 +298,7 @@ impl<Ctx: ResolveContext> Resolve<Ctx> for Path {
|
||||
/// the bindings and the body, and then returning a reference to the body.
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Let {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_let_env(self.bindings.iter(), |ctx| {
|
||||
ctx.with_let_env(self.bindings.clone(), |ctx| {
|
||||
for &id in self.bindings.values() {
|
||||
ctx.resolve(id)?;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user