1use anyhow::Result;
2use runmat_builtins::{self, Value};
3use runmat_gc::{gc_configure, gc_stats, GcConfig};
4use tracing::{debug, info, info_span, warn};
5
6use runmat_hir::{LoweringContext, LoweringResult, SourceId};
7use runmat_lexer::{tokenize_detailed, Token as LexToken};
8use runmat_parser::{parse_with_options, ParserOptions};
9use runmat_runtime::{build_runtime_error, gather_if_needed_async, RuntimeError};
10use runmat_runtime::{
11 runtime_export_workspace_state, runtime_import_workspace_state, WorkspaceReplayMode,
12};
13#[cfg(target_arch = "wasm32")]
14use runmat_snapshot::SnapshotBuilder;
15use runmat_snapshot::{Snapshot, SnapshotConfig, SnapshotLoader};
16use runmat_time::Instant;
17#[cfg(feature = "jit")]
18use runmat_turbine::TurbineEngine;
19use std::collections::{HashMap, HashSet};
20use std::future::Future;
21#[cfg(not(target_arch = "wasm32"))]
22use std::path::Path;
23use std::rc::Rc;
24use std::sync::{
25 atomic::{AtomicBool, Ordering},
26 Arc, Mutex,
27};
28use uuid::Uuid;
29
30use crate::execution::{
31 ExecutionStats, ExecutionStreamEntry, ExecutionStreamKind, InputRequest, InputRequestKind,
32 InputResponse, SharedAsyncInputHandler, StdinEvent, StdinEventKind,
33};
34use crate::fusion::{build_fusion_snapshot, FusionPlanSnapshot};
35use crate::profiling::{gather_profiling, reset_provider_telemetry};
36use crate::source_pool::{line_col_from_offset, SourcePool};
37use crate::telemetry::{TelemetryPlatformInfo, TelemetrySink};
38use crate::workspace::{
39 determine_display_label_from_context, execution_display_context, format_type_info,
40 gather_gpu_preview_values, gpu_dtype_label, gpu_size_bytes, last_emit_var_index,
41 last_store_var_index, slice_value_for_preview, workspace_entry, FinalStmtEmitDisposition,
42 MaterializedVariable, WorkspaceEntry, WorkspaceExportMode, WorkspaceMaterializeOptions,
43 WorkspaceMaterializeTarget, WorkspacePreview, WorkspaceResidency, WorkspaceSnapshot,
44 MATERIALIZE_DEFAULT_LIMIT,
45};
46use crate::{
47 approximate_size_bytes, matlab_class_name, numeric_dtype_label, preview_numeric_values,
48 value_shape, CompatMode, RunError,
49};
50
51mod compile;
52mod config;
53mod run;
54mod snapshot;
55mod workspace;
56
57pub struct RunMatSession {
59 #[cfg(feature = "jit")]
61 jit_engine: Option<TurbineEngine>,
62 verbose: bool,
64 stats: ExecutionStats,
66 variable_array: Vec<Value>,
68 workspace_bindings: HashMap<String, SessionWorkspaceBinding>,
70 workspace_values: HashMap<String, Value>,
72 abi_workspace_handle: crate::abi::WorkspaceHandle,
74 active_source_identity: Option<crate::abi::SourceIdentity>,
76 function_registry: runmat_vm::FunctionRegistry,
78 next_semantic_function_id: usize,
79 source_pool: SourcePool,
81 snapshot: Option<Rc<Snapshot>>,
83 interrupt_flag: Arc<AtomicBool>,
85 is_executing: bool,
87 async_input_handler: Option<SharedAsyncInputHandler>,
90 callstack_limit: usize,
92 error_namespace: String,
94 active_source_name: String,
96 active_source_fullpath_name: Option<String>,
98 pub(crate) telemetry_consent: bool,
99 pub(crate) telemetry_client_id: Option<String>,
100 pub(crate) telemetry_platform: TelemetryPlatformInfo,
101 pub(crate) telemetry_sink: Option<Arc<dyn TelemetrySink>>,
102 workspace_preview_tokens: HashMap<Uuid, WorkspaceMaterializeTicket>,
103 workspace_version: u64,
104 emit_fusion_plan: bool,
105 compat_mode: CompatMode,
106 top_level_await_enabled: bool,
107 dynamic_eval_enabled: bool,
108 format_mode: runmat_builtins::FormatMode,
110 pending_companion_source_discovery: Option<compile::CompanionSourceDiscovery>,
112}
113
114pub(crate) struct PreparedExecution {
115 ast: runmat_parser::Program,
116 lowering: LoweringResult,
117 analysis: runmat_mir::analysis::AnalysisStore,
118 pub(crate) bytecode: runmat_vm::Bytecode,
119 function_registry_after_success: runmat_vm::FunctionRegistry,
120 next_semantic_function_id_after_success: usize,
121}
122
123impl PreparedExecution {
124 #[cfg(test)]
125 pub(crate) fn lowering(&self) -> &LoweringResult {
126 &self.lowering
127 }
128
129 #[cfg(test)]
130 pub(crate) fn analysis(&self) -> &runmat_mir::analysis::AnalysisStore {
131 &self.analysis
132 }
133}
134
135#[derive(Debug, Clone)]
136pub(crate) struct SessionWorkspaceBinding {
137 pub(crate) key: crate::abi::WorkspaceBindingKey,
138 pub(crate) slot: usize,
139}
140
141#[derive(Debug, Clone)]
142struct WorkspaceMaterializeTicket {
143 name: String,
144}
145
146struct ActiveExecutionGuard {
147 flag: *mut bool,
148}
149
150impl ActiveExecutionGuard {
151 fn new(session: &mut RunMatSession) -> Result<Self> {
152 if session.is_executing {
153 Err(anyhow::anyhow!(
154 "RunMatSession is already executing another script"
155 ))
156 } else {
157 session.is_executing = true;
158 Ok(Self {
159 flag: &mut session.is_executing,
160 })
161 }
162 }
163}
164
165impl Drop for ActiveExecutionGuard {
166 fn drop(&mut self) {
167 unsafe {
168 if let Some(flag) = self.flag.as_mut() {
169 *flag = false;
170 }
171 }
172 }
173}
174
175impl Default for RunMatSession {
176 fn default() -> Self {
177 Self::new().expect("Failed to create default RunMat session")
178 }
179}