1use crate::prelude::*;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5pub struct Runtime {
6 pub module_manager: ModuleManager,
7 pub environment_stack: Vec<Box<Environment>>,
8 pub parsing_free_param_collection: FreeParamCollection,
9}
10
11impl Runtime {
12 pub fn new() -> Self {
13 let module_manager = ModuleManager::new_empty_module_manager(BUILTIN_CODE_PATH);
14 let new_environment = Box::new(Environment::new_empty_env());
15
16 Runtime {
17 module_manager,
18 environment_stack: vec![new_environment],
19 parsing_free_param_collection: FreeParamCollection::new(),
20 }
21 }
22
23 pub fn new_with_builtin_code() -> Self {
25 let mut runtime = Self::new();
26 let (stmt_results, runtime_error) =
27 crate::pipeline::run_source_code(builtin_code().as_str(), &mut runtime);
28 let (ok, msg) = crate::pipeline::render_run_source_code_output(
29 &runtime,
30 &stmt_results,
31 &runtime_error,
32 true,
33 );
34 if !ok {
35 panic!("builtin code execution failed: {}", msg);
36 }
37 runtime
38 }
39}
40
41impl Runtime {
42 pub fn validate_name(
43 &mut self,
44 name: &str,
45 _current_line_file: LineFile,
46 ) -> Result<(), RuntimeError> {
47 if let Err(invalid_name_message) = is_valid_litex_name(name) {
48 return Err(ParseRuntimeError(RuntimeErrorStruct::new_with_just_msg(
49 invalid_name_message,
50 ))
51 .into());
52 }
53
54 Ok(())
55 }
56
57 pub fn validate_user_fn_param_names_for_parse(
58 &mut self,
59 names: &[String],
60 line_file: LineFile,
61 ) -> Result<(), RuntimeError> {
62 for name in names {
63 if let Err(e) = is_valid_litex_name(name) {
64 return Err(
65 ParseRuntimeError(RuntimeErrorStruct::new_with_msg_and_line_file(
66 e,
67 line_file.clone(),
68 ))
69 .into(),
70 );
71 }
72 }
73 Ok(())
74 }
75
76 pub fn validate_names_and_insert_into_top_parsing_time_name_scope(
77 &mut self,
78 names: &Vec<String>,
79 line_file: LineFile,
80 ) -> Result<(), RuntimeError> {
81 for name in names {
82 self.validate_name_and_insert_into_top_parsing_time_name_scope(
83 name,
84 line_file.clone(),
85 )?;
86 }
87 Ok(())
88 }
89
90 pub fn validate_name_and_insert_into_top_parsing_time_name_scope(
92 &mut self,
93 name: &str,
94 line_file: LineFile,
95 ) -> Result<(), RuntimeError> {
96 self.validate_name(name, line_file)
97 }
98}
99
100impl Runtime {
101 pub fn new_file_path_new_env_new_name_scope(&mut self, path: &str) {
102 let path_rc: Rc<str> = Rc::from(path);
103 self.module_manager.run_file_paths.push(path_rc.clone());
104 self.module_manager.current_file_index += 1;
105 self.module_manager.display_entry_rc = Some(path_rc);
106 self.module_manager.entry_path = path.to_string();
107 self.push_env();
108 }
109
110 pub fn set_current_user_lit_file_path(&mut self, path: &str) {
113 let path_rc: Rc<str> = Rc::from(path);
114 let idx = self.module_manager.current_file_index;
115 debug_assert!(
116 idx > FILE_INDEX_FOR_BUILTIN,
117 "set_current_user_lit_file_path requires a prior new_file_path_new_env_new_name_scope"
118 );
119 if let Some(slot) = self.module_manager.run_file_paths.get_mut(idx) {
120 *slot = path_rc.clone();
121 }
122 self.module_manager.display_entry_rc = Some(path_rc);
123 self.module_manager.entry_path = path.to_string();
124 }
125}
126
127impl Runtime {
128 pub fn top_level_env(&mut self) -> &mut Environment {
129 let result = self.environment_stack.last_mut();
130 match result {
131 Some(environment) => environment,
132 None => unreachable!("no top level environment"),
133 }
134 }
135}
136
137impl Runtime {
138 fn push_env(&mut self) {
139 let new_env = Box::new(Environment::new_empty_env());
140 self.environment_stack.push(new_env);
141 }
142
143 fn pop_env(&mut self) {
144 let last_env = self.environment_stack.last();
145
146 match last_env {
147 None => {
148 unreachable!("no top level environment")
149 }
150 Some(_) => {
151 self.environment_stack.pop();
152 }
153 }
154 }
155
156 pub fn clear_current_env_and_parse_name_scope(&mut self) {
159 if self.environment_stack.len() > 1 {
160 if let Some(top) = self.environment_stack.last_mut() {
161 *top = Box::new(Environment::new_empty_env());
162 }
163 }
164 self.parsing_free_param_collection.clear();
165 }
166
167 pub fn run_in_local_env<T, E, F>(&mut self, f: F) -> Result<T, E>
170 where
171 F: FnOnce(&mut Self) -> Result<T, E>,
172 {
173 self.push_env();
174 let result = f(self);
175 self.pop_env();
176 result
177 }
178
179 pub fn run_in_local_parsing_time_name_scope<T, E, F>(&mut self, f: F) -> Result<T, E>
183 where
184 F: FnOnce(&mut Self) -> Result<T, E>,
185 {
186 let saved_free_params = self.parsing_free_param_collection.clone();
187 let result = f(self);
188 self.parsing_free_param_collection = saved_free_params;
189 result
190 }
191
192 pub fn parse_in_local_free_param_scope<T, F>(
194 &mut self,
195 kind: ParamObjType,
196 names: &[String],
197 line_file: LineFile,
198 f: F,
199 ) -> Result<T, RuntimeError>
200 where
201 F: FnOnce(&mut Self) -> Result<T, RuntimeError>,
202 {
203 self.parsing_free_param_collection
204 .begin_scope(kind, names, line_file)?;
205 let result = f(self);
206 self.parsing_free_param_collection.end_scope(kind, names);
207 result
208 }
209
210 pub fn with_optional_free_param_scope<T, F>(
212 &mut self,
213 kind: ParamObjType,
214 names: &[String],
215 line_file: LineFile,
216 f: F,
217 ) -> Result<T, RuntimeError>
218 where
219 F: FnOnce(&mut Self) -> Result<T, RuntimeError>,
220 {
221 if names.is_empty() {
222 f(self)
223 } else {
224 self.parse_in_local_free_param_scope(kind, names, line_file, f)
225 }
226 }
227
228 pub fn parse_stmts_with_optional_free_param_scope<F>(
229 &mut self,
230 kind: ParamObjType,
231 names: &[String],
232 line_file: LineFile,
233 parse_body: F,
234 ) -> Result<Vec<Stmt>, RuntimeError>
235 where
236 F: FnOnce(&mut Self) -> Result<Vec<Stmt>, RuntimeError>,
237 {
238 self.with_optional_free_param_scope(kind, names, line_file, parse_body)
239 }
240}
241
242impl Runtime {
243 pub fn is_name_used_for_identifier_and_field_access(&self, name: &str) -> bool {
244 if is_builtin_identifier_name(name) {
245 return true;
246 }
247
248 for env in self.iter_environments_from_top() {
249 if env.defined_identifiers.contains_key(name) {
250 return true;
251 }
252 }
253
254 false
255 }
256
257 pub fn is_name_used_for_prop(&self, name: &str) -> bool {
258 return self.get_prop_definition_by_name(name).is_some();
259 }
260
261 pub fn is_name_used_for_abstract_prop(&self, name: &str) -> bool {
262 if is_builtin_predicate(name) {
263 return true;
264 }
265
266 return self.get_abstract_prop_definition_by_name(name).is_some();
267 }
268
269 pub fn is_name_used_for_family(&self, name: &str) -> bool {
270 return self.get_family_definition_by_name(name).is_some();
271 }
272
273 pub fn is_name_used_for_algo(&self, name: &str) -> bool {
274 return self.get_algo_definition_by_name(name).is_some();
275 }
276}
277
278impl Runtime {
279 pub fn new_file_and_update_runtime_with_file_content(&mut self, path: &str) {
280 let path_rc: Rc<str> = Rc::from(path);
281 self.module_manager.run_file_paths.push(path_rc.clone());
282 self.module_manager.current_file_index = self.module_manager.run_file_paths.len() - 1;
283 self.module_manager.display_entry_rc = Some(path_rc);
284 self.module_manager.entry_path = path.to_string();
285 }
286
287 pub fn change_file_index_to(&mut self, file_index: usize) {
288 self.module_manager.current_file_index = file_index;
289 }
290}
291
292impl Runtime {
293 pub fn store_tuple_obj_and_cart(
294 &mut self,
295 name: &str,
296 tuple: Option<Tuple>,
297 cart: Option<Cart>,
298 line_file: LineFile,
299 ) {
300 let known_tuple_objs = &mut self.top_level_env().known_objs_equal_to_tuple;
301 let old_tuple_and_cart = known_tuple_objs.get(name).cloned();
302
303 let merged_tuple = match (tuple, old_tuple_and_cart.as_ref()) {
304 (Some(new_tuple), _) => Some(new_tuple),
305 (None, Some((old_tuple, _, _))) => old_tuple.clone(),
306 (None, None) => None,
307 };
308 let merged_cart = match (cart, old_tuple_and_cart.as_ref()) {
309 (Some(new_cart), _) => Some(new_cart),
310 (None, Some((_, old_cart, _))) => old_cart.clone(),
311 (None, None) => None,
312 };
313 let merged_line_file = line_file;
314
315 known_tuple_objs.insert(
316 name.to_string(),
317 (merged_tuple, merged_cart, merged_line_file),
318 );
319 }
320
321 pub fn store_known_cart_obj(&mut self, name: &str, cart: Cart, line_file: LineFile) {
322 self.top_level_env()
323 .known_objs_equal_to_cart
324 .insert(name.to_string(), (cart, line_file));
325 }
326
327 pub fn store_known_finite_seq_list_obj(
328 &mut self,
329 name: &str,
330 list: FiniteSeqListObj,
331 member_of_finite_seq_set: Option<FiniteSeqSet>,
332 line_file: LineFile,
333 ) {
334 let map = &mut self.top_level_env().known_objs_equal_to_finite_seq_list;
335 let old = map.get(name).cloned();
336 let merged_member = match (member_of_finite_seq_set, old.as_ref()) {
337 (Some(new_s), _) => Some(new_s),
338 (None, Some((_, Some(old_s), _))) => Some(old_s.clone()),
339 (None, _) => None,
340 };
341 map.insert(name.to_string(), (list, merged_member, line_file));
342 }
343
344 pub fn store_known_matrix_list_obj(
345 &mut self,
346 name: &str,
347 matrix: MatrixListObj,
348 member_of_matrix_set: Option<MatrixSet>,
349 line_file: LineFile,
350 ) {
351 let map = &mut self.top_level_env().known_objs_equal_to_matrix_list;
352 let old = map.get(name).cloned();
353 let merged_member = match (member_of_matrix_set, old.as_ref()) {
354 (Some(new_s), _) => Some(new_s),
355 (None, Some((_, Some(old_s), _))) => Some(old_s.clone()),
356 (None, _) => None,
357 };
358 map.insert(name.to_string(), (matrix, merged_member, line_file));
359 }
360
361 pub fn matrix_set_to_fn_set(&self, ms: &MatrixSet, line_file: LineFile) -> FnSet {
362 let pair = self.generate_random_unused_names(2);
363 let p1 = pair[0].clone();
364 let p2 = pair[1].clone();
365 FnSet::new(
366 vec![
367 ParamGroupWithSet::new(vec![p1.clone()], StandardSet::NPos.into()),
368 ParamGroupWithSet::new(vec![p2.clone()], StandardSet::NPos.into()),
369 ],
370 vec![
371 AtomicFact::from(LessEqualFact::new(
372 obj_for_bound_param_in_scope(p1, ParamObjType::FnSet),
373 (*ms.row_len).clone(),
374 line_file.clone(),
375 ))
376 .into(),
377 AtomicFact::from(LessEqualFact::new(
378 obj_for_bound_param_in_scope(p2, ParamObjType::FnSet),
379 (*ms.col_len).clone(),
380 line_file.clone(),
381 ))
382 .into(),
383 ],
384 (*ms.set).clone(),
385 )
386 .expect("generated matrix fn set uses fresh parameters")
387 }
388
389 pub fn finite_seq_set_to_fn_set(&self, fs: &FiniteSeqSet, line_file: LineFile) -> FnSet {
390 let param = self.generate_random_unused_name();
391 FnSet::new(
392 vec![ParamGroupWithSet::new(
393 vec![param.clone()],
394 StandardSet::NPos.into(),
395 )],
396 vec![AtomicFact::from(LessEqualFact::new(
397 obj_for_bound_param_in_scope(param, ParamObjType::FnSet),
398 (*fs.n).clone(),
399 line_file,
400 ))
401 .into()],
402 (*fs.set).clone(),
403 )
404 .expect("generated finite sequence fn set uses a fresh parameter")
405 }
406
407 pub fn seq_set_to_fn_set(&self, ss: &SeqSet, _line_file: LineFile) -> FnSet {
408 let param = self.generate_random_unused_name();
409 FnSet::new(
410 vec![ParamGroupWithSet::new(
411 vec![param.clone()],
412 StandardSet::NPos.into(),
413 )],
414 vec![],
415 (*ss.set).clone(),
416 )
417 .expect("generated sequence fn set uses a fresh parameter")
418 }
419
420 pub fn finite_seq_set_to_fn_set_from_surface_dom_param(
421 &self,
422 fs: &FiniteSeqSet,
423 line_file: LineFile,
424 surface_dom_param: &str,
425 ) -> Result<FnSet, RuntimeError> {
426 let params = vec![ParamGroupWithSet::new(
427 vec![surface_dom_param.to_string()],
428 StandardSet::NPos.into(),
429 )];
430 let dom_facts: Vec<OrAndChainAtomicFact> = vec![OrAndChainAtomicFact::AtomicFact(
431 LessEqualFact::new(
432 Identifier::new(surface_dom_param.to_string()).into(),
433 (*fs.n).clone(),
434 line_file,
435 )
436 .into(),
437 )];
438 self.new_fn_set(params, dom_facts, (*fs.set).clone())
439 }
440
441 pub fn store_well_defined_obj_cache(&mut self, obj: &Obj) {
442 self.top_level_env()
443 .cache_well_defined_obj
444 .insert(obj.to_string(), ());
445 }
446}
447
448impl Runtime {
449 pub fn new_fn_set(
450 &self,
451 params_and_their_sets: Vec<ParamGroupWithSet>,
452 dom_facts: Vec<OrAndChainAtomicFact>,
453 ret_set: Obj,
454 ) -> Result<FnSet, RuntimeError> {
455 let empty: HashMap<String, Obj> = HashMap::new();
456 let mut dom_stored = Vec::with_capacity(dom_facts.len());
457 for d in &dom_facts {
458 dom_stored.push(self.inst_or_and_chain_atomic_fact(
459 d,
460 &empty,
461 ParamObjType::FnSet,
462 None,
463 )?);
464 }
465 let ret_stored = self.inst_obj(&ret_set, &empty, ParamObjType::FnSet)?;
466 Ok(FnSet::new(params_and_their_sets, dom_stored, ret_stored)?)
467 }
468
469 pub fn new_anonymous_fn(
470 &self,
471 params_and_their_sets: Vec<ParamGroupWithSet>,
472 dom_facts: Vec<OrAndChainAtomicFact>,
473 ret_set: Obj,
474 equal_to: Obj,
475 ) -> Result<AnonymousFn, RuntimeError> {
476 let empty: HashMap<String, Obj> = HashMap::new();
477 let mut dom_stored = Vec::with_capacity(dom_facts.len());
478 for d in &dom_facts {
479 dom_stored.push(self.inst_or_and_chain_atomic_fact(
480 d,
481 &empty,
482 ParamObjType::FnSet,
483 None,
484 )?);
485 }
486 let ret_stored = self.inst_obj(&ret_set, &empty, ParamObjType::FnSet)?;
487 let eq_stored = self.inst_obj(&equal_to, &empty, ParamObjType::FnSet)?;
488 Ok(AnonymousFn::new(
489 params_and_their_sets,
490 dom_stored,
491 ret_stored,
492 eq_stored,
493 )?)
494 }
495
496 pub fn fn_set_from_fn_set_clause(&self, clause: &FnSetClause) -> Result<FnSet, RuntimeError> {
497 self.new_fn_set(
498 clause.params_def_with_set.clone(),
499 clause.dom_facts.clone(),
500 clause.ret_set.clone(),
501 )
502 }
503}
504
505impl Runtime {
506 pub fn params_to_arg_map(
507 &self,
508 param_defs: &ParamDefWithType,
509 args: &[Obj],
510 ) -> Result<HashMap<String, Obj>, RuntimeError> {
511 let param_names = param_defs.collect_param_names();
512 if param_names.len() != args.len() {
513 return Err(
514 InstantiateRuntimeError(RuntimeErrorStruct::new_with_just_msg(format!(
515 "params_to_arg_map: expected {} argument(s), got {}",
516 param_names.len(),
517 args.len()
518 )))
519 .into(),
520 );
521 }
522
523 let mut result: HashMap<String, Obj> = HashMap::new();
524 for (param_name, arg) in param_names.iter().zip(args.iter()) {
525 result.insert(param_name.clone(), arg.clone());
526 }
527 Ok(result)
528 }
529}