git.delta.rocks / jrsonnet / refs/commits / 8dc1868a104f

difftreelog

refactor(evaluator) extract Apply evaluation

Лач2020-06-28parent: #be6bedc.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
5};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}
379
380/// Extracts code block and disables inlining for them
381/// Fixes WASM to java bytecode compilation failing because of very large method
382macro_rules! noinline {
383 ($e:expr) => {
384 (#[inline(never)]
385 move || $e)()
386 };
387}
388
389pub 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/function
401 ("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 // any
417 ("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=>any
423 ("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 // string
438 ("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, includeHidden
448 ("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, includeHidden
463 ("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 jsonnet
497 println!("TRACE: {}", str);
498 rest
499 }),
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 func
522 .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 // faster
548 ("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();
555
556 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 }
570
571 Val::Arr(Rc::new(out))
572 },
573 Val::Str(sep) => {
574 let mut out = String::new();
575
576 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 }
588
589 Val::Str(out.into())
590 },
591 _ => unreachable!()
592 })
593 }))?,
594 // Faster
595 ("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 // Faster
601 ("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}
378622
379pub 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", || {
modifiedcrates/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;