feat: error handling

This commit is contained in:
2025-08-08 19:35:51 +08:00
parent a9cfddbf5c
commit fd182b6233
12 changed files with 187 additions and 311 deletions

View File

@@ -14,7 +14,7 @@ use hashbrown::HashMap;
use nixjit_error::{Error, Result};
use nixjit_ir::{self as ir, ArgIdx, ExprId, PrimOpId};
use nixjit_lir as lir;
use nixjit_value::{Const, Symbol, format_symbol};
use nixjit_value::{Const, format_symbol};
pub use crate::value::*;
@@ -39,6 +39,9 @@ pub trait EvalContext: Sized {
f: impl FnOnce(&mut Self) -> T,
) -> (Vec<Value>, T);
/// Looks up a stack slot on the current stack frame.
fn lookup_stack<'a>(&'a self, idx: usize) -> &'a Value;
/// Looks up an identifier in the current `with` scope chain.
fn lookup_with<'a>(&'a self, ident: &str) -> Option<&'a Value>;
@@ -107,7 +110,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::AttrSet {
);
for (k, v) in self.dyns.iter() {
let mut k = k.eval(ctx)?;
k.coerce_to_string();
k.coerce_to_string()?;
let v_eval_result = v.eval(ctx)?;
attrs.push_attr(k.unwrap_string(), v_eval_result)?;
}
@@ -135,14 +138,10 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::HasAttr {
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()
}
})
match attr {
Str(ident) => Ok(Value::String(ident.clone())),
Dynamic(expr) => expr.eval(ctx)
}
}))?;
Ok(val)
}
@@ -153,42 +152,47 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::BinOp {
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
use ir::BinOpKind::*;
let mut lhs = self.lhs.eval(ctx)?;
if matches!((&self.kind, &lhs), (And, Value::Bool(false))) {
return Ok(Value::Bool(false));
} else if matches!((&self.kind, &lhs), (Or, Value::Bool(true))) {
return Ok(Value::Bool(true))
}
let mut rhs = self.rhs.eval(ctx)?;
match self.kind {
Add => lhs.add(rhs)?,
Sub => {
rhs.neg();
rhs.neg()?;
lhs.add(rhs)?;
}
Mul => lhs.mul(rhs),
Mul => lhs.mul(rhs)?,
Div => lhs.div(rhs)?,
Eq => Value::eq(&mut lhs, &rhs),
Eq => Value::eq(&mut lhs, rhs),
Neq => {
Value::eq(&mut lhs, &rhs);
lhs.not();
Value::eq(&mut lhs, rhs);
let _ = lhs.not();
}
Lt => lhs.lt(rhs),
Lt => lhs.lt(rhs)?,
Gt => {
rhs.lt(lhs);
rhs.lt(lhs)?;
lhs = rhs;
}
Leq => {
rhs.lt(lhs);
rhs.not();
rhs.lt(lhs)?;
let _ = rhs.not();
lhs = rhs;
}
Geq => {
lhs.lt(rhs);
lhs.not();
lhs.lt(rhs)?;
let _ = lhs.not()?;
}
And => lhs.and(rhs),
Or => lhs.or(rhs),
And => lhs.and(rhs)?,
Or => lhs.or(rhs)?,
Impl => {
lhs.not();
lhs.or(rhs);
let _ = lhs.not();
lhs.or(rhs)?;
}
Con => lhs.concat(rhs),
Upd => lhs.update(rhs),
Con => lhs.concat(rhs)?,
Upd => lhs.update(rhs)?,
PipeL => lhs.call(core::iter::once(Ok(rhs)), ctx)?,
PipeR => {
rhs.call(core::iter::once(Ok(lhs)), ctx)?;
@@ -206,10 +210,10 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::UnOp {
let mut rhs = self.rhs.eval(ctx)?;
match self.kind {
Neg => {
rhs.neg();
rhs.neg()?;
}
Not => {
rhs.not();
rhs.not()?;
}
};
Ok(rhs)
@@ -230,7 +234,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Select {
Str(ident) => ident.clone(),
Dynamic(expr) => {
let mut val = expr.eval(ctx)?;
val.coerce_to_string();
val.coerce_to_string()?;
val.unwrap_string()
}
})
@@ -243,7 +247,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Select {
Str(ident) => ident.clone(),
Dynamic(expr) => {
let mut val = expr.eval(ctx)?;
val.coerce_to_string();
val.coerce_to_string()?;
val.unwrap_string()
}
})
@@ -314,7 +318,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Assert {
if cond {
self.expr.eval(ctx)
} else {
Ok(Value::Catchable("assertion failed".to_string()))
Err(Error::Catchable("assertion failed".into()))
}
}
}
@@ -323,22 +327,11 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::ConcatStrings {
/// Evaluates a `ConcatStrings` by evaluating each part, coercing it to a string,
/// and then concatenating the results.
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
let mut parts = self
.parts
.iter()
.map(|part| {
let mut part = part.eval(ctx)?;
part.coerce_to_string();
Ok(part)
})
.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)
let mut buf = String::new();
for part in self.parts.iter() {
buf.push_str(part.eval(ctx)?.coerce_to_string()?.as_ref().unwrap_string());
}
Ok(Value::String(buf))
}
}
@@ -376,7 +369,7 @@ impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Var {
impl<Ctx: EvalContext> Evaluate<Ctx> for ir::Path {
/// Evaluates a `Path`. (Currently a TODO).
fn eval(&self, ctx: &mut Ctx) -> Result<Value> {
fn eval(&self, _ctx: &mut Ctx) -> Result<Value> {
todo!()
}
}