1#![feature(box_syntax, box_patterns)]2#![feature(type_alias_impl_trait)]3#![feature(debug_non_exhaustive)]4#![allow(macro_expanded_macro_exports_accessed_by_absolute_paths)]5mod ctx;6mod dynamic;7mod error;8mod evaluate;9mod function;10mod obj;11mod val;1213pub use ctx::*;14pub use dynamic::*;15pub use error::*;16pub use evaluate::*;17use jsonnet_parser::*;18pub use obj::*;19use std::{cell::RefCell, collections::HashMap, fmt::Debug, path::PathBuf, rc::Rc};20pub use val::*;2122rc_fn_helper!(23 Binding,24 binding,25 dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<Val>26);27rc_fn_helper!(FunctionRhs, function_rhs, dyn Fn(Context) -> Result<Val>);28rc_fn_helper!(29 FunctionDefault,30 function_default,31 dyn Fn(Context, LocExpr) -> Result<Val>32);3334#[derive(Clone)]35pub enum LazyBinding {36 Bindable(Rc<dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>>),37 Bound(LazyVal),38}3940impl Debug for LazyBinding {41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {42 write!(f, "LazyBinding")43 }44}45impl LazyBinding {46 pub fn evaluate(&self, this: Option<ObjValue>, super_obj: Option<ObjValue>) -> Result<LazyVal> {47 match self {48 LazyBinding::Bindable(v) => v(this, super_obj),49 LazyBinding::Bound(v) => Ok(v.clone()),50 }51 }52}5354pub struct FileData(String, LocExpr, Option<Val>);55#[derive(Default)]56pub struct EvaluationStateInternals {57 58 stack: RefCell<Vec<StackTraceElement>>,59 60 61 files: RefCell<HashMap<PathBuf, FileData>>,62 globals: RefCell<HashMap<String, Val>>,63}6465thread_local! {66 pub static EVAL_STATE: RefCell<Option<EvaluationState>> = RefCell::new(None)67}68pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {69 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))70}71pub(crate) fn create_error<T>(err: Error) -> Result<T> {72 with_state(|s| s.error(err))73}74pub(crate) fn push<T>(e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {75 with_state(|s| s.push(e, comment, f))76}7778#[derive(Default, Clone)]79pub struct EvaluationState(Rc<EvaluationStateInternals>);80impl EvaluationState {81 pub fn add_file(&self, name: PathBuf, code: String) -> std::result::Result<(), ParseError> {82 self.0.files.borrow_mut().insert(83 name.clone(),84 FileData(85 code.clone(),86 parse(87 &code,88 &ParserSettings {89 file_name: name,90 loc_data: true,91 },92 )?,93 None,94 ),95 );9697 Ok(())98 }99 pub fn add_parsed_file(100 &self,101 name: PathBuf,102 code: String,103 parsed: LocExpr,104 ) -> std::result::Result<(), ()> {105 self.0106 .files107 .borrow_mut()108 .insert(name, FileData(code, parsed, None));109110 Ok(())111 }112 pub fn get_source(&self, name: &PathBuf) -> Option<String> {113 let ro_map = self.0.files.borrow();114 ro_map.get(name).map(|value| value.0.clone())115 }116 pub fn evaluate_file(&self, name: &PathBuf) -> Result<Val> {117 self.begin_state();118 let expr: LocExpr = {119 let ro_map = self.0.files.borrow();120 let value = ro_map121 .get(name)122 .unwrap_or_else(|| panic!("file not added: {:?}", name));123 if value.2.is_some() {124 return Ok(value.2.clone().unwrap());125 }126 value.1.clone()127 };128 let value = evaluate(self.create_default_context()?, &expr)?;129 {130 self.0131 .files132 .borrow_mut()133 .get_mut(name)134 .unwrap()135 .2136 .replace(value.clone());137 }138 self.end_state();139 Ok(value)140 }141142 pub fn parse_evaluate_raw(&self, code: &str) -> Result<Val> {143 let parsed = parse(144 &code,145 &ParserSettings {146 file_name: PathBuf::from("raw.jsonnet"),147 loc_data: true,148 },149 );150 self.begin_state();151 let value = evaluate(self.create_default_context()?, &parsed.unwrap());152 self.end_state();153 value154 }155156 pub fn add_global(&self, name: String, value: Val) {157 self.0.globals.borrow_mut().insert(name, value);158 }159160 pub fn add_stdlib(&self) {161 self.begin_state();162 use jsonnet_stdlib::STDLIB_STR;163 if cfg!(feature = "serialized-stdlib") {164 self.add_parsed_file(165 PathBuf::from("std.jsonnet"),166 STDLIB_STR.to_owned(),167 bincode::deserialize(include_bytes!(concat!(env!("OUT_DIR"), "/stdlib.bincode")))168 .expect("deserialize stdlib"),169 )170 .unwrap();171 } else {172 self.add_file(PathBuf::from("std.jsonnet"), STDLIB_STR.to_owned())173 .unwrap();174 }175 let val = self.evaluate_file(&PathBuf::from("std.jsonnet")).unwrap();176 self.add_global("std".to_owned(), val);177 self.end_state();178 }179180 pub fn create_default_context(&self) -> Result<Context> {181 let globals = self.0.globals.borrow();182 let mut new_bindings: HashMap<String, LazyBinding> = HashMap::new();183 for (name, value) in globals.iter() {184 new_bindings.insert(185 name.clone(),186 LazyBinding::Bound(resolved_lazy_val!(value.clone())),187 );188 }189 Context::new().extend(new_bindings, None, None, None)190 }191192 pub fn push<T>(&self, e: LocExpr, comment: String, f: impl FnOnce() -> Result<T>) -> Result<T> {193 {194 let mut stack = self.0.stack.borrow_mut();195 if stack.len() > 500 {196 drop(stack);197 return self.error(Error::StackOverflow);198 } else {199 stack.push(StackTraceElement(e, comment));200 }201 }202 let result = f();203 self.0.stack.borrow_mut().pop();204 result205 }206 pub fn print_stack_trace(&self) {207 for e in self.stack_trace().0 {208 println!("{:?} - {:?}", e.0, e.1)209 }210 }211 pub fn stack_trace(&self) -> StackTrace {212 StackTrace(self.0.stack.borrow().iter().rev().cloned().collect())213 }214 pub fn error<T>(&self, err: Error) -> Result<T> {215 Err(LocError(err, self.stack_trace()))216 }217218 fn begin_state(&self) {219 EVAL_STATE.with(|v| v.borrow_mut().replace(self.clone()));220 }221 fn end_state(&self) {222 EVAL_STATE.with(|v| v.borrow_mut().take());223 }224}225226#[cfg(test)]227pub mod tests {228 use super::Val;229 use crate::EvaluationState;230 use jsonnet_parser::*;231 use std::path::PathBuf;232233 #[test]234 fn eval_state_stacktrace() {235 let state = EvaluationState::default();236 state237 .push(238 loc_expr!(239 Expr::Num(0.0),240 true,241 (PathBuf::from("test1.jsonnet"), 10, 20)242 ),243 "outer".to_owned(),244 || {245 state.push(246 loc_expr!(247 Expr::Num(0.0),248 true,249 (PathBuf::from("test2.jsonnet"), 30, 40)250 ),251 "inner".to_owned(),252 || {253 state.print_stack_trace();254 Ok(())255 },256 )?;257 Ok(())258 },259 )260 .unwrap();261 }262263 #[test]264 fn eval_state_standard() {265 let state = EvaluationState::default();266 state.add_stdlib();267 assert_eq!(268 state269 .parse_evaluate_raw(r#"std.assertEqual(std.base64("test"), "dGVzdA==")"#)270 .unwrap(),271 Val::Bool(true)272 );273 }274275 macro_rules! eval {276 ($str: expr) => {277 evaluate(278 Context::new(),279 EvaluationState::default(),280 &parse(281 $str,282 &ParserSettings {283 loc_data: true,284 file_name: "test.jsonnet".to_owned(),285 },286 )287 .unwrap(),288 )289 };290 }291292 macro_rules! eval_stdlib {293 ($str: expr) => {{294 let std = "local std = ".to_owned() + jsonnet_stdlib::STDLIB_STR + ";";295 evaluate(296 Context::new(),297 EvaluationState::default(),298 &parse(299 &(std + $str),300 &ParserSettings {301 loc_data: true,302 file_name: "test.jsonnet".to_owned(),303 },304 )305 .unwrap(),306 )307 }};308 }309310 macro_rules! assert_eval {311 ($str: expr) => {312 assert_eq!(313 evaluate(314 Context::new(),315 EvaluationState::default(),316 &parse(317 $str,318 &ParserSettings {319 loc_data: true,320 file_name: "test.jsonnet".to_owned(),321 }322 )323 .unwrap()324 ),325 Val::Bool(true)326 )327 };328 }329 macro_rules! assert_json {330 ($str: expr, $out: expr) => {331 assert_eq!(332 format!(333 "{}",334 evaluate(335 Context::new(),336 EvaluationState::default(),337 &parse(338 $str,339 &ParserSettings {340 loc_data: true,341 file_name: "test.jsonnet".to_owned(),342 }343 )344 .unwrap()345 )346 ),347 $out348 )349 };350 }351 macro_rules! assert_json_stdlib {352 ($str: expr, $out: expr) => {353 assert_eq!(format!("{}", eval_stdlib!($str)), $out)354 };355 }356 macro_rules! assert_eval_neg {357 ($str: expr) => {358 assert_eq!(359 evaluate(360 Context::new(),361 EvaluationState::default(),362 &parse(363 $str,364 &ParserSettings {365 loc_data: true,366 file_name: "test.jsonnet".to_owned(),367 }368 )369 .unwrap()370 ),371 Val::Bool(false)372 )373 };374 }375376 377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587}