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::sync::{
21 atomic::{AtomicBool, Ordering},
22 Arc, Mutex,
23};
24use uuid::Uuid;
25
26use crate::execution::{
27 ExecutionStats, ExecutionStreamEntry, ExecutionStreamKind, InputRequest, InputRequestKind,
28 InputResponse, SharedAsyncInputHandler, StdinEvent, StdinEventKind,
29};
30use crate::fusion::{build_fusion_snapshot, FusionPlanSnapshot};
31use crate::profiling::{gather_profiling, reset_provider_telemetry};
32use crate::source_pool::{line_col_from_offset, SourcePool};
33use crate::telemetry::{TelemetryPlatformInfo, TelemetrySink};
34use crate::workspace::{
35 determine_display_label_from_context, execution_display_context, format_type_info,
36 gather_gpu_preview_values, gpu_dtype_label, gpu_size_bytes, last_emit_var_index,
37 last_store_var_index, slice_value_for_preview, workspace_entry, FinalStmtEmitDisposition,
38 MaterializedVariable, WorkspaceEntry, WorkspaceExportMode, WorkspaceMaterializeOptions,
39 WorkspaceMaterializeTarget, WorkspacePreview, WorkspaceResidency, WorkspaceSnapshot,
40 MATERIALIZE_DEFAULT_LIMIT,
41};
42use crate::{
43 approximate_size_bytes, matlab_class_name, numeric_dtype_label, preview_numeric_values,
44 value_shape, CompatMode, RunError,
45};
46
47mod compile;
48mod config;
49mod init;
50mod run;
51mod workspace;
52
53pub struct RunMatSession {
55 #[cfg(feature = "jit")]
57 jit_engine: Option<TurbineEngine>,
58 verbose: bool,
60 stats: ExecutionStats,
62 variable_array: Vec<Value>,
64 workspace_bindings: HashMap<String, SessionWorkspaceBinding>,
66 workspace_values: HashMap<String, Value>,
68 abi_workspace_handle: crate::abi::WorkspaceHandle,
70 active_source_identity: Option<crate::abi::SourceIdentity>,
72 function_registry: runmat_vm::FunctionRegistry,
74 next_semantic_function_id: usize,
75 source_pool: SourcePool,
77 interrupt_flag: Arc<AtomicBool>,
79 is_executing: bool,
81 async_input_handler: Option<SharedAsyncInputHandler>,
84 callstack_limit: usize,
86 error_namespace: String,
88 active_source_name: String,
90 active_source_fullpath_name: Option<String>,
92 pub(crate) telemetry_consent: bool,
93 pub(crate) telemetry_client_id: Option<String>,
94 pub(crate) telemetry_platform: TelemetryPlatformInfo,
95 pub(crate) telemetry_sink: Option<Arc<dyn TelemetrySink>>,
96 workspace_preview_tokens: HashMap<Uuid, WorkspaceMaterializeTicket>,
97 workspace_version: u64,
98 emit_fusion_plan: bool,
99 compat_mode: CompatMode,
100 top_level_await_enabled: bool,
101 dynamic_eval_enabled: bool,
102 format_mode: runmat_builtins::FormatMode,
104 diary_state: runmat_runtime::console::DiaryStateSnapshot,
106 pending_companion_source_discovery: Option<compile::CompanionSourceDiscovery>,
108}
109
110pub(crate) struct PreparedExecution {
111 ast: runmat_parser::Program,
112 lowering: LoweringResult,
113 analysis: runmat_mir::analysis::AnalysisStore,
114 pub(crate) bytecode: runmat_vm::Bytecode,
115 function_registry_after_success: runmat_vm::FunctionRegistry,
116 next_semantic_function_id_after_success: usize,
117}
118
119impl PreparedExecution {
120 #[cfg(test)]
121 pub(crate) fn lowering(&self) -> &LoweringResult {
122 &self.lowering
123 }
124
125 #[cfg(test)]
126 pub(crate) fn analysis(&self) -> &runmat_mir::analysis::AnalysisStore {
127 &self.analysis
128 }
129}
130
131#[derive(Debug, Clone)]
132pub(crate) struct SessionWorkspaceBinding {
133 pub(crate) key: crate::abi::WorkspaceBindingKey,
134 pub(crate) slot: usize,
135}
136
137#[derive(Debug, Clone)]
138struct WorkspaceMaterializeTicket {
139 name: String,
140}
141
142struct ActiveExecutionGuard {
143 flag: *mut bool,
144}
145
146impl ActiveExecutionGuard {
147 fn new(session: &mut RunMatSession) -> Result<Self> {
148 if session.is_executing {
149 Err(anyhow::anyhow!(
150 "RunMatSession is already executing another script"
151 ))
152 } else {
153 session.is_executing = true;
154 Ok(Self {
155 flag: &mut session.is_executing,
156 })
157 }
158 }
159}
160
161impl Drop for ActiveExecutionGuard {
162 fn drop(&mut self) {
163 unsafe {
164 if let Some(flag) = self.flag.as_mut() {
165 *flag = false;
166 }
167 }
168 }
169}
170
171struct SessionDiaryStateGuard {
172 session_state: *mut runmat_runtime::console::DiaryStateSnapshot,
173 previous_state: Option<runmat_runtime::console::DiaryStateSnapshot>,
174}
175
176impl SessionDiaryStateGuard {
177 fn new(session: &mut RunMatSession) -> Self {
178 let previous_state =
179 runmat_runtime::console::replace_diary_state(session.diary_state.clone());
180 Self {
181 session_state: &mut session.diary_state,
182 previous_state: Some(previous_state),
183 }
184 }
185}
186
187impl Drop for SessionDiaryStateGuard {
188 fn drop(&mut self) {
189 let current_state = runmat_runtime::console::diary_state_snapshot();
190 unsafe {
191 if let Some(session_state) = self.session_state.as_mut() {
192 *session_state = current_state;
193 }
194 }
195 if let Some(previous_state) = self.previous_state.take() {
196 runmat_runtime::console::replace_diary_state(previous_state);
197 }
198 }
199}
200
201impl Default for RunMatSession {
202 fn default() -> Self {
203 Self::new().expect("Failed to create default RunMat session")
204 }
205}