From 3c7722a3d2e98930f92c4b5f1cee9ce636e0711b Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Fri, 15 Aug 2025 12:38:11 +0800 Subject: [PATCH] feat: graph (WIP) --- TODO.md | 24 +++++++++++++++- evaluator/nixjit_context/src/eval.rs | 8 ++---- evaluator/nixjit_context/src/lib.rs | 14 +++++++++- evaluator/nixjit_context/src/resolve.rs | 32 ++++++++++++---------- evaluator/nixjit_eval/src/lib.rs | 12 ++++++-- evaluator/nixjit_eval/src/value/closure.rs | 6 +++- evaluator/nixjit_lir/src/lib.rs | 12 +++++--- 7 files changed, 78 insertions(+), 30 deletions(-) diff --git a/TODO.md b/TODO.md index 9cc44a3..234d694 100644 --- a/TODO.md +++ b/TODO.md @@ -2,4 +2,26 @@ - [ ] resolve stage - [ ] dynamic attr resolution - [ ] import resolution - - [ ] path resolution + - [ ] static path resolution +- [ ] eval stage + - [ ] dynamic path resolution + - [ ] graph update + - [ ] stack storage + +阻拦变量解析的是 `with import` 而不是一般的 `with` +解析阶段可以解决除涉及非字符串常量拼接路径导入之外的问题 + +# 工作流程 +```mermaid +flowchart TD + Start --> CtxNew[Context::new] + CtxNew --> CtxEval[Context::eval] + CtxEval --> DCtxNew[DowngradeCtx::new] + DCtxNew --> DCtxDowngradeRoot[DowngradeCtx::downgrade_root] + DCtxDowngradeRoot --> RCtxNew[ResolveCtx::new] + RCtxNew --> RCtxResolveRoot[ResolveCtx::resolve_root] + RCtxResolveRoot --> ECtxNew[EvalCtx::new] + ECtxNew --> ECtxEvalRoot[EvalCtx::eval_root] + ECtxEvalRoot --> ECtxEvalDeps[EvalCtx::eval_deps] + ECtxEvalDeps --> ECtxEval[EvalCtx::eval] +``` diff --git a/evaluator/nixjit_context/src/eval.rs b/evaluator/nixjit_context/src/eval.rs index ed5e8ef..6b1ff93 100644 --- a/evaluator/nixjit_context/src/eval.rs +++ b/evaluator/nixjit_context/src/eval.rs @@ -8,6 +8,7 @@ use nixjit_eval::{Args, EvalContext, Evaluate, StackFrame, Value}; use nixjit_ir::ExprId; use nixjit_jit::JITContext; use nixjit_lir::Lir; +use petgraph::visit::{Topo, Walker}; use super::Context; @@ -40,10 +41,7 @@ impl<'ctx, 'bump> EvalCtx<'ctx, 'bump> { dbg!(&deps, &self.stack); for (dep, idx) in deps { unsafe { - if matches!( - &**self.ctx.lirs.get_unchecked(dep.raw()), - Lir::Arg(_) - ) { + if matches!(&**self.ctx.lirs.get_unchecked(dep.raw()), Lir::Arg(_)) { *frame.get_unchecked_mut(idx.raw()) = arg.as_ref().unwrap().clone(); continue; } @@ -76,7 +74,7 @@ impl EvalContext for EvalCtx<'_, '_> { self.stack.push(frame); if let Err(err) = self.eval_deps(func, arg) { self.stack.pop(); - return Err(err) + return Err(err); } let ret = self.eval(func); self.stack.pop(); diff --git a/evaluator/nixjit_context/src/lib.rs b/evaluator/nixjit_context/src/lib.rs index a9bb79e..91b2afb 100644 --- a/evaluator/nixjit_context/src/lib.rs +++ b/evaluator/nixjit_context/src/lib.rs @@ -1,4 +1,4 @@ -use std::{marker::PhantomPinned, ops::Deref}; +use std::{marker::PhantomPinned, ops::{Deref, DerefMut}}; use bumpalo::{Bump, boxed::Box}; use hashbrown::HashMap; @@ -32,6 +32,12 @@ struct Pin<'bump, T> { _marker: PhantomPinned, } +impl Pin<'_, T> { + fn into_inner(self) -> T { + Box::into_inner(self.ptr) + } +} + impl Deref for Pin<'_, T> { type Target = T; fn deref(&self) -> &Self::Target { @@ -39,6 +45,12 @@ impl Deref for Pin<'_, T> { } } +impl DerefMut for Pin<'_, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.ptr.as_mut() + } +} + impl<'bump, T> Pin<'bump, T> { fn new_in(x: T, bump: &'bump Bump) -> Self { Self { diff --git a/evaluator/nixjit_context/src/resolve.rs b/evaluator/nixjit_context/src/resolve.rs index 3e107a2..0fce511 100644 --- a/evaluator/nixjit_context/src/resolve.rs +++ b/evaluator/nixjit_context/src/resolve.rs @@ -1,7 +1,5 @@ use std::cell::RefCell; -use std::pin::Pin; -use bumpalo::boxed::Box; use derive_more::Unwrap; use hashbrown::HashMap; @@ -11,7 +9,7 @@ use nixjit_ir::{Const, ExprId, Param, StackIdx}; use nixjit_lir::{Lir, LookupResult, Resolve, ResolveContext}; use replace_with::replace_with_and_return; -use super::Context; +use super::{Context, Pin}; #[derive(Clone)] enum Scope<'ctx> { @@ -20,7 +18,7 @@ enum Scope<'ctx> { /// A function argument scope. `Some` holds the name of the argument set if present. Arg(Option), Builtins(&'ctx HashMap<&'static str, ExprId>), - Repl(&'ctx HashMap) + Repl(&'ctx HashMap), } /// Represents an expression at different stages of compilation. @@ -44,7 +42,7 @@ impl Ir { pub struct ResolveCtx<'ctx, 'bump> { ctx: &'ctx mut Context<'bump>, - irs: Vec>>>, + irs: Vec>>, scopes: Vec>, has_with: bool, with_used: bool, @@ -58,15 +56,14 @@ impl<'ctx, 'bump> ResolveCtx<'ctx, 'bump> { Self { scopes: vec![ Scope::Builtins(&ctx.global_scope), - Scope::Repl(&ctx.repl_scope) + Scope::Repl(&ctx.repl_scope), ], has_with: false, with_used: false, irs: core::mem::take(&mut ctx.hirs) .into_iter() .map(|hir| Ir::Hir(hir).into()) - .map(|ir| Box::new_in(ir, ctx.bump)) - .map(Pin::new) + .map(|ir| Pin::new_in(ir, ctx.bump)) .collect(), ctx: ctx_mut, closures: Vec::new(), @@ -105,10 +102,10 @@ impl<'ctx, 'bump> ResolveCtx<'ctx, 'bump> { } fn new_lir(&mut self, lir: Lir) -> ExprId { - self.irs.push(Pin::new(Box::new_in( + self.irs.push(Pin::new_in( RefCell::new(Ir::Lir(lir)), self.ctx.bump, - ))); + )); unsafe { ExprId::from_raw(self.ctx.lirs.len() + self.irs.len() - 1) } } } @@ -144,6 +141,10 @@ impl ResolveContext for ResolveCtx<'_, '_> { result } + fn resolve_call(&mut self, func: ExprId, arg: ExprId) -> Result<()> { + todo!() + } + fn resolve_root(mut self, expr: ExprId) -> Result<()> { self.closures.push((expr, None, 0)); let ret = self.resolve(expr); @@ -151,11 +152,10 @@ impl ResolveContext for ResolveCtx<'_, '_> { self.ctx.lirs.extend( self.irs .into_iter() - .map(|pin| unsafe { core::mem::transmute::, Box<_>>(pin) }) - .map(Box::into_inner) + .map(Pin::into_inner) .map(RefCell::into_inner) .map(Ir::unwrap_lir) - .map(|lir| crate::Pin::new_in(lir, self.ctx.bump)) + .map(|lir| crate::Pin::new_in(lir, self.ctx.bump)), ); } ret @@ -215,7 +215,9 @@ impl ResolveContext for ResolveCtx<'_, '_> { } fn lookup_arg(&mut self) -> StackIdx { - let Some((func, Some(arg), count)) = unsafe { &mut *(self as *mut Self) }.closures.last_mut() else { + let Some((func, Some(arg), count)) = + unsafe { &mut *(self as *mut Self) }.closures.last_mut() + else { unreachable!() }; self.add_dep(*func, *arg, count) @@ -246,7 +248,7 @@ impl ResolveContext for ResolveCtx<'_, '_> { (core::mem::replace(&mut self.with_used, with_used), res) } - fn with_param_env( + fn with_closure_env( &mut self, func: ExprId, ident: Option, diff --git a/evaluator/nixjit_eval/src/lib.rs b/evaluator/nixjit_eval/src/lib.rs index cc58082..9373dc2 100644 --- a/evaluator/nixjit_eval/src/lib.rs +++ b/evaluator/nixjit_eval/src/lib.rs @@ -24,11 +24,11 @@ mod value; pub trait EvalContext { fn eval_root(self, expr: ExprId) -> Result; - /// Evaluates an expression by its ID. fn eval(&mut self, expr: ExprId) -> Result; fn call(&mut self, func: ExprId, arg: Option, frame: StackFrame) -> Result; + /// Enters a `with` scope for the duration of a closure's execution. fn with_with_env( &mut self, @@ -83,9 +83,15 @@ impl Evaluate for lir::Lir { Str(x) => x.eval(ctx), Var(x) => x.eval(ctx), Path(x) => x.eval(ctx), - &StackRef(idx) => Ok(ctx.lookup_stack(idx).clone()), + &StackRef(idx) => { + let mut val = ctx.lookup_stack(idx).clone(); + val.force(ctx)?; + Ok(val) + } &ExprRef(expr) => ctx.eval(expr), - &FuncRef(body) => Ok(Value::Closure(Closure::new(body, ctx.capture_stack().clone()).into())), + &FuncRef(body) => Ok(Value::Closure( + Closure::new(body, ctx.capture_stack().clone()).into(), + )), &Arg(_) => unreachable!(), &PrimOp(primop) => Ok(Value::PrimOp(primop)), &Thunk(id) => Ok(Value::Thunk(id)), diff --git a/evaluator/nixjit_eval/src/value/closure.rs b/evaluator/nixjit_eval/src/value/closure.rs index bafbdd7..ffa2415 100644 --- a/evaluator/nixjit_eval/src/value/closure.rs +++ b/evaluator/nixjit_eval/src/value/closure.rs @@ -18,7 +18,11 @@ pub struct Closure { } impl Closure { - pub fn call(self: Rc, arg: Option, ctx: &mut Ctx) -> Result { + pub fn call( + self: Rc, + arg: Option, + ctx: &mut Ctx, + ) -> Result { let Self { body: func, frame } = Rc::unwrap_or_clone(self); ctx.call(func, arg, frame) } diff --git a/evaluator/nixjit_lir/src/lib.rs b/evaluator/nixjit_lir/src/lib.rs index 0fe8279..809052a 100644 --- a/evaluator/nixjit_lir/src/lib.rs +++ b/evaluator/nixjit_lir/src/lib.rs @@ -71,6 +71,8 @@ pub trait ResolveContext { /// Triggers the resolution of a given expression. fn resolve(&mut self, expr: ExprId) -> Result<()>; + fn resolve_call(&mut self, func: ExprId, arg: ExprId) -> Result<()>; + fn resolve_root(self, expr: ExprId) -> Result<()>; /// Looks up a variable by name in the current scope. @@ -89,7 +91,7 @@ pub trait ResolveContext { ) -> T; /// Enters a function parameter scope for the duration of a closure. - fn with_param_env( + fn with_closure_env( &mut self, func: ExprId, ident: Option, @@ -129,7 +131,7 @@ impl Resolve for hir::Hir { ctx.resolve(x)?; Ok(Lir::Thunk(x)) } - Arg(_) => Ok(Lir::StackRef(ctx.lookup_arg())) + Arg(_) => Ok(Lir::StackRef(ctx.lookup_arg())), } } } @@ -219,17 +221,19 @@ impl Resolve for If { /// It then registers the function with the context. impl Resolve for Func { fn resolve(self, ctx: &mut Ctx) -> Result { - ctx.with_param_env(self.body, self.param.ident.clone(), |ctx| ctx.resolve(self.body))?; + ctx.with_closure_env(self.body, self.param.ident.clone(), |ctx| { + ctx.resolve(self.body) + })?; ctx.new_func(self.body, self.param); Ok(Lir::FuncRef(self.body)) } } -/// Resolves a `Call` by resolving the function and all of its arguments. impl Resolve for Call { fn resolve(self, ctx: &mut Ctx) -> Result { ctx.resolve(self.func)?; ctx.resolve(self.arg)?; + ctx.resolve_call(self.func, self.arg)?; Ok(self.to_lir()) } }