chore: comment

This commit is contained in:
2025-08-07 21:00:32 +08:00
parent f946cb2fd1
commit 67cdcfea33
24 changed files with 734 additions and 105 deletions

View File

@@ -1,3 +1,13 @@
//! The central evaluation context for the nixjit interpreter.
//!
//! This module defines the `Context` struct, which holds all the state
//! necessary for the evaluation of a Nix expression. It manages the
//! Intermediate Representations (IRs), scopes, evaluation stack, and
//! the Just-In-Time (JIT) compiler.
//!
//! The `Context` implements various traits (`DowngradeContext`, `ResolveContext`, etc.)
//! to provide the necessary services for each stage of the compilation and
//! evaluation pipeline.
use std::cell::{OnceCell, RefCell};
use std::rc::Rc;
@@ -19,15 +29,22 @@ use nixjit_lir::{Lir, LookupResult, Resolve, ResolveContext};
use nixjit_jit::{JITCompiler, JITContext, JITFunc};
use replace_with::replace_with_and_return;
/// Represents a lexical scope during name resolution.
enum Scope {
/// A `with` expression scope.
With,
/// A `let` binding scope, mapping variable names to their expression IDs.
Let(HashMap<String, ExprId>),
/// A function argument scope. `Some` holds the name of the argument set if present.
Arg(Option<String>),
}
/// Represents an expression at different stages of compilation.
#[derive(Debug, Unwrap)]
enum Ir {
/// An expression in the High-Level Intermediate Representation (HIR).
Hir(Hir),
/// An expression in the Low-Level Intermediate Representation (LIR).
Lir(Lir),
}
@@ -81,20 +98,37 @@ impl Ir {
}
}
/// The main evaluation context.
///
/// This struct orchestrates the entire Nix expression evaluation process,
/// from parsing and semantic analysis to interpretation and JIT compilation.
pub struct Context {
/// Arena for all expressions, which can be either HIR or LIR.
/// `RefCell` is used for interior mutability to allow on-demand resolution.
irs: Vec<RefCell<Ir>>,
/// Tracks whether an `ExprId` has been resolved from HIR to LIR.
resolved: Vec<bool>,
/// The stack of lexical scopes used for name resolution.
scopes: Vec<Scope>,
/// The number of arguments in the current function call scope.
args_count: usize,
/// A table of primitive operation implementations.
primops: Vec<fn(&mut Context, Vec<Value>) -> Result<Value>>,
/// Maps a function's body `ExprId` to its parameter definition.
funcs: HashMap<ExprId, Param>,
/// A dependency graph between expressions.
graph: DiGraph<ExprId, ()>,
/// Maps an `ExprId` to its corresponding `NodeIndex` in the dependency graph.
nodes: Vec<NodeIndex>,
/// The call stack for function evaluation, where each frame holds arguments.
stack: Vec<Vec<Value>>,
/// A stack of namespaces for `with` expressions during evaluation.
with_scopes: Vec<Rc<HashMap<String, Value>>>,
/// The Just-In-Time (JIT) compiler.
jit: JITCompiler<Self>,
/// A cache for JIT-compiled functions, indexed by `ExprId`.
compiled: Vec<OnceCell<JITFunc<Self>>>,
}
@@ -111,9 +145,7 @@ impl Default for Context {
.enumerate()
.map(|(id, (k, _))| (k.to_string(), unsafe { ExprId::from(id) }))
.chain(global.iter().enumerate().map(|(idx, (k, _, _))| {
(k.to_string(), unsafe {
ExprId::from(idx + CONSTS_LEN)
})
(k.to_string(), unsafe { ExprId::from(idx + CONSTS_LEN) })
}))
.chain(core::iter::once(("builtins".to_string(), unsafe {
ExprId::from(CONSTS_LEN + GLOBAL_LEN + SCOPED_LEN)
@@ -162,10 +194,18 @@ impl Default for Context {
}
impl Context {
/// Creates a new, default `Context`.
pub fn new() -> Self {
Self::default()
}
/// The main entry point for evaluating a Nix expression string.
///
/// This function performs the following steps:
/// 1. Parses the expression string into an `rnix` AST.
/// 2. Downgrades the AST to the High-Level IR (HIR).
/// 3. Resolves the HIR to the Low-Level IR (LIR).
/// 4. Evaluates the LIR to produce a final `Value`.
pub fn eval(mut self, expr: &str) -> Result<nixjit_value::Value> {
let root = rnix::Root::parse(expr);
if !root.errors().is_empty() {
@@ -364,9 +404,7 @@ impl EvalContext for Context {
}
fn call_primop(&mut self, id: nixjit_ir::PrimOpId, args: Vec<Value>) -> Result<Value> {
unsafe {
(self.primops.get_unchecked(id.raw()))(self, args)
}
unsafe { (self.primops.get_unchecked(id.raw()))(self, args) }
}
}