difftreelog
refactor(evaluator) simplify state internals
in: master
1 file changed
crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth24pub use import::*;24pub use import::*;25use jrsonnet_parser::*;25use jrsonnet_parser::*;26pub use obj::*;26pub use obj::*;27use std::{cell::RefCell, collections::HashMap, fmt::Debug, path::PathBuf, rc::Rc};27use std::{cell::{Ref, RefCell, RefMut}, collections::HashMap, fmt::Debug, path::PathBuf, rc::Rc};28pub use val::*;28pub use val::*;292930type BindableFn = dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>;30type BindableFn = dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>;48 }48 }49}49}505051pub struct EvaluationSettings {51struct EvaluationSettings {52 pub max_stack_frames: usize,52 max_stack_frames: usize,53 pub max_stack_trace_size: usize,53 max_stack_trace_size: usize,54 ext_vars: HashMap<Rc<str>, Val>,55 globals: HashMap<Rc<str>, Val>,56 import_resolver: Box<dyn ImportResolver>,54}57}55impl Default for EvaluationSettings {58impl Default for EvaluationSettings {56 fn default() -> Self {59 fn default() -> Self {57 EvaluationSettings {60 EvaluationSettings {58 max_stack_frames: 200,61 max_stack_frames: 200,59 max_stack_trace_size: 20,62 max_stack_trace_size: 20,63 globals: Default::default(),64 ext_vars: Default::default(),65 import_resolver: Box::new(DummyImportResolver),60 }66 }61 }67 }62}68}6970#[derive(Default)]71struct EvaluationData {72 /// Used for stack-overflows and stacktraces73 stack: Vec<StackTraceElement>,74 /// Contains file source codes and evaluated results for imports and pretty75 /// printing stacktraces76 files: HashMap<Rc<PathBuf>, FileData>,77 str_files: HashMap<Rc<PathBuf>, Rc<str>>,78}637964pub struct FileData(Rc<str>, LocExpr, Option<Val>);80pub struct FileData(Rc<str>, LocExpr, Option<Val>);65#[derive(Default)]81#[derive(Default)]66pub struct EvaluationStateInternals {82pub struct EvaluationStateInternals {67 /// Used for stack-overflows and stacktraces68 stack: RefCell<Vec<StackTraceElement>>,83 data: RefCell<EvaluationData>,69 /// Contains file source codes and evaluated results for imports and pretty70 /// printing stacktraces71 files: RefCell<HashMap<Rc<PathBuf>, FileData>>,84 settings: RefCell<EvaluationSettings>,72 str_files: RefCell<HashMap<Rc<PathBuf>, Rc<str>>>,73 globals: RefCell<HashMap<Rc<str>, Val>>,7475 /// Values to use with std.extVar76 ext_vars: RefCell<HashMap<Rc<str>, Val>>,7778 settings: EvaluationSettings,79 import_resolver: Box<dyn ImportResolver>,80}85}818682thread_local! {87thread_local! {87pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {92pub(crate) fn with_state<T>(f: impl FnOnce(&EvaluationState) -> T) -> T {88 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))93 EVAL_STATE.with(|s| f(s.borrow().as_ref().unwrap()))89}94}90pub(crate) fn create_error(err: Error) -> LocError {95pub fn create_error(err: Error) -> LocError {91 with_state(|s| s.error(err))96 with_state(|s| s.error(err))92}97}93pub(crate) fn create_error_result<T>(err: Error) -> Result<T> {98pub fn create_error_result<T>(err: Error) -> Result<T> {94 Err(with_state(|s| s.error(err)))99 Err(with_state(|s| s.error(err)))95}100}96pub(crate) fn push<T>(101pub(crate) fn push<T>(109#[derive(Default, Clone)]114#[derive(Default, Clone)]110pub struct EvaluationState(Rc<EvaluationStateInternals>);115pub struct EvaluationState(Rc<EvaluationStateInternals>);111impl EvaluationState {116impl EvaluationState {112 pub fn new(settings: EvaluationSettings, import_resolver: Box<dyn ImportResolver>) -> Self {117 fn data(&self) -> Ref<EvaluationData> {118 self.0.data.borrow()119 }120 fn data_mut(&self) -> RefMut<EvaluationData> {121 self.0.data.borrow_mut()122 }123 fn settings(&self) -> Ref<EvaluationSettings> {124 self.0.settings.borrow()125 }126 fn settings_mut(&self) -> RefMut<EvaluationSettings> {127 self.0.settings.borrow_mut()128 }129130 pub fn set_import_resolver(&self, resolver: Box<dyn ImportResolver>) {131 self.settings_mut().import_resolver = resolver;132 }133 pub fn import_resolver(&self) -> Ref<dyn ImportResolver> {113 EvaluationState(Rc::new(EvaluationStateInternals {134 Ref::map(self.settings(), |s|&*s.import_resolver)114 settings,115 import_resolver,116 ..Default::default()117 }))118 }135 }136119 pub fn evaluate_file_to_json(137 pub fn evaluate_file_to_json(127 name: Rc<PathBuf>,145 name: Rc<PathBuf>,128 code: Rc<str>,146 code: Rc<str>,129 ) -> std::result::Result<(), ParseError> {147 ) -> std::result::Result<(), ParseError> {130 self.0.files.borrow_mut().insert(148 self.data_mut().files.insert(131 name.clone(),149 name.clone(),132 FileData(150 FileData(133 code.clone(),151 code.clone(),150 code: Rc<str>,168 code: Rc<str>,151 parsed: LocExpr,169 parsed: LocExpr,152 ) -> std::result::Result<(), ()> {170 ) -> std::result::Result<(), ()> {153 self.0171 self.data_mut()154 .files155 .borrow_mut()172 .files156 .insert(name, FileData(code, parsed, None));173 .insert(name, FileData(code, parsed, None));157174158 Ok(())175 Ok(())159 }176 }160 pub fn get_source(&self, name: &PathBuf) -> Option<Rc<str>> {177 pub fn get_source(&self, name: &PathBuf) -> Option<Rc<str>> {161 let ro_map = self.0.files.borrow();178 let ro_map = &self.data().files;162 ro_map.get(name).map(|value| value.0.clone())179 ro_map.get(name).map(|value| value.0.clone())163 }180 }164 pub fn evaluate_file(&self, name: &PathBuf) -> Result<Val> {181 pub fn evaluate_file(&self, name: &PathBuf) -> Result<Val> {165 self.run_in_state(|| {182 self.run_in_state(|| {166 let expr: LocExpr = {183 let expr: LocExpr = {167 let ro_map = self.0.files.borrow();184 let ro_map = &self.data().files;168 let value = ro_map185 let value = ro_map169 .get(name)186 .get(name)170 .unwrap_or_else(|| panic!("file not added: {:?}", name));187 .unwrap_or_else(|| panic!("file not added: {:?}", name));176 let value = evaluate(self.create_default_context()?, &expr)?;193 let value = evaluate(self.create_default_context()?, &expr)?;177 {194 {178 self.0195 self.0179 .files196 .data.borrow_mut()180 .borrow_mut()197 .files181 .get_mut(name)198 .get_mut(name)182 .unwrap()199 .unwrap()183 .2200 .2187 })204 })188 }205 }189 pub(crate) fn import_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Val> {206 pub(crate) fn import_file(&self, from: &PathBuf, path: &PathBuf) -> Result<Val> {190 let file_path = self.0.import_resolver.resolve_file(from, path)?;207 let file_path = self.settings().import_resolver.resolve_file(from, path)?;191 {208 {192 let files = self.0.files.borrow();209 let files = &self.data().files;193 if files.contains_key(&file_path) {210 if files.contains_key(&file_path) {194 return self.evaluate_file(&file_path);211 return self.evaluate_file(&file_path);195 }212 }196 }213 }197 let contents = self.0.import_resolver.load_file_contents(&file_path)?;214 let contents = self.settings().import_resolver.load_file_contents(&file_path)?;198 self.add_file(file_path.clone(), contents).map_err(|e| {215 self.add_file(file_path.clone(), contents).map_err(|e| {199 create_error(Error::ImportSyntaxError(e))216 create_error(Error::ImportSyntaxError(e))200 })?;217 })?;201 self.evaluate_file(&file_path)218 self.evaluate_file(&file_path)202 }219 }203 pub(crate) fn import_file_str(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<str>> {220 pub(crate) fn import_file_str(&self, from: &PathBuf, path: &PathBuf) -> Result<Rc<str>> {204 let path = self.0.import_resolver.resolve_file(from, path)?;221 let path = self.settings().import_resolver.resolve_file(from, path)?;205 if !self.0.str_files.borrow().contains_key(&path) {222 if !self.data().str_files.contains_key(&path) {206 let file_str = self.0.import_resolver.load_file_contents(&path)?;223 let file_str = self.settings().import_resolver.load_file_contents(&path)?;207 self.0224 self.data_mut()208 .str_files209 .borrow_mut()225 .str_files210 .insert(path.clone(), file_str);226 .insert(path.clone(), file_str);211 }227 }212 Ok(self.0.str_files.borrow().get(&path).cloned().unwrap())228 Ok(self.data().str_files.get(&path).cloned().unwrap())213 }229 }214230215 pub fn parse_evaluate_raw(&self, code: &str) -> Result<Val> {231 pub fn parse_evaluate_raw(&self, code: &str) -> Result<Val> {229 }245 }230246231 pub fn add_global(&self, name: Rc<str>, value: Val) {247 pub fn add_global(&self, name: Rc<str>, value: Val) {232 self.0.globals.borrow_mut().insert(name, value);248 self.settings_mut().globals.insert(name, value);233 }249 }234 pub fn add_ext_var(&self, name: Rc<str>, value: Val) {250 pub fn add_ext_var(&self, name: Rc<str>, value: Val) {235 self.0.ext_vars.borrow_mut().insert(name, value);251 self.settings_mut().ext_vars.insert(name, value);236 }252 }237253238 pub fn with_stdlib(&self) -> &Self {254 pub fn with_stdlib(&self) -> &Self {278 }294 }279295280 pub fn create_default_context(&self) -> Result<Context> {296 pub fn create_default_context(&self) -> Result<Context> {281 let globals = self.0.globals.borrow();297 let globals = &self.settings().globals;282 let mut new_bindings: HashMap<Rc<str>, LazyBinding> = HashMap::new();298 let mut new_bindings: HashMap<Rc<str>, LazyBinding> = HashMap::new();283 for (name, value) in globals.iter() {299 for (name, value) in globals.iter() {284 new_bindings.insert(300 new_bindings.insert(296 f: impl FnOnce() -> Result<T>,312 f: impl FnOnce() -> Result<T>,297 ) -> Result<T> {313 ) -> Result<T> {298 {314 {299 let mut stack = self.0.stack.borrow_mut();315 let mut data = self.data_mut();316 let stack = &mut data.stack;300 if stack.len() > self.0.settings.max_stack_frames {317 if stack.len() > self.settings().max_stack_frames {318 // Error creation uses data, so i drop guard here301 drop(stack);319 drop(data);302 return Err(self.error(Error::StackOverflow));320 return Err(self.error(Error::StackOverflow));303 } else {321 } else {304 stack.push(StackTraceElement(e, comment));322 stack.push(StackTraceElement(e, comment));305 }323 }306 }324 }307 let result = f();325 let result = f();308 self.0.stack.borrow_mut().pop();326 self.data_mut().stack.pop();309 result327 result310 }328 }311 pub fn print_stack_trace(&self) {329 pub fn print_stack_trace(&self) {315 }333 }316 pub fn stack_trace(&self) -> StackTrace {334 pub fn stack_trace(&self) -> StackTrace {317 StackTrace(335 StackTrace(318 self.0336 self.data()319 .stack320 .borrow()337 .stack321 .iter()338 .iter()322 .rev()339 .rev()323 .take(self.0.settings.max_stack_trace_size)340 .take(self.settings().max_stack_trace_size)324 .cloned()341 .cloned()325 .collect(),342 .collect(),326 )343 )