--- a/cmds/jrsonnet/src/main.rs +++ b/cmds/jrsonnet/src/main.rs @@ -1,7 +1,7 @@ pub mod location; use clap::Clap; -use jsonnet_evaluator::{EvaluationState, LocError, StackTrace, Val}; +use jsonnet_evaluator::{EvaluationSettings, EvaluationState, LocError, StackTrace, Val}; use location::{offset_to_location, CodeLocation}; use std::env::current_dir; use std::{path::PathBuf, str::FromStr}; @@ -111,7 +111,10 @@ fn main() { let opts: Opts = Opts::parse(); - let evaluator = jsonnet_evaluator::EvaluationState::default(); + let evaluator = jsonnet_evaluator::EvaluationState::new(EvaluationSettings { + import_resolver: Box::new(|path| String::from_utf8(std::fs::read(path).unwrap()).unwrap()), + ..Default::default() + }); if !opts.no_stdlib { evaluator.with_stdlib(); } --- a/crates/jsonnet-evaluator/src/evaluate.rs +++ b/crates/jsonnet-evaluator/src/evaluate.rs @@ -1,5 +1,5 @@ use crate::{ - binding, context_creator, create_error, future_wrapper, lazy_val, push, Context, + binding, context_creator, create_error, future_wrapper, lazy_val, push, with_state, Context, ContextCreator, FuncDesc, LazyBinding, ObjMember, ObjValue, Result, Val, }; use closure::closure; @@ -607,6 +607,16 @@ } } } + Import(path) => { + let mut lib_path = loc + .clone() + .expect("imports can't be used without loc_data") + .0 + .clone(); + lib_path.pop(); + lib_path.push(path); + with_state(|s| s.import_file(&lib_path))? + } _ => panic!( "evaluation not implemented: {:?}", LocExpr(expr.clone(), loc.clone()) --- a/crates/jsonnet-evaluator/src/lib.rs +++ b/crates/jsonnet-evaluator/src/lib.rs @@ -50,14 +50,18 @@ } pub struct EvaluationSettings { - max_stack_frames: usize, - max_stack_trace_size: usize, + pub max_stack_frames: usize, + pub max_stack_trace_size: usize, + pub import_resolver: Box String>, } impl Default for EvaluationSettings { fn default() -> Self { EvaluationSettings { max_stack_frames: 200, max_stack_trace_size: 20, + import_resolver: Box::new(|path| { + panic!("default EvaluationSettings have no support for import resolution, can't import {:?}", path) + }), } } } @@ -102,6 +106,12 @@ #[derive(Default, Clone)] pub struct EvaluationState(Rc); impl EvaluationState { + pub fn new(settings: EvaluationSettings) -> Self { + EvaluationState(Rc::new(EvaluationStateInternals { + settings, + ..Default::default() + })) + } pub fn add_file(&self, name: PathBuf, code: String) -> std::result::Result<(), ParseError> { self.0.files.borrow_mut().insert( name.clone(), @@ -139,6 +149,11 @@ } pub fn evaluate_file(&self, name: &PathBuf) -> Result { self.begin_state(); + let value = self.evaluate_file_in_current_state(name)?; + self.end_state(); + Ok(value) + } + pub(crate) fn evaluate_file_in_current_state(&self, name: &PathBuf) -> Result { let expr: LocExpr = { let ro_map = self.0.files.borrow(); let value = ro_map @@ -159,9 +174,15 @@ .2 .replace(value.clone()); } - self.end_state(); Ok(value) } + pub(crate) fn import_file(&self, path: &PathBuf) -> Result { + if !self.0.files.borrow().contains_key(path) { + let file_str = (self.0.settings.import_resolver)(path); + self.add_file(path.clone(), file_str).unwrap(); + } + self.evaluate_file_in_current_state(path) + } pub fn parse_evaluate_raw(&self, code: &str) -> Result { let parsed = parse(