refactor: reduce coupling

This commit is contained in:
2025-07-28 21:37:27 +08:00
parent 78e3c5a26e
commit 7afb2a7b1c
53 changed files with 2964 additions and 3444 deletions

View File

@@ -0,0 +1,13 @@
[package]
name = "nixjit_ir"
description = "The core data structures for the nixjit intermediate representation (IR)."
version = "0.1.0"
edition = "2024"
[dependencies]
derive_more = { version = "2.0", features = ["full"] }
hashbrown = "0.15"
rnix = "0.12"
nixjit_error = { path = "../nixjit_error" }
nixjit_value = { path = "../nixjit_value" }

View File

@@ -0,0 +1,255 @@
//! This crate defines the core data structures for the nixjit Intermediate Representation (IR).
//!
//! The IR provides a simplified, language-agnostic representation of Nix expressions,
//! serving as a bridge between the high-level representation (HIR) and the low-level
//! representation (LIR). It defines the fundamental building blocks like expression IDs,
//! function IDs, and structures for various expression types (e.g., binary operations,
//! attribute sets, function calls).
//!
//! These structures are designed to be generic and reusable across different stages of
//! the compiler.
use rnix::ast;
use derive_more::TryUnwrap;
use hashbrown::HashMap;
use nixjit_value::Const as PubConst;
/// A type-safe wrapper for an index into an expression table.
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct ExprId(usize);
/// A type-safe wrapper for an index into a function table.
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct FuncId(usize);
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
pub struct ArgIdx(usize);
/// Represents a Nix attribute set.
#[derive(Debug, Default)]
pub struct AttrSet {
/// Statically known attributes (key is a string).
pub stcs: HashMap<String, ExprId>,
/// Dynamically computed attributes, where both the key and value are expressions.
pub dyns: Vec<(ExprId, ExprId)>,
/// `true` if this is a recursive attribute set (`rec { ... }`).
pub rec: bool,
}
/// Represents a key in an attribute path.
#[derive(Clone, Debug, TryUnwrap)]
pub enum Attr {
/// A dynamic attribute key, which is an expression that must evaluate to a string.
Dynamic(ExprId),
/// A static attribute key.
Str(String),
}
/// Represents a Nix list.
#[derive(Debug)]
pub struct List {
/// The expressions that are elements of the list.
pub items: Vec<ExprId>,
}
/// Represents a "has attribute" check (`?` operator).
#[derive(Debug)]
pub struct HasAttr {
/// The expression to check for the attribute (the left-hand side).
pub lhs: ExprId,
/// The attribute path to look for (the right-hand side).
pub rhs: Vec<Attr>,
}
/// Represents a binary operation.
#[derive(Debug)]
pub struct BinOp {
pub lhs: ExprId,
pub rhs: ExprId,
pub kind: BinOpKind,
}
/// The kinds of binary operations supported in Nix.
#[derive(Clone, Debug)]
pub enum BinOpKind {
// Arithmetic
Add,
Sub,
Div,
Mul,
// Comparison
Eq,
Neq,
Lt,
Gt,
Leq,
Geq,
// Logical
And,
Or,
Impl,
// Set/String/Path operations
Con, // List concatenation (`++`)
Upd, // AttrSet update (`//`)
// Not standard, but part of rnix AST
PipeL,
PipeR,
}
impl From<ast::BinOpKind> for BinOpKind {
fn from(op: ast::BinOpKind) -> Self {
use BinOpKind::*;
use ast::BinOpKind as kind;
match op {
kind::Concat => Con,
kind::Update => Upd,
kind::Add => Add,
kind::Sub => Sub,
kind::Mul => Mul,
kind::Div => Div,
kind::And => And,
kind::Equal => Eq,
kind::Implication => Impl,
kind::Less => Lt,
kind::LessOrEq => Leq,
kind::More => Gt,
kind::MoreOrEq => Geq,
kind::NotEqual => Neq,
kind::Or => Or,
kind::PipeLeft => PipeL,
kind::PipeRight => PipeR,
}
}
}
/// Represents a unary operation.
#[derive(Debug)]
pub struct UnOp {
pub rhs: ExprId,
pub kind: UnOpKind,
}
/// The kinds of unary operations.
#[derive(Clone, Debug)]
pub enum UnOpKind {
Neg, // Negation (`-`)
Not, // Logical not (`!`)
}
impl From<ast::UnaryOpKind> for UnOpKind {
fn from(value: ast::UnaryOpKind) -> Self {
match value {
ast::UnaryOpKind::Invert => UnOpKind::Not,
ast::UnaryOpKind::Negate => UnOpKind::Neg,
}
}
}
/// Represents an attribute selection from an attribute set.
#[derive(Debug)]
pub struct Select {
/// The expression that should evaluate to an attribute set.
pub expr: ExprId,
/// The path of attributes to select.
pub attrpath: Vec<Attr>,
/// An optional default value to return if the selection fails.
pub default: Option<ExprId>,
}
/// Represents an `if-then-else` expression.
#[derive(Debug)]
pub struct If {
pub cond: ExprId,
pub consq: ExprId, // Consequence (then branch)
pub alter: ExprId, // Alternative (else branch)
}
/// Represents a function value (a lambda).
#[derive(Debug)]
pub struct Func {
/// The body of the function
pub body: ExprId,
pub param: Param,
}
#[derive(Debug)]
pub struct Param {
pub ident: Option<String>,
pub required: Option<Vec<String>>,
pub allowed: Option<Vec<String>>,
}
/// Represents a function call.
#[derive(Debug)]
pub struct Call {
/// The expression that evaluates to the function to be called.
pub func: ExprId,
/// The list of arguments to pass to the function.
pub args: Vec<ExprId>,
}
/// Represents a `with` expression.
#[derive(Debug)]
pub struct With {
/// The namespace to bring into scope.
pub namespace: ExprId,
/// The expression to be evaluated within the new scope.
pub expr: ExprId,
}
/// Represents an `assert` expression.
#[derive(Debug)]
pub struct Assert {
/// The condition to assert.
pub assertion: ExprId,
/// The expression to return if the assertion is true.
pub expr: ExprId,
}
/// Represents the concatenation of multiple string expressions.
/// This is typically the result of downgrading an interpolated string.
#[derive(Debug)]
pub struct ConcatStrings {
pub parts: Vec<ExprId>,
}
/// Represents a constant value (e.g., integer, float, boolean, null).
#[derive(Clone, Copy, Debug)]
pub struct Const {
pub val: PubConst,
}
impl<T: Into<PubConst>> From<T> for Const {
fn from(value: T) -> Self {
Self { val: value.into() }
}
}
/// Represents a simple, non-interpolated string literal.
#[derive(Debug)]
pub struct Str {
pub val: String,
}
/// Represents a variable lookup by its name.
#[derive(Debug)]
pub struct Var {
pub sym: String,
}
/// Represents a path literal.
#[derive(Debug)]
pub struct Path {
/// The expression that evaluates to the string content of the path.
/// This can be a simple `Str` or a `ConcatStrings` for interpolated paths.
pub expr: ExprId,
}