Files
RustAst/src/bin/ast.rs
T
Michael Schimmel 84ef3f9aed feat: Enhance #use directive for directories and cwd
The `#use` directive now supports referencing entire directories,
automatically including all `.myc` files within them. Additionally,
environments are now initialized with the current working directory as a
default search path, simplifying module resolution.
2026-03-06 21:07:27 +01:00

168 lines
4.9 KiB
Rust

use clap::Parser;
use myc::ast::environment::Environment;
use myc::utils::tester;
use std::fs;
use std::path::PathBuf;
#[derive(Parser)]
#[command(author, version, about = "MYC AST Compiler & Benchmarker", long_about = None)]
struct Cli {
/// The script file to run or benchmark
#[arg(value_name = "FILE")]
file: Option<PathBuf>,
/// Run a script string directly
#[arg(short, long)]
eval: Option<String>,
/// Run benchmarks (Only allowed in Release mode)
#[arg(short, long)]
bench: bool,
/// Update the benchmark baseline (Only allowed in Release mode)
#[arg(short, long)]
update_bench: bool,
/// Dump the compiled AST
#[arg(short, long)]
dump: bool,
/// Run with TracingObserver enabled
#[arg(short, long)]
trace: bool,
/// Library directories to load before execution
#[arg(short, long)]
lib: Vec<PathBuf>,
/// Disable optimization
#[arg(long)]
no_opt: bool,
}
fn main() {
let cli = Cli::parse();
let mut env = Environment::new().with_cwd();
env.optimization = !cli.no_opt;
// Load libraries (Now just search paths)
for lib_path in &cli.lib {
env.add_search_path(lib_path);
}
if cli.bench || cli.update_bench {
if cfg!(debug_assertions) {
eprintln!("❌ ERROR: Benchmarks must be run in Release mode!");
eprintln!(" Use: cargo run --release --bin ast -- --bench");
std::process::exit(1);
}
println!("🚀 Running benchmarks in RELEASE mode...\n");
let filter = cli
.file
.as_ref()
.and_then(|p| p.file_name())
.map(|n| n.to_string_lossy().to_string());
let results = tester::run_benchmarks(cli.update_bench, filter.as_deref());
for res in results {
let diff = res
.diff_pct
.map_or(String::new(), |d| format!(" ({:+.1}%)", d));
println!("{}: {} - {:?}{}", res.status, res.name, res.median, diff);
}
return;
}
if let Some(script_str) = cli.eval {
if let Err(e) = env.preload_dependencies(&script_str, None) {
eprintln!("❌ Error resolving dependencies: {}", e);
std::process::exit(1);
}
if cli.dump {
match env.dump_ast(&script_str) {
Ok(dump) => println!("{}", dump),
Err(e) => eprintln!("Error dumping AST: {}", e),
}
} else if cli.trace {
execute_trace(&env, &script_str);
} else {
execute(&env, &script_str);
}
} else if let Some(file_path) = cli.file {
match fs::read_to_string(&file_path) {
Ok(content) => {
if let Err(e) = env.preload_dependencies(&content, Some(&file_path)) {
eprintln!("❌ Error resolving dependencies for {:?}:\n{}", file_path, e);
std::process::exit(1);
}
if cli.dump {
match env.dump_ast(&content) {
Ok(dump) => println!("{}", dump),
Err(e) => eprintln!("Error dumping AST: {}", e),
}
} else if cli.trace {
execute_trace(&env, &content);
} else {
execute(&env, &content);
}
}
Err(e) => {
eprintln!("Error reading file {:?}: {}", file_path, e);
std::process::exit(1);
}
}
} else {
println!("MYC AST Compiler CLI. Use --help for usage.");
}
}
fn execute(env: &Environment, source: &str) {
let result = env.compile(source);
for diag in &result.diagnostics.items {
let level = format!("{:?}", diag.level).to_uppercase();
let loc = diag
.identity
.as_ref()
.and_then(|id| id.location)
.map(|l| format!(" at {}:{}", l.line, l.col))
.unwrap_or_default();
eprintln!("{}{} : {}", level, loc, diag.message);
}
if result.diagnostics.has_errors() {
std::process::exit(1);
}
match env.run_script_compiled(result.ast.unwrap()) {
Ok(res) => println!("{}", res),
Err(e) => {
eprintln!("Runtime Error: {}", e);
std::process::exit(1);
}
}
}
fn execute_trace(env: &Environment, source: &str) {
match env.run_debug(source) {
Ok((Ok(result), logs)) => {
for line in logs {
println!("{}", line);
}
println!("Result: {}", result);
}
Ok((Err(e), logs)) => {
for line in logs {
println!("{}", line);
}
eprintln!("Runtime Error: {}", e);
std::process::exit(1);
}
Err(e) => {
eprintln!("Compilation Error: {}", e);
std::process::exit(1);
}
}
}