1use anyhow::Result;
2use runmat_builtins::{self, Value};
3use runmat_gc::{gc_configure, gc_stats, GcConfig};
4#[cfg(feature = "jit")]
5use tracing::warn;
6use tracing::{debug, info, info_span};
7
8use runmat_hir::{LoweringContext, LoweringResult, SourceId};
9use runmat_lexer::{tokenize_detailed, Token as LexToken};
10use runmat_parser::{parse_with_options, ParserOptions};
11use runmat_runtime::{build_runtime_error, gather_if_needed_async, RuntimeError};
12use runmat_runtime::{
13 runtime_export_workspace_state, runtime_import_workspace_state, WorkspaceReplayMode,
14};
15use runmat_time::Instant;
16#[cfg(feature = "jit")]
17use runmat_turbine::TurbineEngine;
18use std::collections::{HashMap, HashSet};
19use std::future::Future;
20use std::path::PathBuf;
21use std::sync::{
22 atomic::{AtomicBool, Ordering},
23 Arc, Mutex,
24};
25use uuid::Uuid;
26
27use crate::execution::{
28 ExecutionStats, ExecutionStreamEntry, ExecutionStreamKind, InputRequest, InputRequestKind,
29 InputResponse, SharedAsyncInputHandler, StdinEvent, StdinEventKind,
30};
31use crate::fusion::{build_fusion_snapshot, FusionPlanSnapshot};
32use crate::profiling::{gather_profiling, reset_provider_telemetry};
33use crate::source_pool::{line_col_from_offset, SourcePool};
34use crate::telemetry::{TelemetryPlatformInfo, TelemetrySink};
35use crate::workspace::{
36 determine_display_label_from_context, execution_display_context, format_type_info,
37 gather_gpu_preview_values, gpu_dtype_label, gpu_size_bytes, last_emit_var_index,
38 last_store_var_index, slice_value_for_preview, workspace_entry, FinalStmtEmitDisposition,
39 MaterializedVariable, WorkspaceEntry, WorkspaceExportMode, WorkspaceMaterializeOptions,
40 WorkspaceMaterializeTarget, WorkspacePreview, WorkspaceResidency, WorkspaceSnapshot,
41 MATERIALIZE_DEFAULT_LIMIT,
42};
43use crate::{
44 approximate_size_bytes, matlab_class_name, numeric_dtype_label, preview_numeric_values,
45 value_shape, CompatMode, RunError,
46};
47
48mod compile;
49mod config;
50mod init;
51mod run;
52mod workspace;
53
54pub struct RunMatSession {
56 #[cfg(feature = "jit")]
58 jit_engine: Option<TurbineEngine>,
59 verbose: bool,
61 stats: ExecutionStats,
63 variable_array: Vec<Value>,
65 workspace_bindings: HashMap<String, SessionWorkspaceBinding>,
67 workspace_values: HashMap<String, Value>,
69 abi_workspace_handle: crate::abi::WorkspaceHandle,
71 active_source_identity: Option<crate::abi::SourceIdentity>,
73 function_registry: runmat_vm::FunctionRegistry,
75 next_semantic_function_id: usize,
76 search_path: Arc<runmat_runtime::builtins::common::path_state::SearchPath>,
78 dynamic_function_cache: Arc<Mutex<HashMap<PathBuf, DynamicFunctionCacheEntry>>>,
80 source_pool: SourcePool,
82 interrupt_flag: Arc<AtomicBool>,
84 is_executing: bool,
86 async_input_handler: Option<SharedAsyncInputHandler>,
89 callstack_limit: usize,
91 error_namespace: String,
93 active_source_name: String,
95 active_source_fullpath_name: Option<String>,
97 pub(crate) telemetry_consent: bool,
98 pub(crate) telemetry_client_id: Option<String>,
99 pub(crate) telemetry_platform: TelemetryPlatformInfo,
100 pub(crate) telemetry_sink: Option<Arc<dyn TelemetrySink>>,
101 workspace_preview_tokens: HashMap<Uuid, WorkspaceMaterializeTicket>,
102 workspace_version: u64,
103 emit_fusion_plan: bool,
104 compat_mode: CompatMode,
105 top_level_await_enabled: bool,
106 dynamic_eval_enabled: bool,
107 format_mode: runmat_builtins::FormatMode,
109 diary_state: runmat_runtime::console::DiaryStateSnapshot,
111 pending_companion_source_discovery: Option<compile::CompanionSourceDiscovery>,
113}
114
115pub(crate) struct PreparedExecution {
116 ast: runmat_parser::Program,
117 lowering: LoweringResult,
118 analysis: runmat_mir::analysis::AnalysisStore,
119 pub(crate) bytecode: runmat_vm::Bytecode,
120 function_registry_after_success: runmat_vm::FunctionRegistry,
121 next_semantic_function_id_after_success: usize,
122}
123
124impl PreparedExecution {
125 #[cfg(test)]
126 pub(crate) fn lowering(&self) -> &LoweringResult {
127 &self.lowering
128 }
129
130 #[cfg(test)]
131 pub(crate) fn analysis(&self) -> &runmat_mir::analysis::AnalysisStore {
132 &self.analysis
133 }
134}
135
136#[derive(Debug, Clone)]
137pub(crate) struct SessionWorkspaceBinding {
138 pub(crate) key: crate::abi::WorkspaceBindingKey,
139 pub(crate) slot: usize,
140}
141
142#[derive(Debug, Clone)]
143struct WorkspaceMaterializeTicket {
144 name: String,
145}
146
147#[derive(Clone)]
148struct DynamicFunctionCacheEntry {
149 source_text: String,
150 registry: Arc<runmat_vm::FunctionRegistry>,
151}
152
153struct ActiveExecutionGuard {
154 flag: *mut bool,
155}
156
157impl ActiveExecutionGuard {
158 fn new(session: &mut RunMatSession) -> Result<Self> {
159 if session.is_executing {
160 Err(anyhow::anyhow!(
161 "RunMatSession is already executing another script"
162 ))
163 } else {
164 session.is_executing = true;
165 Ok(Self {
166 flag: &mut session.is_executing,
167 })
168 }
169 }
170}
171
172impl Drop for ActiveExecutionGuard {
173 fn drop(&mut self) {
174 unsafe {
175 if let Some(flag) = self.flag.as_mut() {
176 *flag = false;
177 }
178 }
179 }
180}
181
182struct SessionDiaryStateGuard {
183 session_state: *mut runmat_runtime::console::DiaryStateSnapshot,
184 previous_state: Option<runmat_runtime::console::DiaryStateSnapshot>,
185}
186
187impl SessionDiaryStateGuard {
188 fn new(session: &mut RunMatSession) -> Self {
189 let previous_state =
190 runmat_runtime::console::replace_diary_state(session.diary_state.clone());
191 Self {
192 session_state: &mut session.diary_state,
193 previous_state: Some(previous_state),
194 }
195 }
196}
197
198impl Drop for SessionDiaryStateGuard {
199 fn drop(&mut self) {
200 let current_state = runmat_runtime::console::diary_state_snapshot();
201 unsafe {
202 if let Some(session_state) = self.session_state.as_mut() {
203 *session_state = current_state;
204 }
205 }
206 if let Some(previous_state) = self.previous_state.take() {
207 runmat_runtime::console::replace_diary_state(previous_state);
208 }
209 }
210}
211
212impl Default for RunMatSession {
213 fn default() -> Self {
214 Self::new().expect("Failed to create default RunMat session")
215 }
216}