git.delta.rocks / jrsonnet / refs/commits / f44bc09e725c

difftreelog

docs cleanup evaluator's docs

progrm_jarvis2020-08-07parent: #e9a9036.patch.diff
in: master

7 files changed

modifiedcrates/jrsonnet-evaluator/src/builtin/stdlib.rsdiffbeforeafterboth
2use std::{path::PathBuf, rc::Rc};2use std::{path::PathBuf, rc::Rc};
33
4thread_local! {4thread_local! {
5 /// To avoid parsing again when issued from same thread5 /// To avoid parsing again when issued from the same thread
6 #[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")]
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
545 }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 here
550 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 = loc
605 .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 = loc
618 .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();
modifiedcrates/jrsonnet-evaluator/src/function.rsdiffbeforeafterboth
7const 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";
99
10/// 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/// ## Parameters
12/// * `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' definition
15/// * `args` passed function arguments16/// * `args`: passed function arguments
16/// * `tailstruct` if true - function arguments is eager executed, otherwise - lazy17/// * `tailstrict`: if set to `true` function arguments are eagerly executed, otherwise - lazily
17pub 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>,
modifiedcrates/jrsonnet-evaluator/src/import.rsdiffbeforeafterboth
99
10/// 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 correspond
13 /// `(/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>>;
16
16 /// 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>>;
19
18 /// # Safety20 /// # Safety
19 ///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 bindings
22 /// 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}
2527
35 }38 }
39
36 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 paths
47#[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 {
8185
82type ResolutionData = (PathBuf, PathBuf);86type ResolutionData = (PathBuf, PathBuf);
8387
84/// Caches results of underlying resolver implementation88/// Caches results of the underlying resolver
85pub 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>>>>,
modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
56}56}
5757
58pub struct EvaluationSettings {58pub struct EvaluationSettings {
59 /// Limits recursion by limiting stack frames59 /// Limits recursion by limiting the number of stack frames
60 pub max_stack: usize,60 pub max_stack: usize,
61 /// Limit amount of stack trace items preserved61 /// Limits amount of stack trace items preserved
62 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.native
66 pub ext_natives: HashMap<Rc<str>, Rc<NativeCallback>>,66 pub ext_natives: HashMap<Rc<str>, Rc<NativeCallback>>,
9696
97#[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 unwind
100 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 stacktraces
102 /// printing stacktraces
103 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}
119118
120thread_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>);
143142
144impl EvaluationState {143impl EvaluationState {
145 /// Parses and adds file to loaded144 /// Parses and adds files as loaded
146 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 }
266265
267 /// Executes code, creating new stack frame266 /// Executes code creating a new stack frame
268 pub fn push<T>(267 pub fn push<T>(
269 &self,268 &self,
270 e: &ExprLocation,269 e: &ExprLocation,
294 result293 result
295 }294 }
296295
297 /// 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 }
330329
331 /// If passed value is function - call with set TLA330 /// If passed value is function then call with set TLA
332 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}
359358
360/// Raw methods evaluates passed values, but not performs TLA execution359/// Raw methods evaluate passed values but don't perform TLA execution
361impl 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 snippet
369 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 expression
382 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 }
modifiedcrates/jrsonnet-evaluator/src/trace/mod.rsdiffbeforeafterboth
4pub use location::*;4pub use location::*;
5use std::path::PathBuf;5use std::path::PathBuf;
66
7/// How paths should be displayed7/// The way paths should be displayed
8pub enum PathResolver {8pub enum PathResolver {
9 /// Only filename will be shown9 /// Only filename
10 FileName,10 FileName,
11 /// Absolute path of file11 /// Absolute path
12 Absolute,12 Absolute,
13 /// Relative path from base directory13 /// Path relative to base directory
14 Relative(PathBuf),14 Relative(PathBuf),
15}15}
1616
32 }32 }
33}33}
3434
35/// Implements trace to string pretty-printing35/// Implements pretty-printing of traces
36pub trait TraceFormat {36pub trait TraceFormat {
37 fn write_trace(37 fn write_trace(
38 &self,38 &self,
73 Ok(())73 Ok(())
74}74}
7575
76/// vanilla jsonnet like formatting76/// vanilla-like jsonnet formatting
77pub struct CompactFormat {77pub struct CompactFormat {
78 pub resolver: PathResolver,78 pub resolver: PathResolver,
79 pub padding: usize,79 pub padding: usize,
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
225 };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 }
381382
382 /// 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 }
394395
395 /// 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}
446447
447/// 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}
466467
467/// 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()?;