difftreelog
feat experimental null-coaelse operator
in: master
6 files changed
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -24,6 +24,8 @@
exp-object-iteration = []
# Bigint type
exp-bigint = ["num-bigint", "jrsonnet-types/exp-bigint"]
+# obj?.field, obj?.['field']
+exp-null-coaelse = ["jrsonnet-parser/exp-null-coaelse"]
# Improves performance, and implements some useful things using nightly-only features
nightly = ["hashbrown/nightly"]
crates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/evaluate/mod.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate/mod.rs
@@ -446,7 +446,12 @@
|| format!("variable <{name}> access"),
|| ctx.binding(name.clone())?.evaluate(),
)?,
- Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
+ Index {
+ indexable: LocExpr(v, _),
+ index,
+ #[cfg(feature = "exp-null-coaelse")]
+ null_coaelse,
+ } if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
let name = evaluate(ctx.clone(), index)?;
let Val::Str(name) = name else {
throw!(ValueIndexMustBeTypeGot(
@@ -455,17 +460,37 @@
name.value_type(),
))
};
- ctx.super_obj()
- .expect("no super found")
- .get_for(name.into_flat(), ctx.this().expect("no this found").clone())?
- .expect("value not found")
+ let Some(super_obj) = ctx.super_obj() else {
+ throw!(NoSuperFound)
+ };
+ let this = ctx
+ .this()
+ .expect("no this found, while super present, should not happen");
+ let key = name.into_flat();
+ match super_obj.get_for(key.clone(), this.clone())? {
+ Some(v) => v,
+ #[cfg(feature = "exp-null-coaelse")]
+ None if *null_coaelse => Val::Null,
+ None => {
+ let suggestions = suggest_object_fields(super_obj, key.clone());
+
+ throw!(NoSuchField(key, suggestions))
+ }
+ }
}
- Index(value, index) => match (evaluate(ctx.clone(), value)?, evaluate(ctx, index)?) {
+ Index {
+ indexable,
+ index,
+ #[cfg(feature = "exp-null-coaelse")]
+ null_coaelse,
+ } => match (evaluate(ctx.clone(), indexable)?, evaluate(ctx, index)?) {
(Val::Obj(v), Val::Str(key)) => State::push(
CallLocation::new(loc),
|| format!("field <{key}> access"),
|| match v.get(key.clone().into_flat()) {
Ok(Some(v)) => Ok(v),
+ #[cfg(feature = "exp-null-coaelse")]
+ Ok(None) if *null_coaelse => Ok(Val::Null),
Ok(None) => {
let suggestions = suggest_object_fields(&v, key.clone().into_flat());
@@ -514,6 +539,8 @@
ValType::Num,
n.value_type(),
)),
+ #[cfg(feature = "exp-null-coaelse")]
+ (Val::Null, _) if *null_coaelse => Val::Null,
(v, _) => throw!(CantIndexInto(v.value_type())),
},
crates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth88 Ok(match (evaluate(ctx.clone(), a)?, op, b) {88 Ok(match (evaluate(ctx.clone(), a)?, op, b) {89 (Bool(true), Or, _o) => Val::Bool(true),89 (Bool(true), Or, _o) => Val::Bool(true),90 (Bool(false), And, _o) => Val::Bool(false),90 (Bool(false), And, _o) => Val::Bool(false),91 #[cfg(feature = "exp-null-coaelse")]92 (Null, NullCoaelse, eb) => evaluate(ctx, eb)?,93 #[cfg(feature = "exp-null-coaelse")]94 (a, NullCoaelse, _o) => a,91 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(ctx, eb)?)?,95 (a, op, eb) => evaluate_binary_op_normal(&a, op, &evaluate(ctx, eb)?)?,92 })96 })93}97}crates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-parser/Cargo.toml
+++ b/crates/jrsonnet-parser/Cargo.toml
@@ -10,6 +10,7 @@
[features]
default = []
exp-destruct = []
+exp-null-coaelse = []
# Implement serialization of AST using structdump
#
# Structdump generates code, which exactly replicated passed AST
crates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/expr.rs
+++ b/crates/jrsonnet-parser/src/expr.rs
@@ -122,6 +122,8 @@
And,
Or,
+ #[cfg(feature = "exp-null-coaelse")]
+ NullCoaelse,
// Equialent to std.objectHasEx(a, b, true)
In,
@@ -153,6 +155,8 @@
And => "&&",
Or => "||",
In => "in",
+ #[cfg(feature = "exp-null-coaelse")]
+ NullCoaelse => "??",
}
)
}
@@ -399,8 +403,13 @@
ErrorStmt(LocExpr),
/// a(b, c)
Apply(LocExpr, ArgsDesc, bool),
- /// a[b]
- Index(LocExpr, LocExpr),
+ /// a[b], a.b, a?.b
+ Index {
+ indexable: LocExpr,
+ index: LocExpr,
+ #[cfg(feature = "exp-null-coaelse")]
+ null_coaelse: bool,
+ },
/// function(x) x
Function(ParamsDesc, LocExpr),
/// if true == false then 1 else 2
crates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-parser/src/lib.rs
+++ b/crates/jrsonnet-parser/src/lib.rs
@@ -288,7 +288,11 @@
rule unaryop(x: rule<()>) -> ()
= quiet!{ x() } / expected!("<unary op>")
-
+ rule ensure_null_coaelse()
+ = "" {?
+ #[cfg(not(feature = "exp-null-coaelse"))] return Err("!!!experimental null coaelscing was not enabled");
+ #[cfg(feature = "exp-null-coaelse")] Ok(())
+ }
use BinaryOpType::*;
use UnaryOpType::*;
rule expr(s: &ParserSettings) -> LocExpr
@@ -296,6 +300,10 @@
start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.source.clone(), start as u32, end as u32)) }
--
a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}
+ a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {
+ #[cfg(feature = "exp-null-coaelse")] return expr_bin!(a NullCoaelse b);
+ unreachable!("ensure_null_coaelse will fail if feature is not enabled")
+ }
--
a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}
--
@@ -329,8 +337,16 @@
unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}
--
a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}
- a:(@) _ "." _ a:position!() e:id_loc(s) b:position!() {Expr::Index(a, e)}
- a:(@) _ "[" _ e:expr(s) _ "]" {Expr::Index(a, e)}
+ indexable:(@) _ null_coaelse:("?" _ ensure_null_coaelse())? "." _ index:id_loc(s) {Expr::Index{
+ indexable, index,
+ #[cfg(feature = "exp-null-coaelse")]
+ null_coaelse: null_coaelse.is_some(),
+ }}
+ indexable:(@) _ null_coaelse:("?" _ "." _ ensure_null_coaelse())? "[" _ index:expr(s) _ "]" {Expr::Index{
+ indexable, index,
+ #[cfg(feature = "exp-null-coaelse")]
+ null_coaelse: null_coaelse.is_some(),
+ }}
a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}
a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}
--