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,308 @@
use std::rc::Rc;
use hashbrown::HashMap;
use nixjit_error::{Error, Result};
use nixjit_ir::{self as ir, ExprId};
use nixjit_lir as lir;
use nixjit_value::{Const, Symbol};
pub use crate::value::*;
mod value;
pub trait EvalContext: Sized {
fn eval(&mut self, expr: ExprId) -> Result<Value<Self>>;
fn with_with_env<T>(
&mut self,
namespace: Rc<HashMap<String, Value<Self>>>,
f: impl FnOnce(&mut Self) -> T,
) -> T;
fn with_args_env<T>(
&mut self,
args: Vec<Value<Self>>,
f: impl FnOnce(&mut Self) -> T,
) -> (Vec<Value<Self>>, T);
fn lookup_with<'a>(&'a self, ident: &str) -> Option<&'a Value<Self>>;
fn pop_frame(&mut self) -> Vec<Value<Self>>;
}
pub trait Evaluate<Ctx: EvalContext> {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>>;
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ExprId {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
ctx.eval(*self)
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for lir::Lir {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
todo!()
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::AttrSet {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
let mut attrs = AttrSet::new(
self.stcs
.iter()
.map(|(k, v)| {
let eval_result = v.eval(ctx);
Ok((k.clone(), eval_result?))
})
.collect::<Result<_>>()?,
);
for (k, v) in self.dyns.iter() {
let mut k = k.eval(ctx)?;
k.coerce_to_string();
let v_eval_result = v.eval(ctx)?;
attrs.push_attr(k.unwrap_string(), v_eval_result);
}
let result = Value::AttrSet(attrs.into()).ok();
Ok(result.unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::List {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
let items = self
.items
.iter()
.map(|val| val.eval(ctx))
.collect::<Result<Vec<_>>>()?;
let result = Value::List(List::from(items).into()).ok();
Ok(result.unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::HasAttr {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
use ir::Attr::*;
let mut val = self.lhs.eval(ctx)?;
val.has_attr(self.rhs.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Dynamic(expr) => {
let mut val = expr.eval(ctx)?;
val.coerce_to_string();
val.unwrap_string()
}
})
}))?;
let result = val.ok();
Ok(result.unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::BinOp {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
use ir::BinOpKind::*;
let mut lhs = self.lhs.eval(ctx)?;
let mut rhs = self.rhs.eval(ctx)?;
match self.kind {
Add => lhs.add(rhs),
Sub => {
rhs.neg();
lhs.add(rhs);
}
Mul => lhs.mul(rhs),
Div => lhs.div(rhs)?,
Eq => Value::eq(&mut lhs, &rhs),
Neq => {
Value::eq(&mut lhs, &rhs);
lhs.not();
}
Lt => lhs.lt(rhs),
Gt => {
rhs.lt(lhs);
lhs = rhs;
}
Leq => {
rhs.lt(lhs);
rhs.not();
lhs = rhs;
}
Geq => {
lhs.lt(rhs);
lhs.not();
}
And => lhs.and(rhs),
Or => lhs.or(rhs),
Impl => {
lhs.not();
lhs.or(rhs);
}
Con => lhs.concat(rhs),
Upd => lhs.update(rhs),
PipeL => lhs.call(vec![rhs], ctx)?,
PipeR => {
rhs.call(vec![lhs], ctx)?;
lhs = rhs;
}
}
Ok(lhs)
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::UnOp {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
use ir::UnOpKind::*;
let mut rhs = self.rhs.eval(ctx)?;
match self.kind {
Neg => {
rhs.neg();
}
Not => {
rhs.not();
}
};
Ok(rhs)
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Select {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
use ir::Attr::*;
let mut val = self.expr.eval(ctx)?;
if let Some(default) = &self.default {
let default = default.eval(ctx)?;
val.select_with_default(
self.attrpath.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Dynamic(expr) => {
let mut val = expr.eval(ctx)?;
val.coerce_to_string();
val.unwrap_string()
}
})
}),
default,
)?;
} else {
val.select(self.attrpath.iter().map(|attr| {
Ok(match attr {
Str(ident) => ident.clone(),
Dynamic(expr) => {
let mut val = expr.eval(ctx)?;
val.coerce_to_string();
val.unwrap_string()
}
})
}))?;
}
let result = val.ok();
Ok(result.unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::If {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
// TODO: Error Handling
let cond = self.cond.eval(ctx)?;
let cond = cond
.try_unwrap_bool()
.map_err(|_| Error::EvalError(format!("expected a boolean but found ...")))?;
if cond {
self.consq.eval(ctx)
} else {
self.alter.eval(ctx)
}
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Call {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
let mut func = self.func.eval(ctx)?;
func.call(
self.args
.iter()
.map(|arg| arg.eval(ctx))
.collect::<Result<_>>()?,
ctx,
)?;
Ok(func.ok().unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::With {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
let namespace = self.namespace.eval(ctx)?;
ctx.with_with_env(
namespace
.try_unwrap_attr_set()
.map_err(|_| Error::EvalError(format!("expected a set but found ...")))?
.into_inner(),
|ctx| self.expr.eval(ctx),
)
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Assert {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
todo!()
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::ConcatStrings {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
let mut parts = self
.parts
.iter()
.map(|part| {
let mut part = part.eval(ctx)?;
part.coerce_to_string();
part.ok()
})
.collect::<Result<Vec<_>>>()?
.into_iter();
let init = parts.next().unwrap();
let result = parts.fold(init, |mut a, b| {
a.concat_string(b);
a
});
Ok(result.ok().unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Str {
fn eval(&self, _: &mut Ctx) -> Result<Value<Ctx>> {
let result = Value::String(self.val.clone()).ok();
Ok(result.unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Const {
fn eval(&self, _: &mut Ctx) -> Result<Value<Ctx>> {
let result = match self.val {
Const::Null => Value::Null,
Const::Int(x) => Value::Int(x),
Const::Float(x) => Value::Float(x),
Const::Bool(x) => Value::Bool(x),
}
.ok();
Ok(result.unwrap())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Var {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
ctx.lookup_with(&self.sym)
.ok_or_else(|| {
Error::EvalError(format!(
"variable {} not found",
Symbol::from(self.sym.clone())
))
})
.map(|val| val.clone())
}
}
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Path {
fn eval(&self, ctx: &mut Ctx) -> Result<Value<Ctx>> {
todo!()
}
}