difftreelog
refactor(evaluator) extract Apply evaluation
in: master
2 files changed
crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth5};5};6use closure::closure;6use closure::closure;7use jrsonnet_parser::{7use jrsonnet_parser::{8 AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, FieldMember, ForSpecData, IfSpecData,8 ArgsDesc, AssertStmt, BinaryOpType, BindSpec, CompSpec, Expr, ExprLocation, FieldMember,9 LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType, Visibility,9 ForSpecData, IfSpecData, LiteralType, LocExpr, Member, ObjBody, ParamsDesc, UnaryOpType,10 Visibility,10};11};376 })377 })377}378}379380/// Extracts code block and disables inlining for them381/// Fixes WASM to java bytecode compilation failing because of very large method382macro_rules! noinline {383 ($e:expr) => {384 (#[inline(never)]385 move || $e)()386 };387}388389pub fn evaluate_apply(390 context: Context,391 value: &LocExpr,392 args: &ArgsDesc,393 loc: &Option<ExprLocation>,394 tailstrict: bool,395) -> Result<Val> {396 let lazy = evaluate(context.clone(), value)?;397 let value = lazy.unwrap_if_lazy()?;398 Ok(match value {399 Val::Intristic(ns, name) => match (&ns as &str, &name as &str) {400 // arr/string/function401 ("std", "length") => noinline!(parse_args!(context, "std.length", args, 1, [402 0, x: [Val::Str|Val::Arr|Val::Obj], vec![ValType::Str, ValType::Arr, ValType::Obj];403 ], {404 Ok(match x {405 Val::Str(n) => Val::Num(n.chars().count() as f64),406 Val::Arr(i) => Val::Num(i.len() as f64),407 Val::Obj(o) => Val::Num(408 o.fields_visibility()409 .into_iter()410 .filter(|(_k, v)| *v)411 .count() as f64,412 ),413 _ => unreachable!(),414 })415 }))?,416 // any417 ("std", "type") => parse_args!(context, "std.type", args, 1, [418 0, x, vec![];419 ], {420 Val::Str(x.value_type()?.name().into())421 }),422 // length, idx=>any423 ("std", "makeArray") => noinline!(parse_args!(context, "std.makeArray", args, 2, [424 0, sz: [Val::Num]!!Val::Num, vec![ValType::Num];425 1, func: [Val::Func]!!Val::Func, vec![ValType::Func];426 ], {427 assert!(sz >= 0.0);428 let mut out = Vec::with_capacity(sz as usize);429 for i in 0..sz as usize {430 out.push(func.evaluate_values(431 Context::new(),432 &[Val::Num(i as f64)]433 )?)434 }435 Ok(Val::Arr(Rc::new(out)))436 }))?,437 // string438 ("std", "codepoint") => parse_args!(context, "std.codepoint", args, 1, [439 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];440 ], {441 assert!(442 str.chars().count() == 1,443 "std.codepoint should receive single char string"444 );445 Val::Num(str.chars().take(1).next().unwrap() as u32 as f64)446 }),447 // object, includeHidden448 ("std", "objectFieldsEx") => {449 noinline!(parse_args!(context, "std.objectFieldsEx",args, 2, [450 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];451 1, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];452 ], {453 Ok(Val::Arr(Rc::new(454 obj.fields_visibility()455 .into_iter()456 .filter(|(_k, v)| *v || inc_hidden)457 .map(|(k, _v)| Val::Str(k))458 .collect(),459 )))460 }))?461 }462 // object, field, includeHidden463 ("std", "objectHasEx") => parse_args!(context, "std.objectHasEx", args, 3, [464 0, obj: [Val::Obj]!!Val::Obj, vec![ValType::Obj];465 1, f: [Val::Str]!!Val::Str, vec![ValType::Str];466 2, inc_hidden: [Val::Bool]!!Val::Bool, vec![ValType::Bool];467 ], {468 Val::Bool(469 obj.fields_visibility()470 .into_iter()471 .filter(|(_k, v)| *v || inc_hidden)472 .any(|(k, _v)| *k == *f),473 )474 }),475 ("std", "primitiveEquals") => parse_args!(context, "std.primitiveEquals", args, 2, [476 0, a, vec![];477 1, b, vec![];478 ], {479 Val::Bool(a == b)480 }),481 ("std", "modulo") => parse_args!(context, "std.modulo", args, 2, [482 0, a: [Val::Num]!!Val::Num, vec![ValType::Num];483 1, b: [Val::Num]!!Val::Num, vec![ValType::Num];484 ], {485 Val::Num(a % b)486 }),487 ("std", "floor") => parse_args!(context, "std.floor", args, 1, [488 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];489 ], {490 Val::Num(x.floor())491 }),492 ("std", "trace") => parse_args!(context, "std.trace", args, 2, [493 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];494 1, rest, vec![];495 ], {496 // TODO: Line numbers as in original jsonnet497 println!("TRACE: {}", str);498 rest499 }),500 ("std", "pow") => parse_args!(context, "std.modulo", args, 2, [501 0, x: [Val::Num]!!Val::Num, vec![ValType::Num];502 1, n: [Val::Num]!!Val::Num, vec![ValType::Num];503 ], {504 Val::Num(x.powf(n))505 }),506 ("std", "extVar") => parse_args!(context, "std.extVar", args, 2, [507 0, x: [Val::Str]!!Val::Str, vec![ValType::Str];508 ], {509 with_state(|s| s.settings().ext_vars.get(&x).cloned()).ok_or_else(510 || create_error(crate::Error::UndefinedExternalVariable(x)),511 )?512 }),513 ("std", "filter") => noinline!(parse_args!(context, "std.filter", args, 2, [514 0, func: [Val::Func]!!Val::Func, vec![ValType::Func];515 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];516 ], {517 Ok(Val::Arr(Rc::new(518 arr.iter()519 .cloned()520 .filter(|e| {521 func522 .evaluate_values(context.clone(), &[e.clone()])523 .unwrap()524 .try_cast_bool("filter predicate")525 .unwrap()526 })527 .collect(),528 )))529 }))?,530 ("std", "char") => parse_args!(context, "std.char", args, 1, [531 0, n: [Val::Num]!!Val::Num, vec![ValType::Num];532 ], {533 let mut out = String::new();534 out.push(std::char::from_u32(n as u32).unwrap());535 Val::Str(out.into())536 }),537 ("std", "encodeUTF8") => parse_args!(context, "std.encodeUtf8", args, 1, [538 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];539 ], {540 Val::Arr(Rc::new(str.bytes().map(|b| Val::Num(b as f64)).collect()))541 }),542 ("std", "md5") => noinline!(parse_args!(context, "std.md5", args, 1, [543 0, str: [Val::Str]!!Val::Str, vec![ValType::Str];544 ], {545 Ok(Val::Str(format!("{:x}", md5::compute(&str.as_bytes())).into()))546 }))?,547 // faster548 ("std", "join") => noinline!(parse_args!(context, "std.join", args, 2, [549 0, sep: [Val::Str|Val::Arr], vec![ValType::Str, ValType::Arr];550 1, arr: [Val::Arr]!!Val::Arr, vec![ValType::Arr];551 ], {552 Ok(match sep {553 Val::Arr(joiner_items) => {554 let mut out = Vec::new();555556 let mut first = true;557 for item in arr.iter().cloned() {558 if let Val::Arr(items) = item.unwrap_if_lazy()? {559 if !first {560 out.reserve(joiner_items.len());561 out.extend(joiner_items.iter().cloned());562 }563 first = false;564 out.reserve(items.len());565 out.extend(items.iter().cloned());566 } else {567 create_error_result(crate::Error::RuntimeError("in std.join all items should be arrays".into()))?;568 }569 }570571 Val::Arr(Rc::new(out))572 },573 Val::Str(sep) => {574 let mut out = String::new();575576 let mut first = true;577 for item in arr.iter().cloned() {578 if let Val::Str(item) = item.unwrap_if_lazy()? {579 if !first {580 out += &sep;581 }582 first = false;583 out += &item;584 } else {585 create_error_result(crate::Error::RuntimeError("in std.join all items should be strings".into()))?;586 }587 }588589 Val::Str(out.into())590 },591 _ => unreachable!()592 })593 }))?,594 // Faster595 ("std", "escapeStringJson") => parse_args!(context, "std.escapeStringJson", args, 1, [596 0, str_: [Val::Str]!!Val::Str, vec![ValType::Str];597 ], {598 Val::Str(escape_string_json(&str_).into())599 }),600 // Faster601 ("std", "manifestJsonEx") => parse_args!(context, "std.manifestJsonEx", args, 2, [602 0, value, vec![];603 1, indent: [Val::Str]!!Val::Str, vec![ValType::Str];604 ], {605 Val::Str(manifest_json_ex(&value, &indent)?.into())606 }),607 (ns, name) => {608 create_error_result(crate::Error::IntristicNotFound(ns.into(), name.into()))?609 }610 },611 Val::Func(f) => {612 let body = || f.evaluate(context, args, tailstrict);613 if tailstrict {614 body()?615 } else {616 push(loc, "function call", body)?617 }618 }619 v => create_error_result(crate::Error::OnlyFunctionsCanBeCalledGot(v.value_type()?))?,620 })621}378622379pub fn evaluate(context: Context, expr: &LocExpr) -> Result<Val> {623pub fn evaluate(context: Context, expr: &LocExpr) -> Result<Val> {380 use Expr::*;624 use Expr::*;508 &evaluate(context.clone(), s)?,752 &evaluate(context.clone(), s)?,509 &Val::Obj(evaluate_object(context, t)?),753 &Val::Obj(evaluate_object(context, t)?),510 )?,754 )?,511 Apply(value, args, tailstrict) => {755 Apply(value, args, tailstrict) => evaluate_apply(context, value, args, loc, *tailstrict)?,512 let lazy = evaluate(context.clone(), value)?;513 let value = lazy.unwrap_if_lazy()?;514 match value {732 ))?,733 },734 Val::Func(f) => {735 let body = || f.evaluate(context, args, *tailstrict);736 if *tailstrict {737 body()?738 } else {739 push(loc, "function call", body)?740 }741 }742 v => {743 create_error_result(crate::Error::OnlyFunctionsCanBeCalledGot(v.value_type()?))?744 }745 }746 }747 Function(params, body) => evaluate_method(context, params.clone(), body.clone()),756 Function(params, body) => evaluate_method(context, params.clone(), body.clone()),748 AssertExpr(AssertStmt(value, msg), returned) => {757 AssertExpr(AssertStmt(value, msg), returned) => {749 let assertion_result = push(&value.1, "assertion condition", || {758 let assertion_result = push(&value.1, "assertion condition", || {crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(type_alias_impl_trait)]
#![feature(debug_non_exhaustive)]
#![feature(test)]
+#![feature(stmt_expr_attributes)]
#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]
extern crate test;