difftreelog
refactor(evaluator) use PathBuf for file paths
in: master
4 files changed
crates/jsonnet-evaluator/build.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/build.rs
+++ b/crates/jsonnet-evaluator/build.rs
@@ -1,13 +1,18 @@
use bincode::serialize;
use jsonnet_parser::{parse, ParserSettings};
use jsonnet_stdlib::STDLIB_STR;
-use std::{env, fs::File, io::Write, path::Path};
+use std::{
+ env,
+ fs::File,
+ io::Write,
+ path::{Path, PathBuf},
+};
fn main() {
let parsed = parse(
STDLIB_STR,
&ParserSettings {
- file_name: "std.jsonnet".to_owned(),
+ file_name: PathBuf::from("std.jsonnet"),
loc_data: true,
},
)
crates/jsonnet-evaluator/src/error.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/error.rs
+++ b/crates/jsonnet-evaluator/src/error.rs
@@ -8,6 +8,7 @@
NoSuchField(String),
RuntimeError(String),
+ StackOverflow,
}
#[derive(Clone, Debug)]
crates/jsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth32 b.name.clone(),32 b.name.clone(),33 lazy_binding!(move |this, super_obj| {33 lazy_binding!(move |this, super_obj| {34 Ok(lazy_val!(34 Ok(lazy_val!(closure!(clone context_creator, clone b, ||35 push(b.value.clone(), "thunk".to_owned(), ||{35 closure!(clone context_creator, clone b, || evaluate(36 evaluate(36 context_creator.0(this.clone(), super_obj.clone())?,37 context_creator.0(this.clone(), super_obj.clone())?,37 &b.value38 &b.value38 ))39 )40 })39 ))41 )))40 }),42 }),41 )43 )326 Num(v) => Val::Num(*v),328 Num(v) => Val::Num(*v),327 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,329 BinaryOp(v1, o, v2) => evaluate_binary_op_special(context, &v1, *o, &v2)?,328 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,330 UnaryOp(o, v) => evaluate_unary_op(*o, &evaluate(context, v)?)?,329 Var(name) => Val::Lazy(context.binding(&name)).unwrap_if_lazy()?,331 Var(name) => push(locexpr, "var".to_owned(), || {332 Val::Lazy(context.binding(&name)).unwrap_if_lazy()333 })?,330 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {334 Index(LocExpr(v, _), index) if matches!(&**v, Expr::Literal(LiteralType::Super)) => {331 let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;335 let name = evaluate(context.clone(), index)?.try_cast_str("object index")?;332 context336 context412 match evaluate(context, expr)? {416 match evaluate(context, expr)? {413 Val::Str(n) => Val::Num(n.chars().count() as f64),417 Val::Str(n) => Val::Num(n.chars().count() as f64),414 Val::Arr(i) => Val::Num(i.len() as f64),418 Val::Arr(i) => Val::Num(i.len() as f64),419 Val::Obj(o) => Val::Num(o.fields().len() as f64),415 v => panic!("can't get length of {:?}", v),420 v => panic!("can't get length of {:?}", v),416 }421 }417 }422 }crates/jsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jsonnet-evaluator/src/lib.rs
+++ b/crates/jsonnet-evaluator/src/lib.rs
@@ -16,7 +16,7 @@
pub use evaluate::*;
use jsonnet_parser::*;
pub use obj::*;
-use std::{cell::RefCell, collections::HashMap, rc::Rc};
+use std::{cell::RefCell, collections::HashMap, path::PathBuf, rc::Rc};
pub use val::*;
rc_fn_helper!(
@@ -43,7 +43,7 @@
stack: RefCell<Vec<StackTraceElement>>,
/// Contains file source codes and evaluated results for imports and pretty
/// printing stacktraces
- files: RefCell<HashMap<String, FileData>>,
+ files: RefCell<HashMap<PathBuf, FileData>>,
globals: RefCell<HashMap<String, Val>>,
}
@@ -56,7 +56,7 @@
pub(crate) fn create_error<T>(err: Error) -> Result<T> {
with_state(|s| s.error(err))
}
-pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> T) -> T {
+pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
with_state(|s| s.push(e, comment, f))
}
@@ -65,7 +65,7 @@
impl EvaluationState {
pub fn add_file(
&self,
- name: String,
+ name: PathBuf,
code: String,
) -> std::result::Result<(), Box<dyn std::error::Error>> {
self.0.files.borrow_mut().insert(
@@ -87,7 +87,7 @@
}
pub fn add_parsed_file(
&self,
- name: String,
+ name: PathBuf,
code: String,
parsed: LocExpr,
) -> std::result::Result<(), Box<dyn std::error::Error>> {
@@ -98,14 +98,13 @@
Ok(())
}
- pub fn get_source(&self, name: &str) -> String {
+ pub fn get_source(&self, name: &PathBuf) -> Option<String> {
let ro_map = self.0.files.borrow();
- let value = ro_map
+ ro_map
.get(name)
- .unwrap_or_else(|| panic!("file not added: {:?}", name));
- value.0.clone()
+ .map(|value|value.0.clone())
}
- pub fn evaluate_file(&self, name: &str) -> Result<Val> {
+ pub fn evaluate_file(&self, name: &PathBuf) -> Result<Val> {
self.begin_state();
let expr: LocExpr = {
let ro_map = self.0.files.borrow();
@@ -135,7 +134,7 @@
let parsed = parse(
&code,
&ParserSettings {
- file_name: "raw.jsonnet".to_owned(),
+ file_name: PathBuf::from("raw.jsonnet"),
loc_data: true,
},
);
@@ -154,17 +153,17 @@
use jsonnet_stdlib::STDLIB_STR;
if cfg!(feature = "serialized-stdlib") {
self.add_parsed_file(
- "std.jsonnet".to_owned(),
+ PathBuf::from("std.jsonnet"),
STDLIB_STR.to_owned(),
bincode::deserialize(include_bytes!(concat!(env!("OUT_DIR"), "/stdlib.bincode")))
.expect("deserialize stdlib"),
)
.unwrap();
} else {
- self.add_file("std.jsonnet".to_owned(), STDLIB_STR.to_owned())
+ self.add_file(PathBuf::from("std.jsonnet"), STDLIB_STR.to_owned())
.unwrap();
}
- let val = self.evaluate_file("std.jsonnet").unwrap();
+ let val = self.evaluate_file(&PathBuf::from("std.jsonnet")).unwrap();
self.add_global("std".to_owned(), val);
self.end_state();
}
@@ -183,11 +182,16 @@
Context::new().extend(new_bindings, None, None, None)
}
- pub fn push<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> T) -> T {
- self.0
- .stack
- .borrow_mut()
- .push(StackTraceElement(e, comment));
+ pub fn push<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {
+ {
+ let mut stack = self.0.stack.borrow_mut();
+ if stack.len() > 5000 {
+ drop(stack);
+ return self.error(Error::StackOverflow);
+ } else {
+ stack.push(StackTraceElement(e, comment));
+ }
+ }
let result = f();
self.0.stack.borrow_mut().pop();
result
@@ -217,21 +221,36 @@
use super::Val;
use crate::EvaluationState;
use jsonnet_parser::*;
+ use std::path::PathBuf;
#[test]
fn eval_state_stacktrace() {
let state = EvaluationState::default();
- state.push(
- loc_expr!(Expr::Num(0.0), true, ("test1.jsonnet".to_owned(), 10, 20)),
- "outer".to_owned(),
- || {
- state.push(
- loc_expr!(Expr::Num(0.0), true, ("test2.jsonnet".to_owned(), 30, 40)),
- "inner".to_owned(),
- || state.print_stack_trace(),
- );
- },
- );
+ state
+ .push(
+ loc_expr!(
+ Expr::Num(0.0),
+ true,
+ (PathBuf::from("test1.jsonnet"), 10, 20)
+ ),
+ "outer".to_owned(),
+ || {
+ state.push(
+ loc_expr!(
+ Expr::Num(0.0),
+ true,
+ (PathBuf::from("test2.jsonnet"), 30, 40)
+ ),
+ "inner".to_owned(),
+ || {
+ state.print_stack_trace();
+ Ok(())
+ },
+ )?;
+ Ok(())
+ },
+ )
+ .unwrap();
}
#[test]
@@ -240,7 +259,7 @@
state.add_stdlib();
assert_eq!(
state
- .parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==w")"#)
+ .parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#)
.unwrap(),
Val::Bool(true)
);