git.delta.rocks / jrsonnet / refs/commits / 3730d676869d

difftreelog

refactor(evaluator) simplify state internals

Лач2020-06-28parent: #6359a4d.patch.diff
in: master

1 file changed

modifiedcrates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth
24pub 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::*;
2929
30type BindableFn = dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>;30type BindableFn = dyn Fn(Option<ObjValue>, Option<ObjValue>) -> Result<LazyVal>;
48 }48 }
49}49}
5050
51pub 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}
69
70#[derive(Default)]
71struct EvaluationData {
72 /// Used for stack-overflows and stacktraces
73 stack: Vec<StackTraceElement>,
74 /// Contains file source codes and evaluated results for imports and pretty
75 /// printing stacktraces
76 files: HashMap<Rc<PathBuf>, FileData>,
77 str_files: HashMap<Rc<PathBuf>, Rc<str>>,
78}
6379
64pub 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 stacktraces
68 stack: RefCell<Vec<StackTraceElement>>,83 data: RefCell<EvaluationData>,
69 /// Contains file source codes and evaluated results for imports and pretty
70 /// printing stacktraces
71 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>>,
74
75 /// Values to use with std.extVar
76 ext_vars: RefCell<HashMap<Rc<str>, Val>>,
77
78 settings: EvaluationSettings,
79 import_resolver: Box<dyn ImportResolver>,
80}85}
8186
82thread_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 }
129
130 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 }
136
119 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 .files
155 .borrow_mut()172 .files
156 .insert(name, FileData(code, parsed, None));173 .insert(name, FileData(code, parsed, None));
157174
158 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_map
169 .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.0
179 .files196 .data.borrow_mut()
180 .borrow_mut()197 .files
181 .get_mut(name)198 .get_mut(name)
182 .unwrap()199 .unwrap()
183 .2200 .2
187 })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_files
209 .borrow_mut()225 .str_files
210 .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 }
214230
215 pub fn parse_evaluate_raw(&self, code: &str) -> Result<Val> {231 pub fn parse_evaluate_raw(&self, code: &str) -> Result<Val> {
229 }245 }
230246
231 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 }
237253
238 pub fn with_stdlib(&self) -> &Self {254 pub fn with_stdlib(&self) -> &Self {
278 }294 }
279295
280 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 here
301 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 result
310 }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 .stack
320 .borrow()337 .stack
321 .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 )