use anyhow::{Context, Result};
use clap::{Parser, Subcommand, ValueEnum};
use env_logger::Env;
use log::{debug, error, info};
mod config;
use config::{ConfigLoader, PlotBackend, PlotMode, RunMatConfig};
use runmat_builtins::Value;
use runmat_gc::{
gc_allocate, gc_collect_major, gc_collect_minor, gc_get_config, gc_stats, GcConfig,
};
use runmat_kernel::{ConnectionInfo, KernelConfig, KernelServer};
use runmat_repl::ReplEngine;
use runmat_snapshot::presets::SnapshotPreset;
use runmat_snapshot::{SnapshotBuilder, SnapshotConfig, SnapshotLoader};
use std::fs;
use std::path::PathBuf;
use std::time::Duration;
#[derive(Parser)]
#[command(
name = "runmat",
version = "0.0.2",
about = "High-performance MATLAB/Octave code runtime",
long_about = r#"
RunMat is a modern, high-performance runtime for MATLAB/Octave code built
by Dystr (https://dystr.com).
It is built in Rust, and features a V8-inspired tiered execution model with a
baseline interpreter feeding an optimizing JIT compiler built on Cranelift.
Key features:
• JIT compilation with Cranelift for optimal performance
• Generational garbage collection with configurable policies
• High-performance BLAS/LAPACK operations
• Jupyter kernel protocol support with async execution
• Fast startup with snapshotting capabilities
• World-class error messages and debugging
• Compatible with MATLAB/Octave syntax and semantics
Performance Features:
• Multi-tier execution: interpreter + JIT compiler
• Adaptive optimization based on hotspot profiling
• Generational GC with write barriers and concurrent collection
• SIMD-optimized mathematical operations
• Zero-copy memory management where possible
Examples:
runmat # Start interactive REPL with JIT
runmat --no-jit # Start REPL with interpreter only
runmat --gc-preset low-latency # Optimize GC for low latency
runmat script.m # Execute MATLAB/Octave script
runmat --install-kernel # Install as Jupyter kernel
runmat kernel # Start Jupyter kernel
runmat kernel-connection connection.json # Start with connection file
runmat --version --detailed # Show detailed version information
"#,
after_help = r#"
Environment Variables:
RUSTMAT_DEBUG=1 Enable debug logging
RUSTMAT_LOG_LEVEL=debug Set log level (error, warn, info, debug, trace)
RUSTMAT_KERNEL_IP=127.0.0.1 Kernel IP address
RUSTMAT_KERNEL_KEY=<key> Kernel authentication key
RUSTMAT_TIMEOUT=300 Execution timeout in seconds
RUSTMAT_CONFIG=<path> Path to configuration file
RUSTMAT_SNAPSHOT_PATH=<path> Snapshot file to preload standard library
Garbage Collector:
RUSTMAT_GC_PRESET=<preset> GC preset (low-latency, high-throughput, low-memory, debug)
RUSTMAT_GC_YOUNG_SIZE=<mb> Young generation size in MB
RUSTMAT_GC_THREADS=<n> Number of GC threads
JIT Compiler:
RUSTMAT_JIT_ENABLE=1 Enable JIT compilation (default: true)
RUSTMAT_JIT_THRESHOLD=<n> JIT compilation threshold (default: 10)
RUSTMAT_JIT_OPT_LEVEL=<0-3> JIT optimization level (default: 2)
For more information, visit: https://github.com/runmat-org/runmat
"#
)]
#[command(propagate_version = true)]
struct Cli {
#[arg(short, long, env = "RUSTMAT_DEBUG", value_parser = parse_bool_env)]
debug: bool,
#[arg(long, value_enum, env = "RUSTMAT_LOG_LEVEL", default_value = "info", value_parser = parse_log_level_env)]
log_level: LogLevel,
#[arg(long, env = "RUSTMAT_TIMEOUT", default_value = "300")]
timeout: u64,
#[arg(long, env = "RUSTMAT_CONFIG")]
config: Option<PathBuf>,
#[arg(long, env = "RUSTMAT_JIT_DISABLE", value_parser = parse_bool_env)]
no_jit: bool,
#[arg(long, env = "RUSTMAT_JIT_THRESHOLD", default_value = "10")]
jit_threshold: u32,
#[arg(
long,
value_enum,
env = "RUSTMAT_JIT_OPT_LEVEL",
default_value = "speed"
)]
jit_opt_level: OptLevel,
#[arg(long, value_enum, env = "RUSTMAT_GC_PRESET")]
gc_preset: Option<GcPreset>,
#[arg(long, env = "RUSTMAT_GC_YOUNG_SIZE")]
gc_young_size: Option<usize>,
#[arg(long, env = "RUSTMAT_GC_THREADS")]
gc_threads: Option<usize>,
#[arg(long, env = "RUSTMAT_GC_STATS", value_parser = parse_bool_env)]
gc_stats: bool,
#[arg(short, long)]
verbose: bool,
#[arg(long, env = "RUSTMAT_SNAPSHOT_PATH")]
snapshot: Option<PathBuf>,
#[arg(long, value_enum, env = "RUSTMAT_PLOT_MODE")]
plot_mode: Option<PlotMode>,
#[arg(long, env = "RUSTMAT_PLOT_HEADLESS", value_parser = parse_bool_env)]
plot_headless: bool,
#[arg(long, value_enum, env = "RUSTMAT_PLOT_BACKEND")]
plot_backend: Option<PlotBackend>,
#[arg(long)]
generate_config: bool,
#[arg(long)]
install_kernel: bool,
#[command(subcommand)]
command: Option<Commands>,
script: Option<PathBuf>,
}
#[derive(Subcommand, Clone)]
enum Commands {
Repl {
#[arg(short, long)]
verbose: bool,
},
Kernel {
#[arg(long, env = "RUSTMAT_KERNEL_IP", default_value = "127.0.0.1")]
ip: String,
#[arg(long, env = "RUSTMAT_KERNEL_KEY")]
key: Option<String>,
#[arg(long, default_value = "tcp")]
transport: String,
#[arg(long, default_value = "hmac-sha256")]
signature_scheme: String,
#[arg(long, env = "RUSTMAT_SHELL_PORT", default_value = "0")]
shell_port: u16,
#[arg(long, env = "RUSTMAT_IOPUB_PORT", default_value = "0")]
iopub_port: u16,
#[arg(long, env = "RUSTMAT_STDIN_PORT", default_value = "0")]
stdin_port: u16,
#[arg(long, env = "RUSTMAT_CONTROL_PORT", default_value = "0")]
control_port: u16,
#[arg(long, env = "RUSTMAT_HB_PORT", default_value = "0")]
hb_port: u16,
#[arg(long)]
connection_file: Option<PathBuf>,
},
KernelConnection {
connection_file: PathBuf,
},
Run {
file: PathBuf,
#[arg(last = true)]
args: Vec<String>,
},
Version {
#[arg(long)]
detailed: bool,
},
Info,
Gc {
#[command(subcommand)]
gc_command: GcCommand,
},
Benchmark {
file: PathBuf,
#[arg(short, long, default_value = "10")]
iterations: u32,
#[arg(long)]
jit: bool,
},
Snapshot {
#[command(subcommand)]
snapshot_command: SnapshotCommand,
},
Plot {
#[arg(long, value_enum)]
mode: Option<PlotMode>,
#[arg(long)]
width: Option<u32>,
#[arg(long)]
height: Option<u32>,
},
Config {
#[command(subcommand)]
config_command: ConfigCommand,
},
Pkg {
#[command(subcommand)]
pkg_command: PkgCommand,
},
}
#[derive(Subcommand, Clone)]
enum GcCommand {
Stats,
Minor,
Major,
Config,
Stress {
#[arg(short, long, default_value = "10000")]
allocations: usize,
},
}
#[derive(Subcommand, Clone)]
enum SnapshotCommand {
Create {
#[arg(short, long)]
output: PathBuf,
#[arg(short = 'O', long, value_enum, default_value = "speed")]
optimization: OptLevel,
#[arg(short, long, value_enum)]
compression: Option<CompressionAlg>,
},
Info {
snapshot: PathBuf,
},
Presets,
Validate {
snapshot: PathBuf,
},
}
#[derive(Subcommand, Clone)]
enum ConfigCommand {
Show,
Generate {
#[arg(short, long, default_value = ".runmat.yaml")]
output: PathBuf,
},
Validate {
config_file: PathBuf,
},
Paths,
}
#[derive(Subcommand, Clone)]
enum PkgCommand {
Add { name: String },
Remove { name: String },
Install,
Update,
Publish,
}
#[derive(Clone, Debug, ValueEnum)]
enum CompressionAlg {
None,
Lz4,
Zstd,
}
#[derive(Clone, ValueEnum)]
enum LogLevel {
Error,
Warn,
Info,
Debug,
Trace,
}
#[derive(Clone, Debug, ValueEnum)]
enum OptLevel {
None,
Size,
Speed,
Aggressive,
}
#[derive(Clone, Debug, ValueEnum)]
enum GcPreset {
LowLatency,
HighThroughput,
LowMemory,
Debug,
}
impl From<LogLevel> for log::LevelFilter {
fn from(level: LogLevel) -> Self {
match level {
LogLevel::Error => log::LevelFilter::Error,
LogLevel::Warn => log::LevelFilter::Warn,
LogLevel::Info => log::LevelFilter::Info,
LogLevel::Debug => log::LevelFilter::Debug,
LogLevel::Trace => log::LevelFilter::Trace,
}
}
}
impl From<GcPreset> for GcConfig {
fn from(preset: GcPreset) -> Self {
match preset {
GcPreset::LowLatency => GcConfig::low_latency(),
GcPreset::HighThroughput => GcConfig::high_throughput(),
GcPreset::LowMemory => GcConfig::low_memory(),
GcPreset::Debug => GcConfig::debug(),
}
}
}
fn parse_bool_env(s: &str) -> Result<bool, String> {
match s.to_lowercase().as_str() {
"1" | "true" | "yes" | "on" => Ok(true),
"0" | "false" | "no" | "off" => Ok(false),
"" => Ok(false), _ => Err(format!(
"Invalid boolean value '{s}'. Expected: 1/0, true/false, yes/no, on/off"
)),
}
}
fn parse_log_level_env(s: &str) -> Result<LogLevel, String> {
if s.is_empty() {
return Ok(LogLevel::Info); }
match s.to_lowercase().as_str() {
"error" => Ok(LogLevel::Error),
"warn" => Ok(LogLevel::Warn),
"info" => Ok(LogLevel::Info),
"debug" => Ok(LogLevel::Debug),
"trace" => Ok(LogLevel::Trace),
_ => Err(format!(
"Invalid log level '{s}'. Expected: error, warn, info, debug, trace"
)),
}
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
if cli.generate_config {
let sample_config = ConfigLoader::generate_sample_config();
println!("{sample_config}");
return Ok(());
}
if cli.install_kernel {
return install_jupyter_kernel().await;
}
let mut config = match load_configuration(&cli) {
Ok(c) => c,
Err(e) => {
if matches!(cli.command, Some(Commands::Pkg { .. })) {
eprintln!("Warning: {e}. Using default configuration for pkg command.");
RunMatConfig::default()
} else {
return Err(e);
}
}
};
apply_cli_overrides(&mut config, &cli);
let log_level = if config.logging.debug || cli.debug {
log::LevelFilter::Debug
} else {
match config.logging.level {
config::LogLevel::Error => log::LevelFilter::Error,
config::LogLevel::Warn => log::LevelFilter::Warn,
config::LogLevel::Info => log::LevelFilter::Info,
config::LogLevel::Debug => log::LevelFilter::Debug,
config::LogLevel::Trace => log::LevelFilter::Trace,
}
};
env_logger::Builder::from_env(Env::default().default_filter_or("info"))
.filter_level(log_level)
.init();
runmat_accelerate::simple_provider::register_inprocess_provider();
info!("RunMat v{} starting", env!("CARGO_PKG_VERSION"));
debug!("Configuration loaded: {config:?}");
configure_gc_from_config(&config)?;
let _gui_initialized = if config.plotting.mode == PlotMode::Gui
|| (config.plotting.mode == PlotMode::Auto && !config.plotting.force_headless)
{
info!("Initializing GUI plotting system");
runmat_plot::register_main_thread();
match runmat_plot::gui::initialize_native_window() {
Ok(()) => {
info!("Native window system initialized successfully");
}
Err(e) => {
info!("Native window initialization failed: {e}, using thread manager");
}
}
match runmat_plot::initialize_gui_manager() {
Ok(()) => {
info!("GUI thread manager initialized successfully");
match runmat_plot::health_check_global() {
Ok(result) => {
info!("GUI system health check: {result}");
true
}
Err(e) => {
error!("GUI system health check failed: {e}");
true
}
}
}
Err(e) => {
error!("Failed to initialize GUI thread manager: {e}");
false
}
}
} else {
false
};
let command = cli.command.clone();
let script = cli.script.clone();
match (command, script) {
(Some(command), None) => execute_command(command, &cli, &config).await,
(None, Some(script)) => execute_script(script, &cli, &config).await,
(None, None) => {
execute_repl(&config).await
}
(Some(_), Some(_)) => {
error!("Cannot specify both command and script file");
std::process::exit(1);
}
}
}
fn load_configuration(cli: &Cli) -> Result<RunMatConfig> {
let config_from_env = std::env::var("RUSTMAT_CONFIG").ok().map(PathBuf::from);
if let Some(config_file) = &cli.config {
let is_from_env = config_from_env.as_ref() == Some(config_file);
if config_file.exists() {
if config_file.is_dir() {
info!(
"Config path is a directory, ignoring: {}",
config_file.display()
);
} else {
info!("Loading configuration from: {}", config_file.display());
return ConfigLoader::load_from_file(config_file);
}
} else if !is_from_env {
error!(
"Specified config file does not exist: {}",
config_file.display()
);
std::process::exit(1);
}
}
match ConfigLoader::load() {
Ok(c) => Ok(c),
Err(e) => {
if let Ok(conf_env) = std::env::var("RUSTMAT_CONFIG") {
let p = PathBuf::from(conf_env);
if p.is_dir() {
info!(
"Config path from env is a directory, ignoring: {}",
p.display()
);
return Ok(RunMatConfig::default());
}
}
if let Some(home) = dirs::home_dir() {
let dir = home.join(".runmat");
if dir.is_dir() {
info!(
"Home config path is a directory, ignoring: {}",
dir.display()
);
return Ok(RunMatConfig::default());
}
}
Err(e)
}
}
}
fn apply_cli_overrides(config: &mut RunMatConfig, cli: &Cli) {
if cli.no_jit {
config.jit.enabled = false;
}
config.jit.threshold = cli.jit_threshold;
config.jit.optimization_level = match cli.jit_opt_level {
OptLevel::None => config::JitOptLevel::None,
OptLevel::Size => config::JitOptLevel::Size,
OptLevel::Speed => config::JitOptLevel::Speed,
OptLevel::Aggressive => config::JitOptLevel::Aggressive,
};
config.runtime.timeout = cli.timeout;
config.runtime.verbose = cli.verbose;
if let Some(snapshot) = &cli.snapshot {
config.runtime.snapshot_path = Some(snapshot.clone());
}
if let Some(preset) = &cli.gc_preset {
config.gc.preset = Some(match preset {
GcPreset::LowLatency => config::GcPreset::LowLatency,
GcPreset::HighThroughput => config::GcPreset::HighThroughput,
GcPreset::LowMemory => config::GcPreset::LowMemory,
GcPreset::Debug => config::GcPreset::Debug,
});
}
if let Some(young_size) = cli.gc_young_size {
config.gc.young_size_mb = Some(young_size);
}
if let Some(threads) = cli.gc_threads {
config.gc.threads = Some(threads);
}
config.gc.collect_stats = cli.gc_stats;
if let Some(plot_mode) = &cli.plot_mode {
config.plotting.mode = *plot_mode;
let env_value = match plot_mode {
PlotMode::Auto => "auto",
PlotMode::Gui => "gui",
PlotMode::Headless => "headless",
PlotMode::Jupyter => "jupyter",
};
std::env::set_var("RUSTMAT_PLOT_MODE", env_value);
}
if cli.plot_headless {
config.plotting.force_headless = true;
std::env::set_var("RUSTMAT_PLOT_MODE", "headless");
}
if let Some(backend) = &cli.plot_backend {
config.plotting.backend = *backend;
}
config.logging.debug = cli.debug;
config.logging.level = match cli.log_level {
LogLevel::Error => config::LogLevel::Error,
LogLevel::Warn => config::LogLevel::Warn,
LogLevel::Info => config::LogLevel::Info,
LogLevel::Debug => config::LogLevel::Debug,
LogLevel::Trace => config::LogLevel::Trace,
};
}
fn configure_gc_from_config(config: &RunMatConfig) -> Result<()> {
let mut gc_config = if let Some(preset) = &config.gc.preset {
(*preset).into()
} else {
runmat_gc::GcConfig::default()
};
if let Some(young_size) = config.gc.young_size_mb {
gc_config.young_generation_size = young_size * 1024 * 1024; }
if let Some(threads) = config.gc.threads {
gc_config.max_gc_threads = threads;
}
gc_config.collect_statistics = config.gc.collect_stats;
gc_config.verbose_logging = config.logging.debug || config.runtime.verbose;
info!(
"Configuring GC with preset: {:?}",
config
.gc
.preset
.map(|p| format!("{p:?}"))
.unwrap_or_else(|| "default".to_string())
);
debug!(
"GC Configuration: young_gen={}MB, threads={}, stats={}",
gc_config.young_generation_size / 1024 / 1024,
gc_config.max_gc_threads,
gc_config.collect_statistics
);
runmat_gc::gc_configure(gc_config).context("Failed to configure garbage collector")?;
Ok(())
}
async fn execute_command(command: Commands, cli: &Cli, config: &RunMatConfig) -> Result<()> {
match command {
Commands::Repl { verbose } => {
let mut repl_config = config.clone();
repl_config.runtime.verbose = verbose || config.runtime.verbose;
execute_repl(&repl_config).await
}
Commands::Kernel {
ip,
key,
transport,
signature_scheme,
shell_port,
iopub_port,
stdin_port,
control_port,
hb_port,
connection_file,
} => {
execute_kernel(
ip,
key,
transport,
signature_scheme,
shell_port,
iopub_port,
stdin_port,
control_port,
hb_port,
connection_file,
cli.timeout,
)
.await
}
Commands::KernelConnection { connection_file } => {
execute_kernel_with_connection(connection_file, cli.timeout).await
}
Commands::Run { file, args } => execute_script_with_args(file, args, cli, config).await,
Commands::Version { detailed } => {
show_version(detailed);
Ok(())
}
Commands::Info => show_system_info(cli).await,
Commands::Gc { gc_command } => execute_gc_command(gc_command).await,
Commands::Benchmark {
file,
iterations,
jit,
} => execute_benchmark(file, iterations, jit, cli).await,
Commands::Snapshot { snapshot_command } => execute_snapshot_command(snapshot_command).await,
Commands::Plot {
mode,
width,
height,
} => execute_plot_command(mode, width, height, config).await,
Commands::Config { config_command } => execute_config_command(config_command, config).await,
Commands::Pkg { pkg_command } => execute_pkg_command(pkg_command).await,
}
}
async fn execute_repl(config: &RunMatConfig) -> Result<()> {
info!("Starting RunMat REPL");
if config.runtime.verbose {
info!("Verbose mode enabled");
}
let enable_jit = config.jit.enabled;
info!(
"JIT compiler: {}",
if enable_jit { "enabled" } else { "disabled" }
);
let mut engine = ReplEngine::with_snapshot(
enable_jit,
config.runtime.verbose,
config.runtime.snapshot_path.as_ref(),
)
.context("Failed to create REPL engine")?;
info!("RunMat REPL ready");
use std::io::{self, Write};
println!(
"RunMat v{} by Dystr (https://dystr.com)",
env!("CARGO_PKG_VERSION")
);
println!("Fast, free, modern MATLAB runtime with JIT compilation and GC");
println!();
if enable_jit {
println!(
"JIT compiler: enabled (Cranelift optimization level: {:?})",
config.jit.optimization_level
);
} else {
println!("JIT compiler: disabled (interpreter mode)");
}
println!(
"Garbage collector: {:?}",
config
.gc
.preset
.map(|p| format!("{p:?}"))
.unwrap_or_else(|| "default".to_string())
);
if let Some(snapshot_info) = engine.snapshot_info() {
println!("{snapshot_info}");
} else {
println!("No snapshot loaded - standard library will be compiled on demand");
}
println!("Type 'help' for help, 'exit' to quit, '.info' for system information");
println!();
let mut input = String::new();
let is_interactive = atty::is(atty::Stream::Stdin);
loop {
if is_interactive {
print!("runmat> ");
io::stdout().flush().unwrap();
}
input.clear();
match io::stdin().read_line(&mut input) {
Ok(0) => {
if !is_interactive {
break;
}
continue;
}
Ok(_) => {
let line = input.trim();
if line == "exit" || line == "quit" {
break;
}
if line == "help" {
show_repl_help();
continue;
}
if line == ".info" {
engine.show_system_info();
continue;
}
if line == ".stats" {
let stats = engine.stats();
println!("Execution Statistics:");
println!(
" Total: {}, JIT: {}, Interpreter: {}",
stats.total_executions, stats.jit_compiled, stats.interpreter_fallback
);
println!(" Average time: {:.2}ms", stats.average_execution_time_ms);
continue;
}
if line == ".gc" {
let gc_stats = engine.gc_stats();
println!("{}", gc_stats.summary_report());
continue;
}
if line.is_empty() {
continue;
}
match engine.execute(line) {
Ok(result) => {
if let Some(error) = result.error {
eprintln!("Error: {error}");
} else if let Some(value) = result.value {
println!("ans = {value}");
if config.runtime.verbose && result.execution_time_ms > 10 {
println!(
" ({}ms {})",
result.execution_time_ms,
if result.used_jit {
"JIT"
} else {
"interpreter"
}
);
}
} else if let Some(type_info) = result.type_info {
println!("ans = {type_info}");
}
}
Err(e) => {
eprintln!("Execution error: {e}");
}
}
}
Err(e) => {
eprintln!("Error reading input: {e}");
break;
}
}
}
info!("RunMat REPL exiting");
Ok(())
}
#[allow(clippy::too_many_arguments)]
async fn execute_kernel(
ip: String,
key: Option<String>,
transport: String,
signature_scheme: String,
shell_port: u16,
iopub_port: u16,
stdin_port: u16,
control_port: u16,
hb_port: u16,
connection_file: Option<PathBuf>,
timeout: u64,
) -> Result<()> {
info!("Starting RunMat Jupyter kernel");
let mut connection = ConnectionInfo {
ip,
transport,
signature_scheme,
key: key.unwrap_or_else(|| uuid::Uuid::new_v4().to_string()),
shell_port,
iopub_port,
stdin_port,
control_port,
hb_port,
};
if shell_port == 0 || iopub_port == 0 || stdin_port == 0 || control_port == 0 || hb_port == 0 {
connection
.assign_ports()
.context("Failed to assign kernel ports")?;
}
if let Some(path) = connection_file {
connection
.write_to_file(&path)
.with_context(|| format!("Failed to write connection file to {path:?}"))?;
info!("Connection file written to {path:?}");
}
let config = KernelConfig {
connection,
session_id: uuid::Uuid::new_v4().to_string(),
debug: log::log_enabled!(log::Level::Debug),
execution_timeout: Some(timeout),
};
let mut server = KernelServer::new(config);
info!("Starting kernel server...");
server
.start()
.await
.context("Failed to start kernel server")?;
info!("Kernel is ready. Press Ctrl+C to stop.");
tokio::signal::ctrl_c()
.await
.context("Failed to listen for ctrl-c")?;
info!("Shutting down kernel...");
server
.stop()
.await
.context("Failed to stop kernel server")?;
Ok(())
}
async fn execute_kernel_with_connection(connection_file: PathBuf, timeout: u64) -> Result<()> {
info!("Starting kernel with connection file: {connection_file:?}");
let connection = ConnectionInfo::from_file(&connection_file)
.with_context(|| format!("Failed to load connection file: {connection_file:?}"))?;
let config = KernelConfig {
connection,
session_id: uuid::Uuid::new_v4().to_string(),
debug: log::log_enabled!(log::Level::Debug),
execution_timeout: Some(timeout),
};
let mut server = KernelServer::new(config);
server
.start()
.await
.context("Failed to start kernel server")?;
tokio::signal::ctrl_c()
.await
.context("Failed to listen for ctrl-c")?;
server
.stop()
.await
.context("Failed to stop kernel server")?;
Ok(())
}
async fn execute_script(script: PathBuf, cli: &Cli, config: &RunMatConfig) -> Result<()> {
execute_script_with_args(script, vec![], cli, config).await
}
async fn execute_script_with_args(
script: PathBuf,
_args: Vec<String>,
_cli: &Cli,
config: &RunMatConfig,
) -> Result<()> {
info!("Executing script: {script:?}");
let content = fs::read_to_string(&script)
.with_context(|| format!("Failed to read script file: {script:?}"))?;
let enable_jit = config.jit.enabled;
let mut engine = ReplEngine::with_snapshot(
enable_jit,
config.runtime.verbose,
config.runtime.snapshot_path.as_ref(),
)
.context("Failed to create execution engine")?;
let start_time = std::time::Instant::now();
let result = engine
.execute(&content)
.context("Failed to execute script")?;
let execution_time = start_time.elapsed();
if let Some(error) = result.error {
error!("Script execution failed: {error}");
std::process::exit(1);
} else {
info!(
"Script executed successfully in {:?} ({})",
execution_time,
if result.used_jit {
"JIT"
} else {
"interpreter"
}
);
if let Some(value) = result.value {
println!("{value:?}");
}
}
Ok(())
}
async fn execute_gc_command(gc_command: GcCommand) -> Result<()> {
match gc_command {
GcCommand::Stats => {
let stats = gc_stats();
println!("{}", stats.summary_report());
}
GcCommand::Minor => {
let start = std::time::Instant::now();
match gc_collect_minor() {
Ok(collected) => {
let duration = start.elapsed();
println!("Minor GC collected {collected} objects in {duration:?}");
}
Err(e) => {
error!("Minor GC failed: {e}");
std::process::exit(1);
}
}
}
GcCommand::Major => {
let start = std::time::Instant::now();
match gc_collect_major() {
Ok(collected) => {
let duration = start.elapsed();
println!("Major GC collected {collected} objects in {duration:?}");
}
Err(e) => {
error!("Major GC failed: {e}");
std::process::exit(1);
}
}
}
GcCommand::Config => {
println!("Current GC Configuration:");
let config = gc_get_config();
println!(
" Young Generation Size: {} MB",
config.young_generation_size / 1024 / 1024
);
println!(
" Minor GC Threshold: {} objects",
config.minor_gc_threshold
);
println!(
" Major GC Threshold: {} objects",
config.major_gc_threshold
);
println!(" Max GC Threads: {}", config.max_gc_threads);
println!(
" Collection Statistics: {}",
if config.collect_statistics {
"enabled"
} else {
"disabled"
}
);
println!(
" Verbose Logging: {}",
if config.verbose_logging {
"enabled"
} else {
"disabled"
}
);
}
GcCommand::Stress { allocations } => {
info!("Starting GC stress test with {allocations} allocations");
let start_time = std::time::Instant::now();
let initial_stats = gc_stats();
println!("Running GC stress test with {allocations} allocations...");
let mut _objects = Vec::new();
for i in 0..allocations {
let value = Value::Num(i as f64);
match gc_allocate(value) {
Ok(ptr) => {
_objects.push(ptr);
if i % 1000 == 0 && i > 0 {
let _ = gc_collect_minor();
}
if i % 5000 == 0 && i > 0 {
let _ = gc_collect_major();
}
}
Err(e) => {
error!("Allocation failed at iteration {i}: {e}");
break;
}
}
if i % (allocations / 10).max(1) == 0 {
println!(" Progress: {i}/{allocations} allocations");
}
}
let duration = start_time.elapsed();
let final_stats = gc_stats();
println!("GC Stress Test Results:");
println!(" Duration: {duration:?}");
println!(" Allocations completed: {}", _objects.len());
println!(
" Allocation rate: {:.2} allocs/sec",
_objects.len() as f64 / duration.as_secs_f64()
);
println!(
" Total collections: {}",
final_stats
.minor_collections
.load(std::sync::atomic::Ordering::Relaxed)
- initial_stats
.minor_collections
.load(std::sync::atomic::Ordering::Relaxed)
+ final_stats
.major_collections
.load(std::sync::atomic::Ordering::Relaxed)
- initial_stats
.major_collections
.load(std::sync::atomic::Ordering::Relaxed)
);
println!(
" Final memory: {} bytes",
final_stats
.current_memory_usage
.load(std::sync::atomic::Ordering::Relaxed)
);
match gc_collect_major() {
Ok(collected) => println!(" Final collection freed {collected} objects"),
Err(e) => error!("Final collection failed: {e}"),
}
}
}
Ok(())
}
async fn execute_benchmark(file: PathBuf, iterations: u32, jit: bool, _cli: &Cli) -> Result<()> {
info!("Benchmarking script: {file:?} ({iterations} iterations, JIT: {jit})");
let content = fs::read_to_string(&file)
.with_context(|| format!("Failed to read script file: {file:?}"))?;
let mut engine = ReplEngine::with_snapshot(jit, false, _cli.snapshot.as_ref())
.context("Failed to create execution engine")?;
let mut total_time = Duration::ZERO;
let mut jit_executions = 0;
let mut interpreter_executions = 0;
println!("Warming up...");
for _ in 0..3 {
let _ = engine.execute(&content)?;
}
println!("Running benchmark...");
for i in 1..=iterations {
let result = engine.execute(&content)?;
if let Some(error) = result.error {
error!("Benchmark iteration {i} failed: {error}");
std::process::exit(1);
}
total_time += Duration::from_millis(result.execution_time_ms);
if result.used_jit {
jit_executions += 1;
} else {
interpreter_executions += 1;
}
if i % 10 == 0 {
println!(" Completed {i} iterations");
}
}
let avg_time = total_time / iterations;
println!("\nBenchmark Results:");
println!(" Total iterations: {iterations}");
println!(" JIT executions: {jit_executions}");
println!(" Interpreter executions: {interpreter_executions}");
println!(" Total time: {total_time:?}");
println!(" Average time: {avg_time:?}");
println!(
" Throughput: {:.2} executions/second",
iterations as f64 / total_time.as_secs_f64()
);
Ok(())
}
async fn execute_plot_command(
mode: Option<PlotMode>,
width: Option<u32>,
height: Option<u32>,
config: &RunMatConfig,
) -> Result<()> {
info!("Starting interactive plotting window");
let plot_mode = mode.unwrap_or(config.plotting.mode);
match plot_mode {
PlotMode::Auto => {
if config.plotting.force_headless || !is_gui_available() {
info!("Auto-detected headless environment");
execute_headless_plot().await
} else {
info!("Auto-detected GUI environment");
execute_gui_plot(width, height, config).await
}
}
PlotMode::Gui => execute_gui_plot(width, height, config).await,
PlotMode::Headless => execute_headless_plot().await,
PlotMode::Jupyter => {
info!("Jupyter plotting mode not yet implemented");
println!("Jupyter plotting mode will be available in future releases.");
Ok(())
}
}
}
async fn execute_gui_plot(
_width: Option<u32>,
_height: Option<u32>,
_config: &RunMatConfig,
) -> Result<()> {
info!("Initializing GUI plotting window");
match Ok::<(), anyhow::Error>(()) {
Ok(()) => {
info!("GUI plotting window closed successfully");
Ok(())
}
Err(e) => {
error!("GUI plotting failed: {e}");
Err(anyhow::anyhow!("GUI plotting failed: {}", e))
}
}
}
async fn execute_headless_plot() -> Result<()> {
info!("Generating sample static plots");
let sample_data_x = vec![1.0, 2.0, 3.0, 4.0, 5.0];
let sample_data_y = vec![1.0, 4.0, 2.0, 8.0, 3.0];
let options = runmat_plot::PlotOptions::default();
match runmat_plot::plot_line(&sample_data_x, &sample_data_y, "sample_plot.png", options) {
Ok(()) => {
println!("Sample plot generated: sample_plot.png");
Ok(())
}
Err(e) => {
error!("Failed to generate plot: {e}");
Err(anyhow::anyhow!("Plot generation failed: {}", e))
}
}
}
fn is_gui_available() -> bool {
use std::env;
if env::var("CI").is_ok()
|| env::var("GITHUB_ACTIONS").is_ok()
|| env::var("HEADLESS").is_ok()
|| env::var("NO_GUI").is_ok()
{
return false;
}
if env::var("SSH_CLIENT").is_ok() && env::var("DISPLAY").is_err() {
return false;
}
atty::is(atty::Stream::Stdout)
}
async fn execute_config_command(
config_command: ConfigCommand,
config: &RunMatConfig,
) -> Result<()> {
match config_command {
ConfigCommand::Show => {
println!("Current RunMat Configuration:");
println!("==============================");
let yaml =
serde_yaml::to_string(config).context("Failed to serialize configuration")?;
println!("{yaml}");
}
ConfigCommand::Generate { output } => {
let sample_config = RunMatConfig::default();
ConfigLoader::save_to_file(&sample_config, &output)
.with_context(|| format!("Failed to write config to {}", output.display()))?;
println!("Sample configuration generated: {}", output.display());
println!("Edit this file to customize your RunMat settings.");
}
ConfigCommand::Validate { config_file } => {
match ConfigLoader::load_from_file(&config_file) {
Ok(_) => {
println!("Configuration file is valid: {}", config_file.display());
}
Err(e) => {
error!("Configuration validation failed: {e}");
std::process::exit(1);
}
}
}
ConfigCommand::Paths => {
println!("RunMat Configuration File Locations:");
println!("====================================");
println!();
if let Ok(config_path) = std::env::var("RUSTMAT_CONFIG") {
println!("Environment override: {config_path}");
}
println!("Current directory:");
if let Ok(current_dir) = std::env::current_dir() {
for name in &[
".runmat.yaml",
".runmat.yml",
".runmat.json",
".runmat.toml",
] {
let path = current_dir.join(name);
let exists = if path.exists() { " (exists)" } else { "" };
println!(" {}{}", path.display(), exists);
}
}
println!();
println!("Home directory:");
if let Some(home_dir) = dirs::home_dir() {
for name in &[".runmat.yaml", ".runmat.yml", ".runmat.json"] {
let path = home_dir.join(name);
let exists = if path.exists() { " (exists)" } else { "" };
println!(" {}{}", path.display(), exists);
}
let config_dir = home_dir.join(".config/runmat");
for name in &["config.yaml", "config.yml", "config.json"] {
let path = config_dir.join(name);
let exists = if path.exists() { " (exists)" } else { "" };
println!(" {}{}", path.display(), exists);
}
}
#[cfg(unix)]
{
println!();
println!("System-wide:");
for name in &[
"/etc/runmat/config.yaml",
"/etc/runmat/config.yml",
"/etc/runmat/config.json",
] {
let path = std::path::Path::new(name);
let exists = if path.exists() { " (exists)" } else { "" };
println!(" {}{}", path.display(), exists);
}
}
}
}
Ok(())
}
async fn execute_pkg_command(pkg_command: PkgCommand) -> Result<()> {
let msg = "RunMat package manager is coming soon. Track progress in the repo.";
match pkg_command {
PkgCommand::Add { name } => println!("pkg add {name}: {msg}"),
PkgCommand::Remove { name } => println!("pkg remove {name}: {msg}"),
PkgCommand::Install => println!("pkg install: {msg}"),
PkgCommand::Update => println!("pkg update: {msg}"),
PkgCommand::Publish => println!("pkg publish: {msg}"),
}
Ok(())
}
impl From<config::GcPreset> for runmat_gc::GcConfig {
fn from(preset: config::GcPreset) -> Self {
match preset {
config::GcPreset::LowLatency => runmat_gc::GcConfig::low_latency(),
config::GcPreset::HighThroughput => runmat_gc::GcConfig::high_throughput(),
config::GcPreset::LowMemory => runmat_gc::GcConfig::low_memory(),
config::GcPreset::Debug => runmat_gc::GcConfig::debug(),
}
}
}
impl From<CompressionAlg> for runmat_snapshot::CompressionAlgorithm {
fn from(alg: CompressionAlg) -> Self {
use runmat_snapshot::CompressionAlgorithm;
match alg {
CompressionAlg::None => CompressionAlgorithm::None,
CompressionAlg::Lz4 => CompressionAlgorithm::Lz4,
CompressionAlg::Zstd => CompressionAlgorithm::Zstd,
}
}
}
async fn execute_snapshot_command(snapshot_command: SnapshotCommand) -> Result<()> {
match snapshot_command {
SnapshotCommand::Create {
output,
optimization,
compression,
} => {
info!("Creating snapshot: {output:?}");
let mut config = SnapshotConfig::default();
if let Some(comp) = compression {
config.compression_enabled = !matches!(comp, CompressionAlg::None);
config.compression_algorithm = comp.into();
}
let _optimization_level = match optimization {
OptLevel::None => runmat_snapshot::OptimizationLevel::None,
OptLevel::Size => runmat_snapshot::OptimizationLevel::Basic,
OptLevel::Speed => runmat_snapshot::OptimizationLevel::Aggressive,
OptLevel::Aggressive => runmat_snapshot::OptimizationLevel::MaxPerformance,
};
let builder = SnapshotBuilder::new(config);
builder
.build_and_save(&output)
.with_context(|| format!("Failed to build and save snapshot to {output:?}"))?;
println!("Snapshot created successfully: {output:?}");
}
SnapshotCommand::Info { snapshot } => {
info!("Loading snapshot info: {snapshot:?}");
let mut loader = SnapshotLoader::new(SnapshotConfig::default());
let (loaded, stats) = loader
.load(&snapshot)
.with_context(|| format!("Failed to load snapshot from {snapshot:?}"))?;
println!("Snapshot Information:");
println!(" File: {snapshot:?}");
println!(" Version: {}", loaded.metadata.runmat_version);
println!(" Created: {:?}", loaded.metadata.created_at);
println!(" Tool Version: {}", loaded.metadata.tool_version);
println!(" Build Config: {:?}", loaded.metadata.build_config);
println!(" Builtin Functions: {}", loaded.builtins.functions.len());
println!(
" HIR Cache Functions: {}",
loaded.hir_cache.functions.len()
);
println!(" HIR Cache Patterns: {}", loaded.hir_cache.patterns.len());
println!(
" Bytecode Cache (stdlib): {}",
loaded.bytecode_cache.stdlib_bytecode.len()
);
println!(
" Bytecode Cache (sequences): {}",
loaded.bytecode_cache.operation_sequences.len()
);
println!(
" Bytecode Cache (hotspots): {}",
loaded.bytecode_cache.hotspots.len()
);
println!(" GC Presets: {}", loaded.gc_presets.presets.len());
println!(" Load Time: {:?}", stats.load_time);
println!(" Total Size: {} bytes", stats.total_size);
println!(" Compressed Size: {} bytes", stats.compressed_size);
println!(" Compression Ratio: {:.2}x", stats.compression_ratio);
}
SnapshotCommand::Presets => {
println!("Available Snapshot Presets:");
println!();
let presets = vec![
(
"development",
SnapshotPreset::Development,
"Fast development iteration",
),
(
"production",
SnapshotPreset::Production,
"Production deployment",
),
(
"high-performance",
SnapshotPreset::HighPerformance,
"High-performance computing",
),
(
"low-memory",
SnapshotPreset::LowMemory,
"Memory-constrained environments",
),
(
"network-optimized",
SnapshotPreset::NetworkOptimized,
"Network-optimized (minimal size)",
),
(
"debug",
SnapshotPreset::Debug,
"Debug-friendly (maximum validation)",
),
];
for (name, preset, description) in presets {
let config = preset.config();
println!(" {name}");
println!(" Description: {description}");
println!(" Compression: {:?}", config.compression_algorithm);
println!(
" Validation: {}",
if config.validation_enabled {
"enabled"
} else {
"disabled"
}
);
println!(
" Memory Mapping: {}",
if config.memory_mapping_enabled {
"enabled"
} else {
"disabled"
}
);
println!(
" Parallel Loading: {}",
if config.parallel_loading {
"enabled"
} else {
"disabled"
}
);
println!();
}
}
SnapshotCommand::Validate { snapshot } => {
info!("Validating snapshot: {snapshot:?}");
let mut loader = SnapshotLoader::new(SnapshotConfig::default());
match loader.load(&snapshot) {
Ok((_, stats)) => {
println!("Snapshot validation passed: {snapshot:?}");
println!(" Load time: {:?}", stats.load_time);
println!(" File size: {} bytes", stats.total_size);
if stats.compressed_size > 0 {
println!(" Compressed size: {} bytes", stats.compressed_size);
println!(" Compression ratio: {:.2}x", stats.compression_ratio);
}
}
Err(e) => {
error!("Snapshot validation failed: {e}");
std::process::exit(1);
}
}
}
}
Ok(())
}
fn show_version(detailed: bool) {
println!("RunMat v{}", env!("CARGO_PKG_VERSION"));
if detailed {
println!(
"Built with Rust {}",
std::env::var("RUSTC_VERSION").unwrap_or_else(|_| "unknown".to_string())
);
println!(
"Target: {}",
std::env::var("TARGET").unwrap_or_else(|_| "unknown".to_string())
);
println!(
"Profile: {}",
if cfg!(debug_assertions) {
"debug"
} else {
"release"
}
);
println!("Features: jupyter-kernel, plotting, repl, jit, gc");
println!();
println!("Components:");
println!(" • runmat-lexer: MATLAB/Octave tokenizer");
println!(" • runmat-parser: Syntax parser with error recovery");
println!(" • runmat-hir: High-level intermediate representation");
println!(" • runmat-ignition: Baseline interpreter");
println!(" • runmat-turbine: JIT compiler with Cranelift");
println!(" • runmat-gc: Generational garbage collector");
println!(" • runmat-runtime: BLAS/LAPACK runtime with builtins");
println!(" • runmat-kernel: Jupyter kernel protocol");
println!(" • runmat-plot: Headless plotting backend");
}
}
async fn show_system_info(cli: &Cli) -> Result<()> {
println!("RunMat System Information");
println!("==========================");
println!();
println!("Version: {}", env!("CARGO_PKG_VERSION"));
println!(
"Rust Version: {}",
std::env::var("RUSTC_VERSION").unwrap_or_else(|_| "unknown".to_string())
);
println!(
"Target: {}",
std::env::var("TARGET").unwrap_or_else(|_| "unknown".to_string())
);
println!();
println!("Runtime Configuration:");
println!(
" JIT Compiler: {}",
if !cli.no_jit { "enabled" } else { "disabled" }
);
println!(" JIT Threshold: {}", cli.jit_threshold);
println!(" JIT Optimization: {:?}", cli.jit_opt_level);
println!(
" GC Preset: {:?}",
cli.gc_preset
.as_ref()
.map(|p| format!("{p:?}"))
.unwrap_or_else(|| "default".to_string())
);
if let Some(young_size) = cli.gc_young_size {
println!(" GC Young Generation: {young_size}MB");
}
if let Some(threads) = cli.gc_threads {
println!(" GC Threads: {threads}");
}
println!(" GC Statistics: {}", cli.gc_stats);
println!();
println!("Environment:");
println!(" RUSTMAT_DEBUG: {:?}", std::env::var("RUSTMAT_DEBUG").ok());
println!(
" RUSTMAT_LOG_LEVEL: {:?}",
std::env::var("RUSTMAT_LOG_LEVEL").ok()
);
println!(
" RUSTMAT_TIMEOUT: {:?}",
std::env::var("RUSTMAT_TIMEOUT").ok()
);
println!(
" RUSTMAT_JIT_ENABLE: {:?}",
std::env::var("RUSTMAT_JIT_ENABLE").ok()
);
println!(
" RUSTMAT_GC_PRESET: {:?}",
std::env::var("RUSTMAT_GC_PRESET").ok()
);
println!();
let gc_stats = gc_stats();
println!("Garbage Collector Status:");
println!("{}", gc_stats.summary_report());
println!();
println!("Available Commands:");
println!(" repl Start interactive REPL with JIT");
println!(" --install-kernel Install RunMat as Jupyter kernel");
println!(" kernel Start Jupyter kernel");
println!(" kernel-connection Start kernel with connection file");
println!(" run <file> Execute MATLAB script");
println!(" gc stats Show GC statistics");
println!(" gc major Force major GC collection");
println!(" benchmark <file> Benchmark script execution");
println!(" snapshot create Create standard library snapshot");
println!(" snapshot info Inspect snapshot file");
println!(" snapshot presets List available presets");
println!(" snapshot validate Validate snapshot file");
println!(" version Show version information");
println!(" info Show this system information");
Ok(())
}
fn show_repl_help() {
println!("RunMat REPL Help");
println!("=================");
println!();
println!("Commands:");
println!(" exit, quit Exit the REPL");
println!(" help Show this help message");
println!(" .info Show detailed system information");
println!(" .stats Show execution statistics");
println!(" .gc Show garbage collector statistics");
println!();
println!("MATLAB/Octave syntax is supported:");
println!(" x = 1 + 2 # Assignment");
println!(" y = [1, 2, 3] # Vectors");
println!(" z = [1, 2; 3, 4] # Matrices");
println!(" if x > 0; disp('positive'); end # Control flow");
println!(" for i = 1:5; disp(i); end # Loops");
println!();
println!("Features:");
println!(" • JIT compilation with Cranelift for optimal performance");
println!(" • Generational garbage collection with configurable policies");
println!(" • High-performance BLAS/LAPACK operations on matrices");
println!(" • Interpreter fallback for unsupported JIT patterns");
println!(" • Real-time performance monitoring and statistics");
println!();
println!("Performance Tips:");
println!(" • Repeated code automatically gets JIT compiled");
println!(" • Matrix operations use optimized BLAS routines");
println!(" • Use '.stats' to monitor JIT compilation effectiveness");
println!(" • Use '.gc' to monitor memory usage and collection");
println!();
println!("Press Enter after each statement to execute.");
}
async fn install_jupyter_kernel() -> Result<()> {
use std::fs;
info!("Installing RunMat as a Jupyter kernel");
let current_exe = std::env::current_exe().context("Failed to get current executable path")?;
let kernel_dir =
find_jupyter_kernel_dir().context("Failed to find Jupyter kernel directory")?;
let runmat_kernel_dir = kernel_dir.join("runmat");
fs::create_dir_all(&runmat_kernel_dir).with_context(|| {
format!(
"Failed to create kernel directory: {}",
runmat_kernel_dir.display()
)
})?;
let kernel_json = format!(
r#"{{
"argv": [
"{}",
"kernel-connection",
"{{connection_file}}"
],
"display_name": "RunMat",
"language": "matlab",
"metadata": {{
"debugger": false
}}
}}"#,
current_exe.display()
);
let kernel_json_path = runmat_kernel_dir.join("kernel.json");
fs::write(&kernel_json_path, kernel_json).with_context(|| {
format!(
"Failed to write kernel.json to {}",
kernel_json_path.display()
)
})?;
create_kernel_logos(&runmat_kernel_dir)?;
println!("RunMat Jupyter kernel installed successfully!");
println!("Kernel directory: {}", runmat_kernel_dir.display());
println!();
println!("You can now start Jupyter and select 'RunMat' as a kernel:");
println!(" jupyter notebook");
println!(" # or");
println!(" jupyter lab");
println!();
println!("To verify the installation:");
println!(" jupyter kernelspec list");
Ok(())
}
fn find_jupyter_kernel_dir() -> Result<PathBuf> {
if let Ok(output) = std::process::Command::new("jupyter")
.args(["--data-dir"])
.output()
{
if output.status.success() {
let data_dir_str = String::from_utf8_lossy(&output.stdout);
let data_dir = data_dir_str.trim();
let kernels_dir = PathBuf::from(data_dir).join("kernels");
if kernels_dir.exists() || kernels_dir.parent().is_some_and(|p| p.exists()) {
return Ok(kernels_dir);
}
}
}
if let Some(home_dir) = dirs::home_dir() {
let user_kernels = home_dir.join(".local/share/jupyter/kernels");
if user_kernels.exists() || user_kernels.parent().is_some_and(|p| p.exists()) {
return Ok(user_kernels);
}
#[cfg(target_os = "macos")]
{
let macos_kernels = home_dir.join("Library/Jupyter/kernels");
if macos_kernels.exists() || macos_kernels.parent().is_some_and(|p| p.exists()) {
return Ok(macos_kernels);
}
}
#[cfg(target_os = "windows")]
{
if let Ok(appdata) = std::env::var("APPDATA") {
let windows_kernels = PathBuf::from(appdata).join("jupyter/kernels");
if windows_kernels.exists() || windows_kernels.parent().is_some_and(|p| p.exists())
{
return Ok(windows_kernels);
}
}
}
let default_kernels = home_dir.join(".local/share/jupyter/kernels");
return Ok(default_kernels);
}
Err(anyhow::anyhow!(
"Could not determine Jupyter kernel directory. Please install Jupyter first."
))
}
fn create_kernel_logos(kernel_dir: &std::path::Path) -> Result<()> {
let logo_info = kernel_dir.join("logo-readme.txt");
fs::write(
logo_info,
"RunMat kernel logos can be added here:\n- logo-32x32.png\n- logo-64x64.png",
)
.context("Failed to create logo info file")?;
Ok(())
}