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(&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_algo(&self, name: &str) -> bool {
270 return self.get_algo_definition_by_name(name).is_some();
271 }
272}
273
274impl Runtime {
275 pub fn new_file_and_update_runtime_with_file_content(&mut self, path: &str) {
276 let path_rc: Rc<str> = Rc::from(path);
277 self.module_manager.run_file_paths.push(path_rc.clone());
278 self.module_manager.current_file_index = self.module_manager.run_file_paths.len() - 1;
279 self.module_manager.display_entry_rc = Some(path_rc);
280 self.module_manager.entry_path = path.to_string();
281 }
282
283 pub fn change_file_index_to(&mut self, file_index: usize) {
284 self.module_manager.current_file_index = file_index;
285 }
286}
287
288impl Runtime {
289 pub fn store_tuple_obj_and_cart(
290 &mut self,
291 name: &str,
292 tuple: Option<Tuple>,
293 cart: Option<Cart>,
294 line_file: LineFile,
295 ) {
296 let known_tuple_objs = &mut self.top_level_env().known_objs_equal_to_tuple;
297 let old_tuple_and_cart = known_tuple_objs.get(name).cloned();
298
299 let merged_tuple = match (tuple, old_tuple_and_cart.as_ref()) {
300 (Some(new_tuple), _) => Some(new_tuple),
301 (None, Some((old_tuple, _, _))) => old_tuple.clone(),
302 (None, None) => None,
303 };
304 let merged_cart = match (cart, old_tuple_and_cart.as_ref()) {
305 (Some(new_cart), _) => Some(new_cart),
306 (None, Some((_, old_cart, _))) => old_cart.clone(),
307 (None, None) => None,
308 };
309 let merged_line_file = line_file;
310
311 known_tuple_objs.insert(
312 name.to_string(),
313 (merged_tuple, merged_cart, merged_line_file),
314 );
315 }
316
317 pub fn store_known_cart_obj(&mut self, name: &str, cart: Cart, line_file: LineFile) {
318 self.top_level_env()
319 .known_objs_equal_to_cart
320 .insert(name.to_string(), (cart, line_file));
321 }
322
323 pub fn store_known_set_builder_obj(
324 &mut self,
325 name: &str,
326 set_builder: SetBuilder,
327 line_file: LineFile,
328 ) {
329 self.top_level_env()
330 .known_objs_equal_to_set_builder
331 .insert(name.to_string(), (set_builder, line_file));
332 }
333
334 pub fn store_known_finite_seq_list_obj(
335 &mut self,
336 name: &str,
337 list: FiniteSeqListObj,
338 member_of_finite_seq_set: Option<FiniteSeqSet>,
339 line_file: LineFile,
340 ) {
341 let map = &mut self.top_level_env().known_objs_equal_to_finite_seq_list;
342 let old = map.get(name).cloned();
343 let merged_member = match (member_of_finite_seq_set, old.as_ref()) {
344 (Some(new_s), _) => Some(new_s),
345 (None, Some((_, Some(old_s), _))) => Some(old_s.clone()),
346 (None, _) => None,
347 };
348 map.insert(name.to_string(), (list, merged_member, line_file));
349 }
350
351 pub fn store_known_matrix_list_obj(
352 &mut self,
353 name: &str,
354 matrix: MatrixListObj,
355 member_of_matrix_set: Option<MatrixSet>,
356 line_file: LineFile,
357 ) {
358 let map = &mut self.top_level_env().known_objs_equal_to_matrix_list;
359 let old = map.get(name).cloned();
360 let merged_member = match (member_of_matrix_set, old.as_ref()) {
361 (Some(new_s), _) => Some(new_s),
362 (None, Some((_, Some(old_s), _))) => Some(old_s.clone()),
363 (None, _) => None,
364 };
365 map.insert(name.to_string(), (matrix, merged_member, line_file));
366 }
367
368 pub fn matrix_set_to_fn_set(&self, ms: &MatrixSet, line_file: LineFile) -> FnSet {
369 let pair = self.generate_random_unused_names(2);
370 let p1 = pair[0].clone();
371 let p2 = pair[1].clone();
372 FnSet::new(
373 vec![
374 ParamGroupWithSet::new(vec![p1.clone()], StandardSet::NPos.into()),
375 ParamGroupWithSet::new(vec![p2.clone()], StandardSet::NPos.into()),
376 ],
377 vec![
378 AtomicFact::from(LessEqualFact::new(
379 obj_for_bound_param_in_scope(p1, ParamObjType::FnSet),
380 (*ms.row_len).clone(),
381 line_file.clone(),
382 ))
383 .into(),
384 AtomicFact::from(LessEqualFact::new(
385 obj_for_bound_param_in_scope(p2, ParamObjType::FnSet),
386 (*ms.col_len).clone(),
387 line_file.clone(),
388 ))
389 .into(),
390 ],
391 (*ms.set).clone(),
392 )
393 .expect("generated matrix fn set uses fresh parameters")
394 }
395
396 pub fn finite_seq_set_to_fn_set(&self, fs: &FiniteSeqSet, line_file: LineFile) -> FnSet {
397 let param = self.generate_random_unused_name();
398 FnSet::new(
399 vec![ParamGroupWithSet::new(
400 vec![param.clone()],
401 StandardSet::NPos.into(),
402 )],
403 vec![AtomicFact::from(LessEqualFact::new(
404 obj_for_bound_param_in_scope(param, ParamObjType::FnSet),
405 (*fs.n).clone(),
406 line_file,
407 ))
408 .into()],
409 (*fs.set).clone(),
410 )
411 .expect("generated finite sequence fn set uses a fresh parameter")
412 }
413
414 pub fn seq_set_to_fn_set(&self, ss: &SeqSet, _line_file: LineFile) -> FnSet {
415 let param = self.generate_random_unused_name();
416 FnSet::new(
417 vec![ParamGroupWithSet::new(
418 vec![param.clone()],
419 StandardSet::NPos.into(),
420 )],
421 vec![],
422 (*ss.set).clone(),
423 )
424 .expect("generated sequence fn set uses a fresh parameter")
425 }
426
427 pub fn finite_seq_set_to_fn_set_from_surface_dom_param(
428 &self,
429 fs: &FiniteSeqSet,
430 line_file: LineFile,
431 surface_dom_param: &str,
432 ) -> Result<FnSet, RuntimeError> {
433 let params = vec![ParamGroupWithSet::new(
434 vec![surface_dom_param.to_string()],
435 StandardSet::NPos.into(),
436 )];
437 let dom_facts: Vec<OrAndChainAtomicFact> = vec![OrAndChainAtomicFact::AtomicFact(
438 LessEqualFact::new(
439 Identifier::new(surface_dom_param.to_string()).into(),
440 (*fs.n).clone(),
441 line_file,
442 )
443 .into(),
444 )];
445 self.new_fn_set(params, dom_facts, (*fs.set).clone())
446 }
447
448 pub fn store_well_defined_obj_cache(&mut self, obj: &Obj) {
449 self.top_level_env()
450 .cache_well_defined_obj
451 .insert(obj.to_string(), ());
452 }
453}
454
455impl Runtime {
456 pub fn new_fn_set(
457 &self,
458 params_and_their_sets: impl Into<ParamDefWithSet>,
459 dom_facts: Vec<OrAndChainAtomicFact>,
460 ret_set: Obj,
461 ) -> Result<FnSet, RuntimeError> {
462 let empty: HashMap<String, Obj> = HashMap::new();
463 let mut dom_stored = Vec::with_capacity(dom_facts.len());
464 for d in &dom_facts {
465 dom_stored.push(self.inst_or_and_chain_atomic_fact(
466 d,
467 &empty,
468 ParamObjType::FnSet,
469 None,
470 )?);
471 }
472 let ret_stored = self.inst_obj(&ret_set, &empty, ParamObjType::FnSet)?;
473 Ok(FnSet::new(params_and_their_sets, dom_stored, ret_stored)?)
474 }
475
476 pub fn new_anonymous_fn(
477 &self,
478 params_and_their_sets: impl Into<ParamDefWithSet>,
479 dom_facts: Vec<OrAndChainAtomicFact>,
480 ret_set: Obj,
481 equal_to: Obj,
482 ) -> Result<AnonymousFn, RuntimeError> {
483 let empty: HashMap<String, Obj> = HashMap::new();
484 let mut dom_stored = Vec::with_capacity(dom_facts.len());
485 for d in &dom_facts {
486 dom_stored.push(self.inst_or_and_chain_atomic_fact(
487 d,
488 &empty,
489 ParamObjType::FnSet,
490 None,
491 )?);
492 }
493 let ret_stored = self.inst_obj(&ret_set, &empty, ParamObjType::FnSet)?;
494 let eq_stored = self.inst_obj(&equal_to, &empty, ParamObjType::FnSet)?;
495 Ok(AnonymousFn::new(
496 params_and_their_sets,
497 dom_stored,
498 ret_stored,
499 eq_stored,
500 )?)
501 }
502
503 pub fn fn_set_from_fn_set_clause(&self, clause: &FnSetClause) -> Result<FnSet, RuntimeError> {
504 self.new_fn_set(
505 clause.params_def_with_set.clone(),
506 clause.dom_facts.clone(),
507 clause.ret_set.clone(),
508 )
509 }
510}
511
512impl Runtime {
513 pub fn params_to_arg_map(
514 &self,
515 param_defs: &ParamDefWithType,
516 args: &[Obj],
517 ) -> Result<HashMap<String, Obj>, RuntimeError> {
518 let param_names = param_defs.collect_param_names();
519 if param_names.len() != args.len() {
520 return Err(
521 InstantiateRuntimeError(RuntimeErrorStruct::new_with_just_msg(format!(
522 "params_to_arg_map: expected {} argument(s), got {}",
523 param_names.len(),
524 args.len()
525 )))
526 .into(),
527 );
528 }
529
530 let mut result: HashMap<String, Obj> = HashMap::new();
531 for (param_name, arg) in param_names.iter().zip(args.iter()) {
532 result.insert(param_name.clone(), arg.clone());
533 }
534 Ok(result)
535 }
536}