git.delta.rocks / jrsonnet / refs/commits / 0f5ef44c0f70

difftreelog

feat experimental null-coaelse operator

Yaroslav Bolyukin2023-07-26parent: #3302e38.patch.diff
in: master

6 files changed

modifiedcrates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth
24exp-object-iteration = []24exp-object-iteration = []
25# Bigint type25# Bigint type
26exp-bigint = ["num-bigint", "jrsonnet-types/exp-bigint"]26exp-bigint = ["num-bigint", "jrsonnet-types/exp-bigint"]
27# obj?.field, obj?.['field']
28exp-null-coaelse = ["jrsonnet-parser/exp-null-coaelse"]
2729
28# Improves performance, and implements some useful things using nightly-only features30# Improves performance, and implements some useful things using nightly-only features
29nightly = ["hashbrown/nightly"]31nightly = ["hashbrown/nightly"]
modifiedcrates/jrsonnet-evaluator/src/evaluate/mod.rsdiffbeforeafterboth
446 || format!("variable <{name}> access"),446 || format!("variable <{name}> access"),
447 || ctx.binding(name.clone())?.evaluate(),447 || ctx.binding(name.clone())?.evaluate(),
448 )?,448 )?,
449 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {449 Index {
450 indexable: LocExpr(v, _),
451 index,
452 #[cfg(feature = "exp-null-coaelse")]
453 null_coaelse,
454 } if matches!(&**v, Expr::Literal(LiteralType::Super)) => {
450 let name = evaluate(ctx.clone(), index)?;455 let name = evaluate(ctx.clone(), index)?;
451 let Val::Str(name) = name else {456 let Val::Str(name) = name else {
452 throw!(ValueIndexMustBeTypeGot(457 throw!(ValueIndexMustBeTypeGot(
455 name.value_type(),460 name.value_type(),
456 ))461 ))
457 };462 };
458 ctx.super_obj()463 let Some(super_obj) = ctx.super_obj() else {
464 throw!(NoSuperFound)
465 };
466 let this = ctx
459 .expect("no super found")467 .this()
468 .expect("no this found, while super present, should not happen");
460 .get_for(name.into_flat(), ctx.this().expect("no this found").clone())?469 let key = name.into_flat();
461 .expect("value not found")470 match super_obj.get_for(key.clone(), this.clone())? {
471 Some(v) => v,
472 #[cfg(feature = "exp-null-coaelse")]
473 None if *null_coaelse => Val::Null,
474 None => {
475 let suggestions = suggest_object_fields(super_obj, key.clone());
476
477 throw!(NoSuchField(key, suggestions))
478 }
479 }
462 }480 }
463 Index(value, index) => match (evaluate(ctx.clone(), value)?, evaluate(ctx, index)?) {481 Index {
482 indexable,
483 index,
484 #[cfg(feature = "exp-null-coaelse")]
485 null_coaelse,
486 } => match (evaluate(ctx.clone(), indexable)?, evaluate(ctx, index)?) {
464 (Val::Obj(v), Val::Str(key)) => State::push(487 (Val::Obj(v), Val::Str(key)) => State::push(
465 CallLocation::new(loc),488 CallLocation::new(loc),
466 || format!("field <{key}> access"),489 || format!("field <{key}> access"),
467 || match v.get(key.clone().into_flat()) {490 || match v.get(key.clone().into_flat()) {
468 Ok(Some(v)) => Ok(v),491 Ok(Some(v)) => Ok(v),
492 #[cfg(feature = "exp-null-coaelse")]
493 Ok(None) if *null_coaelse => Ok(Val::Null),
469 Ok(None) => {494 Ok(None) => {
470 let suggestions = suggest_object_fields(&v, key.clone().into_flat());495 let suggestions = suggest_object_fields(&v, key.clone().into_flat());
471496
514 ValType::Num,539 ValType::Num,
515 n.value_type(),540 n.value_type(),
516 )),541 )),
542 #[cfg(feature = "exp-null-coaelse")]
543 (Val::Null, _) if *null_coaelse => Val::Null,
517544
518 (v, _) => throw!(CantIndexInto(v.value_type())),545 (v, _) => throw!(CantIndexInto(v.value_type())),
519 },546 },
modifiedcrates/jrsonnet-evaluator/src/evaluate/operator.rsdiffbeforeafterboth
88 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}
modifiedcrates/jrsonnet-parser/Cargo.tomldiffbeforeafterboth
10[features]10[features]
11default = []11default = []
12exp-destruct = []12exp-destruct = []
13exp-null-coaelse = []
13# Implement serialization of AST using structdump14# Implement serialization of AST using structdump
14#15#
15# Structdump generates code, which exactly replicated passed AST16# Structdump generates code, which exactly replicated passed AST
modifiedcrates/jrsonnet-parser/src/expr.rsdiffbeforeafterboth
122122
123 And,123 And,
124 Or,124 Or,
125 #[cfg(feature = "exp-null-coaelse")]
126 NullCoaelse,
125127
126 // Equialent to std.objectHasEx(a, b, true)128 // Equialent to std.objectHasEx(a, b, true)
127 In,129 In,
153 And => "&&",155 And => "&&",
154 Or => "||",156 Or => "||",
155 In => "in",157 In => "in",
158 #[cfg(feature = "exp-null-coaelse")]
159 NullCoaelse => "??",
156 }160 }
157 )161 )
158 }162 }
399 ErrorStmt(LocExpr),403 ErrorStmt(LocExpr),
400 /// a(b, c)404 /// a(b, c)
401 Apply(LocExpr, ArgsDesc, bool),405 Apply(LocExpr, ArgsDesc, bool),
402 /// a[b]406 /// a[b], a.b, a?.b
403 Index(LocExpr, LocExpr),407 Index {
408 indexable: LocExpr,
409 index: LocExpr,
410 #[cfg(feature = "exp-null-coaelse")]
411 null_coaelse: bool,
412 },
404 /// function(x) x413 /// function(x) x
405 Function(ParamsDesc, LocExpr),414 Function(ParamsDesc, LocExpr),
406 /// if true == false then 1 else 2415 /// if true == false then 1 else 2
modifiedcrates/jrsonnet-parser/src/lib.rsdiffbeforeafterboth
288 rule unaryop(x: rule<()>) -> ()288 rule unaryop(x: rule<()>) -> ()
289 = quiet!{ x() } / expected!("<unary op>")289 = quiet!{ x() } / expected!("<unary op>")
290290
291291 rule ensure_null_coaelse()
292 = "" {?
293 #[cfg(not(feature = "exp-null-coaelse"))] return Err("!!!experimental null coaelscing was not enabled");
294 #[cfg(feature = "exp-null-coaelse")] Ok(())
295 }
292 use BinaryOpType::*;296 use BinaryOpType::*;
293 use UnaryOpType::*;297 use UnaryOpType::*;
294 rule expr(s: &ParserSettings) -> LocExpr298 rule expr(s: &ParserSettings) -> LocExpr
295 = precedence! {299 = precedence! {
296 start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.source.clone(), start as u32, end as u32)) }300 start:position!() v:@ end:position!() { LocExpr(Rc::new(v), ExprLocation(s.source.clone(), start as u32, end as u32)) }
297 --301 --
298 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}302 a:(@) _ binop(<"||">) _ b:@ {expr_bin!(a Or b)}
303 a:(@) _ binop(<"??">) _ ensure_null_coaelse() b:@ {
304 #[cfg(feature = "exp-null-coaelse")] return expr_bin!(a NullCoaelse b);
305 unreachable!("ensure_null_coaelse will fail if feature is not enabled")
306 }
299 --307 --
300 a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}308 a:(@) _ binop(<"&&">) _ b:@ {expr_bin!(a And b)}
301 --309 --
329 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}337 unaryop(<"~">) _ b:@ {expr_un!(BitNot b)}
330 --338 --
331 a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}339 a:(@) _ "[" _ e:slice_desc(s) _ "]" {Expr::Slice(a, e)}
332 a:(@) _ "." _ a:position!() e:id_loc(s) b:position!() {Expr::Index(a, e)}340 indexable:(@) _ null_coaelse:("?" _ ensure_null_coaelse())? "." _ index:id_loc(s) {Expr::Index{
341 indexable, index,
342 #[cfg(feature = "exp-null-coaelse")]
343 null_coaelse: null_coaelse.is_some(),
344 }}
333 a:(@) _ "[" _ e:expr(s) _ "]" {Expr::Index(a, e)}345 indexable:(@) _ null_coaelse:("?" _ "." _ ensure_null_coaelse())? "[" _ index:expr(s) _ "]" {Expr::Index{
346 indexable, index,
347 #[cfg(feature = "exp-null-coaelse")]
348 null_coaelse: null_coaelse.is_some(),
349 }}
334 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}350 a:(@) _ "(" _ args:args(s) _ ")" ts:(_ keyword("tailstrict"))? {Expr::Apply(a, args, ts.is_some())}
335 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}351 a:(@) _ "{" _ body:objinside(s) _ "}" {Expr::ObjExtend(a, body)}
336 --352 --