difftreelog
docs cleanup evaluator's docs
in: master
7 files changed
crates/jrsonnet-evaluator/src/builtin/stdlib.rsdiffbeforeafterboth2use std::{path::PathBuf, rc::Rc};2use std::{path::PathBuf, rc::Rc};334thread_local! {4thread_local! {5 /// To avoid parsing again when issued from same thread5 /// To avoid parsing again when issued from the same thread6 #[allow(unreachable_code)]6 #[allow(unreachable_code)]7 static PARSED_STDLIB: LocExpr = {7 static PARSED_STDLIB: LocExpr = {8 #[cfg(feature = "codegenerated-stdlib")]8 #[cfg(feature = "codegenerated-stdlib")]crates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth545 }545 }546 Val::Arr(Rc::new(out))546 Val::Arr(Rc::new(out))547 }547 }548 ArrComp(expr, compspecs) => Val::Arr(548 ArrComp(expr, comp_specs) => Val::Arr(549 // First compspec should be forspec, so no "None" possible here549 // First comp_spec should be for_spec, so no "None" possible here550 Rc::new(evaluate_comp(context, &|ctx| evaluate(ctx, expr), compspecs)?.unwrap()),550 Rc::new(evaluate_comp(context, &|ctx| evaluate(ctx, expr), comp_specs)?.unwrap()),551 ),551 ),552 Obj(body) => Val::Obj(evaluate_object(context, body)?),552 Obj(body) => Val::Obj(evaluate_object(context, body)?),553 ObjExtend(s, t) => evaluate_add_op(553 ObjExtend(s, t) => evaluate_add_op(564 || "assertion condition".to_owned(),564 || "assertion condition".to_owned(),565 || {565 || {566 evaluate(context.clone(), &value)?566 evaluate(context.clone(), &value)?567 .try_cast_bool("assertion condition should be boolean")567 .try_cast_bool("assertion condition should be of type `boolean`")568 },568 },569 )?;569 )?;570 if assertion_result {570 if assertion_result {580 || "error statement".to_owned(),580 || "error statement".to_owned(),581 || {581 || {582 throw!(RuntimeError(582 throw!(RuntimeError(583 evaluate(context, e)?.try_cast_str("error text should be string")?,583 evaluate(context, e)?.try_cast_str("error text should be of type `string`")?,584 ))584 ))585 },585 },586 )?,586 )?,590 cond_else,590 cond_else,591 } => {591 } => {592 if evaluate(context.clone(), &cond.0)?592 if evaluate(context.clone(), &cond.0)?593 .try_cast_bool("if condition should be boolean")?593 .try_cast_bool("if condition should be of type `boolean`")?594 {594 {595 evaluate(context, cond_then)?595 evaluate(context, cond_then)?596 } else {596 } else {603 Import(path) => {603 Import(path) => {604 let mut tmp = loc604 let mut tmp = loc605 .clone()605 .clone()606 .expect("imports can't be used without loc_data")606 .expect("imports cannot be used without loc_data")607 .0;607 .0;608 let import_location = Rc::make_mut(&mut tmp);608 let import_location = Rc::make_mut(&mut tmp);609 import_location.pop();609 import_location.pop();616 ImportStr(path) => {616 ImportStr(path) => {617 let mut tmp = loc617 let mut tmp = loc618 .clone()618 .clone()619 .expect("imports can't be used without loc_data")619 .expect("imports cannot be used without loc_data")620 .0;620 .0;621 let import_location = Rc::make_mut(&mut tmp);621 let import_location = Rc::make_mut(&mut tmp);622 import_location.pop();622 import_location.pop();crates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth7const NO_DEFAULT_CONTEXT: &str =7const NO_DEFAULT_CONTEXT: &str =8 "no default context set for call with defined default parameter value";8 "no default context set for call with defined default parameter value";9910/// Creates correct [context](Context) for function body evaluation, returning error on invalid call10/// Creates correct [context](Context) for function body evaluation returning error on invalid call.11///11///12/// ## Parameters12/// * `ctx` used for passed argument expressions execution, and for body execution (if `body_ctx` is not set)13/// * `ctx`: used for passed argument expressions' execution and for body execution (if `body_ctx` is not set)13/// * `body_ctx` used for default parameter values execution, and for body execution (if set)14/// * `body_ctx`: used for default parameter values' execution and for body execution (if set)14/// * `params` function parameters definition15/// * `params`: function parameters' definition15/// * `args` passed function arguments16/// * `args`: passed function arguments16/// * `tailstruct` if true - function arguments is eager executed, otherwise - lazy17/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily17pub fn parse_function_call(18pub fn parse_function_call(18 ctx: Context,19 ctx: Context,19 body_ctx: Option<Context>,20 body_ctx: Option<Context>,crates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth9910/// Implements file resolution logic for `import` and `importStr`10/// Implements file resolution logic for `import` and `importStr`11pub trait ImportResolver {11pub trait ImportResolver {12 /// Resolve real file path, i.e12 /// Resolves real file path, e.g. `(/home/user/manifests, b.libjsonnet)` can correspond13 /// `(/home/user/manifests, b.libsonnet)` can resolve to both `/home/user/manifests/b.libsonnet` and to `/home/user/vendor/b.libsonnet`13 /// both to `/home/user/manifests/b.libjsonnet` and to `/home/user/${vendor}/b.libjsonnet`14 /// (Where vendor is a library path)14 /// where `${vendor}` is a library path.15 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>>;15 fn resolve_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<PathBuf>>;1616 /// Reads file from filesystem, should be used only with path received from `resolve_file`17 /// Reads file from filesystem, should be used only with path received from `resolve_file`17 fn load_file_contents(&self, resolved: &PathBuf) -> Result<Rc<str>>;18 fn load_file_contents(&self, resolved: &PathBuf) -> Result<Rc<str>>;1918 /// # Safety20 /// # Safety19 ///21 ///20 /// For use in bindings, do not try to use it elsewhere22 /// For use only in bindings, should not be used elsewhere.21 /// Implementations, which are not intended to be23 /// Implementations which are not intended to be used in bindings22 /// used in bindings, should panic in this method24 /// should panic on call to this method.23 unsafe fn as_any(&self) -> &dyn Any;25 unsafe fn as_any(&self) -> &dyn Any;24}26}252735 }38 }3936 unsafe fn as_any(&self) -> &dyn Any {40 unsafe fn as_any(&self) -> &dyn Any {37 panic!("this resolver can't be used as any")41 panic!("`as_any($self)` is not supported by dummy resolver")38 }42 }39}43}40impl Default for Box<dyn ImportResolver> {44impl Default for Box<dyn ImportResolver> {46/// File resolver, can load file from both FS and library paths50/// File resolver, can load file from both FS and library paths47#[derive(Default)]51#[derive(Default)]48pub struct FileImportResolver {52pub struct FileImportResolver {49 /// Library directories to search for file53 /// Library directories to search for file.50 /// In original jsonnet referred as jpath54 /// Referred to as `jpath` in original jsonnet implementation.51 pub library_paths: Vec<PathBuf>,55 pub library_paths: Vec<PathBuf>,52}56}53impl ImportResolver for FileImportResolver {57impl ImportResolver for FileImportResolver {818582type ResolutionData = (PathBuf, PathBuf);86type ResolutionData = (PathBuf, PathBuf);838784/// Caches results of underlying resolver implementation88/// Caches results of the underlying resolver85pub struct CachingImportResolver {89pub struct CachingImportResolver {86 resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<PathBuf>>>>,90 resolution_cache: RefCell<HashMap<ResolutionData, Result<Rc<PathBuf>>>>,87 loading_cache: RefCell<HashMap<PathBuf, Result<Rc<str>>>>,91 loading_cache: RefCell<HashMap<PathBuf, Result<Rc<str>>>>,crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth56}56}575758pub struct EvaluationSettings {58pub struct EvaluationSettings {59 /// Limits recursion by limiting stack frames59 /// Limits recursion by limiting the number of stack frames60 pub max_stack: usize,60 pub max_stack: usize,61 /// Limit amount of stack trace items preserved61 /// Limits amount of stack trace items preserved62 pub max_trace: usize,62 pub max_trace: usize,63 /// Used for std.extVar63 /// Used for s`td.extVar`64 pub ext_vars: HashMap<Rc<str>, Val>,64 pub ext_vars: HashMap<Rc<str>, Val>,65 /// Used for ext.native65 /// Used for ext.native66 pub ext_natives: HashMap<Rc<str>, Rc<NativeCallback>>,66 pub ext_natives: HashMap<Rc<str>, Rc<NativeCallback>>,969697#[derive(Default)]97#[derive(Default)]98struct EvaluationData {98struct EvaluationData {99 /// Used for stack overflow detection, stacktrace is now populated on unwind99 /// Used for stack overflow detection, stacktrace is populated on unwind100 stack_depth: usize,100 stack_depth: usize,101 /// Contains file source codes and evaluated results for imports and pretty101 /// Contains file source codes and evaluation results for imports and pretty-printed stacktraces102 /// printing stacktraces103 files: HashMap<Rc<PathBuf>, FileData>,102 files: HashMap<Rc<PathBuf>, FileData>,104 str_files: HashMap<Rc<PathBuf>, Rc<str>>,103 str_files: HashMap<Rc<PathBuf>, Rc<str>>,105}104}118}117}119118120thread_local! {119thread_local! {121 /// Contains state for currently executing file120 /// Contains the state for a currently executed file.122 /// Global state is fine there121 /// Global state is fine here.123 pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)122 pub(crate) static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)124}123}125pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {124pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {142pub struct EvaluationState(Rc<EvaluationStateInternals>);141pub struct EvaluationState(Rc<EvaluationStateInternals>);143142144impl EvaluationState {143impl EvaluationState {145 /// Parses and adds file to loaded144 /// Parses and adds files as loaded146 pub fn add_file(&self, path: Rc<PathBuf>, source_code: Rc<str>) -> Result<()> {145 pub fn add_file(&self, path: Rc<PathBuf>, source_code: Rc<str>) -> Result<()> {147 self.add_parsed_file(146 self.add_parsed_file(148 path.clone(),147 path.clone(),264 Context::new().extend_unbound(new_bindings, None, None, None)263 Context::new().extend_unbound(new_bindings, None, None, None)265 }264 }266265267 /// Executes code, creating new stack frame266 /// Executes code creating a new stack frame268 pub fn push<T>(267 pub fn push<T>(269 &self,268 &self,270 e: &ExprLocation,269 e: &ExprLocation,294 result293 result295 }294 }296295297 /// Runs passed function in state (required, if function needs to modify stack trace)296 /// Runs passed function in state (required if function needs to modify stack trace)298 pub fn run_in_state<T>(&self, f: impl FnOnce() -> T) -> T {297 pub fn run_in_state<T>(&self, f: impl FnOnce() -> T) -> T {299 EVAL_STATE.with(|v| {298 EVAL_STATE.with(|v| {300 let has_state = v.borrow().is_some();299 let has_state = v.borrow().is_some();328 self.run_in_state(|| val.manifest_stream(&self.manifest_format()))327 self.run_in_state(|| val.manifest_stream(&self.manifest_format()))329 }328 }330329331 /// If passed value is function - call with set TLA330 /// If passed value is function then call with set TLA332 pub fn with_tla(&self, val: Val) -> Result<Val> {331 pub fn with_tla(&self, val: Val) -> Result<Val> {333 Ok(match val {332 Ok(match val {334 Val::Func(func) => func.evaluate_map(333 Val::Func(func) => func.evaluate_map(357 }356 }358}357}359358360/// Raw methods evaluates passed values, but not performs TLA execution359/// Raw methods evaluate passed values but don't perform TLA execution361impl EvaluationState {360impl EvaluationState {362 pub fn evaluate_file_raw(&self, name: &PathBuf) -> Result<Val> {361 pub fn evaluate_file_raw(&self, name: &PathBuf) -> Result<Val> {363 self.run_in_state(|| self.import_file(&std::env::current_dir().expect("cwd"), &name))362 self.run_in_state(|| self.import_file(&std::env::current_dir().expect("cwd"), &name))364 }363 }365 pub fn evaluate_file_raw_nocwd(&self, name: &PathBuf) -> Result<Val> {364 pub fn evaluate_file_raw_nocwd(&self, name: &PathBuf) -> Result<Val> {366 self.run_in_state(|| self.import_file(&PathBuf::from("."), &name))365 self.run_in_state(|| self.import_file(&PathBuf::from("."), &name))367 }366 }368 /// Parses and evaluates snippet367 /// Parses and evaluates the given snippet369 pub fn evaluate_snippet_raw(&self, source: Rc<PathBuf>, code: Rc<str>) -> Result<Val> {368 pub fn evaluate_snippet_raw(&self, source: Rc<PathBuf>, code: Rc<str>) -> Result<Val> {370 let parsed = parse(369 let parsed = parse(371 &code,370 &code,378 self.add_parsed_file(source, code, parsed.clone())?;377 self.add_parsed_file(source, code, parsed.clone())?;379 self.evaluate_expr_raw(parsed)378 self.evaluate_expr_raw(parsed)380 }379 }381 /// Evaluates parsed expression380 /// Evaluates the parsed expression382 pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result<Val> {381 pub fn evaluate_expr_raw(&self, code: LocExpr) -> Result<Val> {383 self.run_in_state(|| evaluate(self.create_default_context()?, &code))382 self.run_in_state(|| evaluate(self.create_default_context()?, &code))384 }383 }crates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth4pub use location::*;4pub use location::*;5use std::path::PathBuf;5use std::path::PathBuf;667/// How paths should be displayed7/// The way paths should be displayed8pub enum PathResolver {8pub enum PathResolver {9 /// Only filename will be shown9 /// Only filename10 FileName,10 FileName,11 /// Absolute path of file11 /// Absolute path12 Absolute,12 Absolute,13 /// Relative path from base directory13 /// Path relative to base directory14 Relative(PathBuf),14 Relative(PathBuf),15}15}161632 }32 }33}33}343435/// Implements trace to string pretty-printing35/// Implements pretty-printing of traces36pub trait TraceFormat {36pub trait TraceFormat {37 fn write_trace(37 fn write_trace(38 &self,38 &self,73 Ok(())73 Ok(())74}74}757576/// vanilla jsonnet like formatting76/// vanilla-like jsonnet formatting77pub struct CompactFormat {77pub struct CompactFormat {78 pub resolver: PathResolver,78 pub resolver: PathResolver,79 pub padding: usize,79 pub padding: usize,crates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth225 };225 };226}226}227impl Val {227impl Val {228 /// Creates Val::Num after checking for overflow. As numbers are f64, we can just check for finity228 /// Creates `Val::Num` after checking for numeric overflow.229 /// As numbers are `f64`, we can just check for their finity.229 pub fn new_checked_num(num: f64) -> Result<Val> {230 pub fn new_checked_num(num: f64) -> Result<Val> {230 if num.is_finite() {231 if num.is_finite() {231 Ok(Val::Num(num))232 Ok(Val::Num(num))379 .map(|s| s.into())380 .map(|s| s.into())380 }381 }381382382 /// Calls std.manifestJson383 /// Calls `std.manifestJson`383 #[cfg(feature = "faster")]384 #[cfg(feature = "faster")]384 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {385 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {385 manifest_json_ex(386 manifest_json_ex(392 .map(|s| s.into())393 .map(|s| s.into())393 }394 }394395395 /// Calls std.manifestJson396 /// Calls `std.manifestJson`396 #[cfg(not(feature = "faster"))]397 #[cfg(not(feature = "faster"))]397 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {398 pub fn to_std_json(&self, padding: usize) -> Result<Rc<str>> {398 with_state(|s| {399 with_state(|s| {444 matches!(val, Val::Func(_))445 matches!(val, Val::Func(_))445}446}446447447/// Implements std.primitiveEquals builtin448/// Native implementation of `std.primitiveEquals`448pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {449pub fn primitive_equals(val_a: &Val, val_b: &Val) -> Result<bool> {449 Ok(match (val_a.unwrap_if_lazy()?, val_b.unwrap_if_lazy()?) {450 Ok(match (val_a.unwrap_if_lazy()?, val_b.unwrap_if_lazy()?) {450 (Val::Bool(a), Val::Bool(b)) => a == b,451 (Val::Bool(a), Val::Bool(b)) => a == b,464 })465 })465}466}466467467/// Native implementation of std.equals468/// Native implementation of `std.equals`468pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {469pub fn equals(val_a: &Val, val_b: &Val) -> Result<bool> {469 let val_a = val_a.unwrap_if_lazy()?;470 let val_a = val_a.unwrap_if_lazy()?;470 let val_b = val_b.unwrap_if_lazy()?;471 let val_b = val_b.unwrap_if_lazy()?;