refactor: reduce coupling
This commit is contained in:
16
evaluator/nixjit_lir/Cargo.toml
Normal file
16
evaluator/nixjit_lir/Cargo.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "nixjit_lir"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
derive_more = { version = "2.0", features = ["full"] }
|
||||
hashbrown = "0.15"
|
||||
itertools = "0.14"
|
||||
rnix = "0.12"
|
||||
|
||||
nixjit_error = { path = "../nixjit_error" }
|
||||
nixjit_ir = { path = "../nixjit_ir" }
|
||||
nixjit_hir = { path = "../nixjit_hir" }
|
||||
nixjit_macros = { path = "../nixjit_macros" }
|
||||
nixjit_value = { path = "../nixjit_value" }
|
||||
244
evaluator/nixjit_lir/src/lib.rs
Normal file
244
evaluator/nixjit_lir/src/lib.rs
Normal file
@@ -0,0 +1,244 @@
|
||||
use derive_more::{IsVariant, TryUnwrap, Unwrap};
|
||||
|
||||
use nixjit_error::{Error, Result};
|
||||
use nixjit_hir as hir;
|
||||
use nixjit_ir::*;
|
||||
use nixjit_macros::ir;
|
||||
use nixjit_value::format_symbol;
|
||||
|
||||
ir! {
|
||||
Lir,
|
||||
|
||||
AttrSet,
|
||||
List,
|
||||
HasAttr,
|
||||
BinOp,
|
||||
UnOp,
|
||||
Select,
|
||||
If,
|
||||
Call,
|
||||
With,
|
||||
Assert,
|
||||
ConcatStrings,
|
||||
Const,
|
||||
Str,
|
||||
Var,
|
||||
Path,
|
||||
ExprRef(ExprId),
|
||||
FuncRef(ExprId),
|
||||
ArgRef(ArgIdx),
|
||||
}
|
||||
|
||||
pub enum LookupResult {
|
||||
Expr(ExprId),
|
||||
Arg(ArgIdx),
|
||||
Unknown,
|
||||
NotFound,
|
||||
}
|
||||
|
||||
pub trait ResolveContext {
|
||||
fn new_dep(&mut self, expr: ExprId, dep: ExprId);
|
||||
fn new_func(&mut self, body: ExprId, param: Param);
|
||||
fn resolve(&mut self, expr: ExprId) -> Result<()>;
|
||||
fn lookup(&self, name: &str) -> LookupResult;
|
||||
fn with_with_env<T>(&mut self, f: impl FnOnce(&mut Self) -> T) -> (bool, T);
|
||||
fn with_let_env<'a, T>(
|
||||
&mut self,
|
||||
bindings: impl IntoIterator<Item = (&'a String, &'a ExprId)>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
fn with_param_env<'a, T>(
|
||||
&mut self,
|
||||
ident: Option<&'a str>,
|
||||
f: impl FnOnce(&mut Self) -> T,
|
||||
) -> T;
|
||||
}
|
||||
|
||||
pub trait Resolve<Ctx: ResolveContext> {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir>;
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Hir {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
use hir::Hir::*;
|
||||
match self {
|
||||
AttrSet(x) => x.resolve(ctx),
|
||||
List(x) => x.resolve(ctx),
|
||||
HasAttr(x) => x.resolve(ctx),
|
||||
BinOp(x) => x.resolve(ctx),
|
||||
UnOp(x) => x.resolve(ctx),
|
||||
Select(x) => x.resolve(ctx),
|
||||
If(x) => x.resolve(ctx),
|
||||
Func(x) => x.resolve(ctx),
|
||||
Call(x) => x.resolve(ctx),
|
||||
With(x) => x.resolve(ctx),
|
||||
Assert(x) => x.resolve(ctx),
|
||||
ConcatStrings(x) => x.resolve(ctx),
|
||||
Const(x) => Ok(Lir::Const(x)),
|
||||
Str(x) => Ok(Lir::Str(x)),
|
||||
Var(x) => x.resolve(ctx),
|
||||
Path(x) => x.resolve(ctx),
|
||||
Let(x) => x.resolve(ctx),
|
||||
Arg(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for AttrSet {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
if self.rec {
|
||||
todo!()
|
||||
} 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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for List {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for &item in self.items.iter() {
|
||||
ctx.resolve(item)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for HasAttr {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.lhs)?;
|
||||
for attr in self.rhs.iter() {
|
||||
if let &Attr::Dynamic(expr) = attr {
|
||||
ctx.resolve(expr)?;
|
||||
}
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for BinOp {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.lhs)?;
|
||||
ctx.resolve(self.rhs)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for UnOp {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.rhs)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Select {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.expr)?;
|
||||
for attr in self.attrpath.iter() {
|
||||
if let &Attr::Dynamic(expr) = attr {
|
||||
ctx.resolve(expr)?;
|
||||
}
|
||||
}
|
||||
if let Some(expr) = self.default {
|
||||
ctx.resolve(expr)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for If {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.cond)?;
|
||||
ctx.resolve(self.consq)?;
|
||||
ctx.resolve(self.alter)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Func {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_param_env(self.param.ident.as_deref(), |ctx| ctx.resolve(self.body))?;
|
||||
ctx.new_func(self.body, self.param);
|
||||
Ok(Lir::FuncRef(self.body))
|
||||
}
|
||||
}
|
||||
|
||||
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)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for With {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.namespace)?;
|
||||
let (env_used, res) = ctx.with_with_env(|ctx| ctx.resolve(self.expr));
|
||||
res?;
|
||||
if env_used {
|
||||
Ok(self.to_lir())
|
||||
} else {
|
||||
Ok(Lir::ExprRef(self.expr))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Assert {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.assertion)?;
|
||||
ctx.resolve(self.expr)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for ConcatStrings {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
for &part in self.parts.iter() {
|
||||
ctx.resolve(part)?;
|
||||
}
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Var {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
use LookupResult::*;
|
||||
match ctx.lookup(&self.sym) {
|
||||
Expr(expr) => Ok(Lir::ExprRef(expr)),
|
||||
Arg(arg) => Ok(Lir::ArgRef(arg)),
|
||||
Unknown => Ok(self.to_lir()),
|
||||
NotFound => Err(Error::ResolutionError(format!(
|
||||
"undefined variable '{}'",
|
||||
format_symbol(&self.sym)
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for Path {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.resolve(self.expr)?;
|
||||
Ok(self.to_lir())
|
||||
}
|
||||
}
|
||||
|
||||
impl<Ctx: ResolveContext> Resolve<Ctx> for hir::Let {
|
||||
fn resolve(self, ctx: &mut Ctx) -> Result<Lir> {
|
||||
ctx.with_let_env(self.bindings.iter(), |ctx| {
|
||||
for &id in self.bindings.values() {
|
||||
ctx.resolve(id)?;
|
||||
}
|
||||
ctx.resolve(self.body)
|
||||
})?;
|
||||
Ok(Lir::ExprRef(self.body))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user