84ef3f9aed
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.
168 lines
4.9 KiB
Rust
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);
|
|
}
|
|
}
|
|
}
|