difftreelog
refactor trivial arrays
in: master
5 files changed
crates/jrsonnet-evaluator/src/analyze.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/analyze.rs
+++ b/crates/jrsonnet-evaluator/src/analyze.rs
@@ -138,14 +138,12 @@
#[derive(Debug, Acyclic)]
pub enum LExpr {
Slot(LSlot),
- Null,
- Bool(bool),
- Str(IStr),
- Num(NumValue),
+ Trivial(TrivialVal),
Arr {
shape: ClosureShape,
items: Rc<Vec<LExpr>>,
},
+ ArrConst(Rc<Vec<TrivialVal>>),
ArrComp(Box<LArrComp>),
Obj(LObjBody),
ObjExtend(Box<LExpr>, LObjBody),
@@ -1345,15 +1343,15 @@
#[allow(clippy::too_many_lines)]
pub fn analyze(expr: &Expr, stack: &mut AnalysisStack, taint: &mut AnalysisResult) -> LExpr {
match expr {
- Expr::Literal(span, l) => match l {
- LiteralType::This => stack.use_this(taint).map_or_else(
+ Expr::Identity(span, l) => match l {
+ IdentityKind::This => stack.use_this(taint).map_or_else(
|| {
stack.report_error("`self` used outside of object", Some(span.clone()));
LExpr::BadLocal("self")
},
LExpr::Slot,
),
- LiteralType::Super => {
+ IdentityKind::Super => {
if stack.use_super(taint).is_some() {
LExpr::Super
} else {
@@ -1361,25 +1359,34 @@
LExpr::BadLocal("super")
}
}
- LiteralType::Dollar => stack.use_dollar(taint).map_or_else(
+ IdentityKind::Dollar => stack.use_dollar(taint).map_or_else(
|| {
stack.report_error("`$` used outside of object", Some(span.clone()));
LExpr::BadLocal("$")
},
LExpr::Slot,
),
- LiteralType::Null => LExpr::Null,
- LiteralType::True => LExpr::Bool(true),
- LiteralType::False => LExpr::Bool(false),
},
- Expr::Str(s) => LExpr::Str(s.clone()),
- Expr::Num(n) => LExpr::Num(*n),
+ Expr::Trivial(tv) => LExpr::Trivial(tv.clone()),
Expr::Var(v) => stack
.use_local(&v.value, v.span.clone(), taint)
.map_or_else(|| LExpr::BadLocal("ref"), LExpr::Slot),
Expr::Arr(a) => {
- let (shape, items) = stack
- .in_using_closure(|stack| a.iter().map(|v| analyze(v, stack, taint)).collect());
+ if a.iter().all(|i| matches!(i, Expr::Trivial(_))) {
+ let trivials: Vec<_> = a
+ .iter()
+ .map(|i| match i {
+ Expr::Trivial(tv) => tv.clone(),
+ _ => unreachable!("checked above"),
+ })
+ .collect();
+ return LExpr::ArrConst(Rc::new(trivials));
+ }
+ let (shape, items) = stack.in_using_closure(|stack| {
+ a.iter()
+ .map(|v| analyze(v, stack, taint))
+ .collect::<Vec<_>>()
+ });
LExpr::Arr {
shape,
items: Rc::new(items),
@@ -1412,7 +1419,7 @@
}
Expr::LocalExpr(binds, body) => analyze_local_expr(binds, body, stack, taint),
Expr::Import(kind, path_expr) => {
- let Expr::Str(path) = &**path_expr else {
+ let Expr::Trivial(TrivialVal::Str(path)) = &**path_expr else {
stack.report_error(
"import path must be a string literal",
Some(kind.span.clone()),
crates/jrsonnet-evaluator/src/arr/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/mod.rs
+++ b/crates/jrsonnet-evaluator/src/arr/mod.rs
@@ -8,12 +8,7 @@
use jrsonnet_gcmodule::{Cc, cc_dyn};
-use crate::{
- Context, Result, Thunk, Val,
- analyze::{ClosureShape, LExpr},
- function::NativeFn,
- typed::IntoUntyped,
-};
+use crate::{Context, Result, Thunk, Val, analyze::LExpr, function::NativeFn, typed::IntoUntyped};
mod spec;
pub use spec::{ArrayLike, *};
@@ -42,8 +37,8 @@
Self::new(())
}
- pub fn expr(ctx: Context, shape: &ClosureShape, exprs: Rc<Vec<LExpr>>) -> Self {
- Self::new(ExprArray::new(ctx, shape, exprs))
+ pub fn expr(ctx: Context, exprs: Rc<Vec<LExpr>>) -> Self {
+ Self::new(ExprArray::new(ctx, exprs))
}
pub fn repeated(data: Self, repeats: u32) -> Option<Self> {
crates/jrsonnet-evaluator/src/arr/spec.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/arr/spec.rs
+++ b/crates/jrsonnet-evaluator/src/arr/spec.rs
@@ -8,11 +8,12 @@
use jrsonnet_gcmodule::{Cc, Trace};
use jrsonnet_interner::{IBytes, IStr};
+use jrsonnet_ir::TrivialVal;
use super::{ArrValue, arridx};
use crate::{
Context, Error, ObjValue, Result, Thunk, Val,
- analyze::{ClosureShape, LExpr},
+ analyze::LExpr,
error::ErrorKind::InfiniteRecursionDetected,
evaluate::evaluate,
function::NativeFn,
@@ -108,6 +109,18 @@
}
}
+impl ArrayCheap for Rc<Vec<TrivialVal>> {
+ fn get(&self, index: u32) -> Option<Val> {
+ self.as_slice()
+ .get(index as usize)
+ .map(|tv| tv.clone().into())
+ }
+
+ fn len(&self) -> u32 {
+ arridx(self.as_slice().len())
+ }
+}
+
#[derive(Debug, Trace, Clone)]
enum ArrayThunk {
Computed(Val),
@@ -123,9 +136,9 @@
cached: Cc<RefCell<Vec<ArrayThunk>>>,
}
impl ExprArray {
- pub fn new(outer: Context, shape: &ClosureShape, src: Rc<Vec<LExpr>>) -> Self {
+ pub fn new(ctx: Context, src: Rc<Vec<LExpr>>) -> Self {
Self {
- ctx: Context::enter_using(&outer, shape),
+ ctx,
cached: Cc::new(RefCell::new(vec![ArrayThunk::Waiting; src.len()])),
src,
}
@@ -153,9 +166,17 @@
unreachable!()
};
- let new_value: Val = evaluate(self.ctx.clone(), &self.src[index as usize])?;
- self.cached.borrow_mut()[index as usize] = ArrayThunk::Computed(new_value.clone());
- Ok(Some(new_value))
+ let result = evaluate(self.ctx.clone(), &self.src[index as usize]);
+ match result {
+ Ok(new_value) => {
+ self.cached.borrow_mut()[index as usize] = ArrayThunk::Computed(new_value.clone());
+ Ok(Some(new_value))
+ }
+ Err(e) => {
+ self.cached.borrow_mut()[index as usize] = ArrayThunk::Waiting;
+ Err(e)
+ }
+ }
}
fn get_lazy32(&self, index: u32) -> Option<Thunk<Val>> {
#[derive(Trace)]
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -52,15 +52,11 @@
}
pub fn evaluate_trivial(expr: &LExpr) -> Option<Val> {
- // TODO: Eager trivial array
- Some(match expr {
- LExpr::Str(s) => Val::string(s.clone()),
- LExpr::Num(n) => Val::Num(*n),
- LExpr::Bool(false) => Val::Bool(false),
- LExpr::Bool(true) => Val::Bool(true),
- LExpr::Null => Val::Null,
- _ => return None,
- })
+ if let LExpr::Trivial(tv) = expr {
+ Some(tv.clone().into())
+ } else {
+ None
+ }
}
pub fn evaluate_method(ctx: Context, name: IStr, func: &Rc<LFunction>) -> Val {
@@ -119,13 +115,24 @@
pub fn evaluate(mut ctx: Context, mut expr: &LExpr) -> Result<Val> {
loop {
return Ok(match expr {
- LExpr::Null => Val::Null,
- LExpr::Bool(b) => Val::Bool(*b),
- LExpr::Str(s) => Val::string(s.clone()),
- LExpr::Num(n) => Val::Num(*n),
+ LExpr::Trivial(tv) => tv.clone().into(),
LExpr::Slot(slot) => ctx.slot(*slot).evaluate()?,
LExpr::BadLocal(name) => panic!("unresolvable reference: {name}"),
- LExpr::Arr { shape, items } => Val::Arr(ArrValue::expr(ctx, shape, items.clone())),
+ LExpr::ArrConst(rc) => Val::Arr(ArrValue::new(rc.clone())),
+ LExpr::Arr { shape, items } => {
+ let inner = Context::enter_using(&ctx, shape);
+ 'eager: {
+ let mut out: Vec<Val> = Vec::with_capacity(items.len());
+ for item in items.iter() {
+ let Ok(r) = evaluate(inner.clone(), item) else {
+ break 'eager;
+ };
+ out.push(r);
+ }
+ return Ok(Val::Arr(ArrValue::new(out)));
+ }
+ Val::Arr(ArrValue::expr(inner, items.clone()))
+ }
LExpr::UnaryOp(op, value) => {
let value = evaluate(ctx, value)?;
evaluate_unary_op(*op, &value)?
crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth101011use jrsonnet_gcmodule::{Acyclic, Cc, Trace, cc_dyn};11use jrsonnet_gcmodule::{Acyclic, Cc, Trace, cc_dyn};12use jrsonnet_interner::IStr;12use jrsonnet_interner::IStr;13use jrsonnet_ir::BinaryOpType;13use jrsonnet_ir::{BinaryOpType, TrivialVal};14pub use jrsonnet_macros::Thunk;14pub use jrsonnet_macros::Thunk;15use jrsonnet_types::ValType;15use jrsonnet_types::ValType;16use rustc_hash::FxHashMap;16use rustc_hash::FxHashMap;621 Self::Bool(value)621 Self::Bool(value)622 }622 }623}623}624impl From<TrivialVal> for Val {625 fn from(tv: TrivialVal) -> Self {626 match tv {627 TrivialVal::Null => Self::Null,628 TrivialVal::Bool(b) => Self::Bool(b),629 TrivialVal::Num(n) => Self::Num(n),630 TrivialVal::Str(s) => Self::string(s),631 }632 }633}624634625const fn is_function_like(val: &Val) -> bool {635const fn is_function_like(val: &Val) -> bool {626 matches!(val, Val::Func(_))636 matches!(val, Val::Func(_))