runmat_core/session/
compile.rs1use super::*;
2
3impl RunMatSession {
4 pub(crate) fn compile_input(
5 &mut self,
6 input: &str,
7 ) -> std::result::Result<PreparedExecution, RunError> {
8 let source_name = self.current_source_name().to_string();
9 let source_id = self.source_pool.intern(&source_name, input);
10 let ast = {
11 let _span = info_span!("runtime.parse").entered();
12 parse_with_options(input, ParserOptions::new(self.compat_mode))?
13 };
14 let lowering = {
15 let _span = info_span!("runtime.lower").entered();
16 runmat_hir::lower(
17 &ast,
18 &LoweringContext::new(&self.variable_names, &self.function_definitions),
19 )?
20 };
21 let existing_functions = self.convert_hir_functions_to_user_functions();
22 let mut bytecode = {
23 let _span = info_span!("runtime.compile.bytecode").entered();
24 runmat_vm::compile(&lowering.hir, &existing_functions)?
25 };
26 bytecode.source_id = Some(source_id);
27 let new_function_names: HashSet<String> = lowering.functions.keys().cloned().collect();
28 for (name, func) in bytecode.functions.iter_mut() {
29 if new_function_names.contains(name) {
30 func.source_id = Some(source_id);
31 }
32 }
33 Ok(PreparedExecution {
34 ast,
35 lowering,
36 bytecode,
37 })
38 }
39
40 pub(crate) fn populate_callstack(&self, error: &mut RuntimeError) {
41 if !error.context.call_stack.is_empty() || error.context.call_frames.is_empty() {
42 return;
43 }
44 let mut rendered = Vec::new();
45 if error.context.call_frames_elided > 0 {
46 rendered.push(format!(
47 "... {} frames elided ...",
48 error.context.call_frames_elided
49 ));
50 }
51 for frame in error.context.call_frames.iter().rev() {
52 let mut line = frame.function.clone();
53 if let (Some(source_id), Some((start, _end))) = (frame.source_id, frame.span) {
54 if let Some(source) = self.source_pool.get(SourceId(source_id)) {
55 let (line_num, col) = line_col_from_offset(&source.text, start);
56 line = format!("{} @ {}:{}:{}", frame.function, source.name, line_num, col);
57 }
58 }
59 rendered.push(line);
60 }
61 error.context.call_stack = rendered;
62 }
63
64 pub(crate) fn normalize_error_namespace(&self, error: &mut RuntimeError) {
65 let Some(identifier) = error.identifier.clone() else {
66 return;
67 };
68 let suffix = identifier
69 .split_once(':')
70 .map(|(_, suffix)| suffix)
71 .unwrap_or(identifier.as_str());
72 error.identifier = Some(format!("{}:{suffix}", self.error_namespace));
73 }
74
75 pub fn compile_fusion_plan(
77 &mut self,
78 input: &str,
79 ) -> std::result::Result<Option<FusionPlanSnapshot>, RunError> {
80 let prepared = self.compile_input(input)?;
81 Ok(build_fusion_snapshot(
82 prepared.bytecode.accel_graph.as_ref(),
83 &prepared.bytecode.fusion_groups,
84 ))
85 }
86
87 pub(crate) fn prepare_variable_array_for_execution(
88 &mut self,
89 bytecode: &runmat_vm::Bytecode,
90 updated_var_mapping: &HashMap<String, usize>,
91 debug_trace: bool,
92 ) {
93 let max_var_id = updated_var_mapping.values().copied().max().unwrap_or(0);
95 let required_len = std::cmp::max(bytecode.var_count, max_var_id + 1);
96 let mut new_variable_array = vec![Value::Num(0.0); required_len];
97 if debug_trace {
98 debug!(
99 bytecode_var_count = bytecode.var_count,
100 required_len, max_var_id, "[repl] prepare variable array"
101 );
102 }
103
104 for (var_name, &new_var_id) in updated_var_mapping {
106 if new_var_id < new_variable_array.len() {
107 if let Some(value) = self.workspace_values.get(var_name) {
108 if debug_trace {
109 debug!(
110 var_name,
111 var_id = new_var_id,
112 ?value,
113 "[repl] prepare set var"
114 );
115 }
116 new_variable_array[new_var_id] = value.clone();
117 }
118 } else if debug_trace {
119 debug!(
120 var_name,
121 var_id = new_var_id,
122 len = new_variable_array.len(),
123 "[repl] prepare skipping var"
124 );
125 }
126 }
127
128 self.variable_array = new_variable_array;
130 }
131
132 fn convert_hir_functions_to_user_functions(&self) -> HashMap<String, runmat_vm::UserFunction> {
134 let mut user_functions = HashMap::new();
135
136 for (name, hir_stmt) in &self.function_definitions {
137 if let runmat_hir::HirStmt::Function {
138 name: func_name,
139 params,
140 outputs,
141 body,
142 has_varargin: _,
143 has_varargout: _,
144 ..
145 } = hir_stmt
146 {
147 let var_map =
149 runmat_hir::remapping::create_complete_function_var_map(params, outputs, body);
150 let max_local_var = var_map.len();
151
152 let source_id = self.function_source_ids.get(name).copied();
153 if let Some(id) = source_id {
154 if let Some(source) = self.source_pool.get(id) {
155 let _ = (&source.name, &source.text);
156 }
157 }
158 let user_func = runmat_vm::UserFunction {
159 name: func_name.clone(),
160 params: params.clone(),
161 outputs: outputs.clone(),
162 body: body.clone(),
163 local_var_count: max_local_var,
164 has_varargin: false,
165 has_varargout: false,
166 var_types: vec![Type::Unknown; max_local_var],
167 source_id,
168 };
169 user_functions.insert(name.clone(), user_func);
170 }
171 }
172
173 user_functions
174 }
175}