use clap::{Arg, ArgMatches, Command}; use serde_json; use super::CliConfig; use super::utils::parse_debug_fuel; pub fn parse() -> CliConfig { let argv: Vec = std::env::args().collect(); if let Some(pos) = argv.iter().position(|s| s == "--") { let script_args: Vec = argv.iter().skip(pos + 1).cloned().collect(); if !script_args.is_empty() { if let Ok(json) = serde_json::to_string(&script_args) { std::env::set_var("NYASH_SCRIPT_ARGS_JSON", json); } } let matches = build_command() .try_get_matches_from(&argv[..pos]) .unwrap_or_else(|e| e.exit()); from_matches(&matches) } else { let matches = build_command().get_matches(); from_matches(&matches) } } pub fn build_command() -> Command { Command::new("nyash") .version("1.0") .author("Claude Code ") .about("🦀 Nyash Programming Language - Everything is Box in Rust! 🦀") .arg(Arg::new("file").help("Nyash file to execute").value_name("FILE").index(1)) .arg(Arg::new("macro-expand-child").long("macro-expand-child").value_name("FILE").help("Macro sandbox child: read AST JSON v0 from stdin, expand using Nyash macro file, write AST JSON v0 to stdout (PoC)")) .arg(Arg::new("dump-ast").long("dump-ast").help("Dump parsed AST and exit").action(clap::ArgAction::SetTrue)) .arg(Arg::new("macro-preexpand").long("macro-preexpand").help("Enable selfhost macro pre-expand").action(clap::ArgAction::SetTrue)) .arg(Arg::new("macro-preexpand-auto").long("macro-preexpand-auto").help("Auto enable selfhost macro pre-expand").action(clap::ArgAction::SetTrue)) .arg(Arg::new("macro-top-level-allow").long("macro-top-level-allow").help("Allow top-level macro usage").action(clap::ArgAction::SetTrue)) .arg(Arg::new("macro-profile").long("macro-profile").value_name("{dev|ci-fast|strict}").help("Select macro profile")) .arg(Arg::new("dump-expanded-ast-json").long("dump-expanded-ast-json").help("Dump AST after macro expansion as JSON v0 and exit").action(clap::ArgAction::SetTrue)) .arg(Arg::new("macro-ctx-json").long("macro-ctx-json").value_name("JSON").help("Provide MacroCtx as JSON string for macro child routes")) .arg(Arg::new("gc").long("gc").value_name("{auto,rc+cycle,minorgen,stw,rc,off}").help("Select GC mode (default: rc+cycle)")) .arg(Arg::new("parser").long("parser").value_name("{rust|ny}").help("Choose parser: 'rust' (default) or 'ny' (direct v0 bridge)")) .arg(Arg::new("ny-parser-pipe").long("ny-parser-pipe").help("Read Ny JSON IR v0 from stdin and execute via MIR Interpreter").action(clap::ArgAction::SetTrue)) .arg(Arg::new("json-file").long("json-file").value_name("FILE").help("Read Ny JSON IR v0 from a file and execute via MIR Interpreter")) .arg(Arg::new("emit-mir-json").long("emit-mir-json").value_name("FILE").help("Emit MIR JSON v0 to file and exit")) .arg(Arg::new("emit-exe").long("emit-exe").value_name("FILE").help("Emit native executable via ny-llvmc and exit")) .arg(Arg::new("emit-exe-nyrt").long("emit-exe-nyrt").value_name("DIR").help("Directory containing libnyash_kernel.a (used with --emit-exe)")) .arg(Arg::new("emit-exe-libs").long("emit-exe-libs").value_name("FLAGS").help("Extra linker flags for ny-llvmc when emitting executable")) .arg(Arg::new("stage3").long("stage3").help("Enable Stage-3 syntax acceptance for selfhost parser").action(clap::ArgAction::SetTrue)) .arg(Arg::new("ny-compiler-args").long("ny-compiler-args").value_name("ARGS").help("Pass additional args to selfhost child compiler")) .arg(Arg::new("using").long("using").value_name("NAME").help("Add a using directive to current session; repeat").action(clap::ArgAction::Append)) .arg(Arg::new("debug-fuel").long("debug-fuel").value_name("N|unlimited").help("Limit interpreter/JIT steps or 'unlimited' (default 100000)").default_value("100000")) .arg(Arg::new("run-tests").long("run-tests").help("Run inline tests in the module (functions starting with 'test_')").action(clap::ArgAction::SetTrue)) .arg(Arg::new("test-filter").long("test-filter").value_name("SUBSTR").help("Only run tests whose name contains SUBSTR (with --run-tests)")) .arg(Arg::new("test-entry").long("test-entry").value_name("{wrap|override}").help("When --run-tests and a main exists: wrap or override") ) .arg(Arg::new("test-return").long("test-return").value_name("{tests|original}").help("Harness return policy (tests or original)") ) .arg(Arg::new("dump-mir").long("dump-mir").help("Dump MIR instead of executing").action(clap::ArgAction::SetTrue)) .arg(Arg::new("verify").long("verify").help("Verify MIR integrity and exit").action(clap::ArgAction::SetTrue)) .arg(Arg::new("mir-verbose").long("mir-verbose").help("Show verbose MIR output with statistics").action(clap::ArgAction::SetTrue)) .arg(Arg::new("mir-verbose-effects").long("mir-verbose-effects").help("Show per-instruction effect category").action(clap::ArgAction::SetTrue)) .arg(Arg::new("no-optimize").long("no-optimize").help("Disable MIR optimizer passes").action(clap::ArgAction::SetTrue)) .arg(Arg::new("backend").long("backend").value_name("BACKEND").help("Backend: vm (default), llvm, interpreter").default_value("vm")) .arg(Arg::new("verbose").long("verbose").short('v').help("Verbose CLI output (sets NYASH_CLI_VERBOSE=1)").action(clap::ArgAction::SetTrue)) .arg(Arg::new("compile-wasm").long("compile-wasm").help("Compile to WebAssembly").action(clap::ArgAction::SetTrue)) .arg(Arg::new("compile-native").long("compile-native").help("Compile to native executable (AOT)").action(clap::ArgAction::SetTrue)) .arg(Arg::new("aot").long("aot").help("Short form of --compile-native").action(clap::ArgAction::SetTrue)) .arg(Arg::new("output").long("output").short('o').value_name("FILE").help("Output file for compilation")) .arg(Arg::new("benchmark").long("benchmark").help("Run performance benchmarks").action(clap::ArgAction::SetTrue)) .arg(Arg::new("iterations").long("iterations").value_name("COUNT").help("Iterations for benchmarks").default_value("10")) .arg(Arg::new("vm-stats").long("vm-stats").help("Enable VM instruction statistics").action(clap::ArgAction::SetTrue)) .arg(Arg::new("vm-stats-json").long("vm-stats-json").help("Output VM statistics in JSON").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-exec").long("jit-exec").help("Enable JIT execution").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-stats").long("jit-stats").help("Print JIT statistics").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-stats-json").long("jit-stats-json").help("Output JIT stats in JSON").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-dump").long("jit-dump").help("Dump JIT lowering summary").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-events").long("jit-events").help("Emit JIT events JSONL").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-events-compile").long("jit-events-compile").help("Emit compile-time JIT events").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-events-runtime").long("jit-events-runtime").help("Emit runtime JIT events").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-events-path").long("jit-events-path").value_name("FILE").help("Write JIT events JSONL to file")) .arg(Arg::new("jit-threshold").long("jit-threshold").value_name("N").help("Hotness threshold for JIT compilation")) .arg(Arg::new("jit-phi-min").long("jit-phi-min").help("Minimal PHI path for branches").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-hostcall").long("jit-hostcall").help("Enable JIT hostcall bridge").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-handle-debug").long("jit-handle-debug").help("Print JIT handle allocation debug logs").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-native-f64").long("jit-native-f64").help("Enable native f64 ABI path").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-native-bool").long("jit-native-bool").help("Enable native bool ABI path").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-only").long("jit-only").help("Run JIT only (no VM fallback)").action(clap::ArgAction::SetTrue)) .arg(Arg::new("jit-direct").long("jit-direct").help("Independent JIT engine mode").action(clap::ArgAction::SetTrue)) .arg(Arg::new("emit-cfg").long("emit-cfg").value_name("DOT_FILE").help("Emit JIT CFG as DOT")) .arg(Arg::new("run-task").long("run-task").value_name("NAME").help("Run a named task from nyash.toml")) .arg(Arg::new("load-ny-plugins").long("load-ny-plugins").help("Load scripts from nyash.toml [ny_plugins]").action(clap::ArgAction::SetTrue)) .arg(Arg::new("build").long("build").value_name("PATH").help("Build AOT executable using nyash.toml at PATH (MVP)")) .arg(Arg::new("build-app").long("app").value_name("FILE").help("Entry Nyash script for --build")) .arg(Arg::new("build-out").long("out").value_name("FILE").help("Output executable name for --build")) .arg(Arg::new("build-aot").long("build-aot").value_name("{cranelift|llvm}").help("AOT backend for --build")) .arg(Arg::new("build-profile").long("profile").value_name("{release|debug}").help("Cargo profile for --build")) .arg(Arg::new("build-target").long("target").value_name("TRIPLE").help("Target triple for --build")) } pub fn from_matches(matches: &ArgMatches) -> CliConfig { if matches.get_flag("stage3") { std::env::set_var("NYASH_NY_COMPILER_STAGE3", "1"); } if let Some(a) = matches.get_one::("ny-compiler-args") { std::env::set_var("NYASH_NY_COMPILER_CHILD_ARGS", a); } let cfg = CliConfig { file: matches.get_one::("file").cloned(), debug_fuel: parse_debug_fuel(matches.get_one::("debug-fuel").unwrap()), dump_ast: matches.get_flag("dump-ast"), dump_mir: matches.get_flag("dump-mir"), verify_mir: matches.get_flag("verify"), mir_verbose: matches.get_flag("mir-verbose"), mir_verbose_effects: matches.get_flag("mir-verbose-effects"), no_optimize: matches.get_flag("no-optimize"), backend: matches.get_one::("backend").unwrap().clone(), compile_wasm: matches.get_flag("compile-wasm"), compile_native: matches.get_flag("compile-native") || matches.get_flag("aot"), output_file: matches.get_one::("output").cloned(), benchmark: matches.get_flag("benchmark"), iterations: matches.get_one::("iterations").unwrap().parse().unwrap_or(10), vm_stats: matches.get_flag("vm-stats"), vm_stats_json: matches.get_flag("vm-stats-json"), jit_exec: matches.get_flag("jit-exec"), jit_stats: matches.get_flag("jit-stats"), jit_stats_json: matches.get_flag("jit-stats-json"), jit_dump: matches.get_flag("jit-dump"), jit_events: matches.get_flag("jit-events"), jit_events_compile: matches.get_flag("jit-events-compile"), jit_events_runtime: matches.get_flag("jit-events-runtime"), jit_events_path: matches.get_one::("jit-events-path").cloned(), jit_threshold: matches.get_one::("jit-threshold").and_then(|s| s.parse::().ok()), jit_phi_min: matches.get_flag("jit-phi-min"), jit_hostcall: matches.get_flag("jit-hostcall"), jit_handle_debug: matches.get_flag("jit-handle-debug"), jit_native_f64: matches.get_flag("jit-native-f64"), jit_native_bool: matches.get_flag("jit-native-bool"), emit_cfg: matches.get_one::("emit-cfg").cloned(), jit_only: matches.get_flag("jit-only"), jit_direct: matches.get_flag("jit-direct"), cli_verbose: matches.get_flag("verbose"), run_task: matches.get_one::("run-task").cloned(), load_ny_plugins: matches.get_flag("load-ny-plugins"), gc_mode: matches.get_one::("gc").cloned(), parser_ny: matches.get_one::("parser").map(|s| s == "ny").unwrap_or(false), ny_parser_pipe: matches.get_flag("ny-parser-pipe"), json_file: matches.get_one::("json-file").cloned(), build_path: matches.get_one::("build").cloned(), build_app: matches.get_one::("build-app").cloned(), build_out: matches.get_one::("build-out").cloned(), build_aot: matches.get_one::("build-aot").cloned(), build_profile: matches.get_one::("build-profile").cloned(), build_target: matches.get_one::("build-target").cloned(), cli_usings: matches.get_many::("using").map(|v| v.cloned().collect()).unwrap_or_else(|| Vec::new()), emit_mir_json: matches.get_one::("emit-mir-json").cloned(), emit_exe: matches.get_one::("emit-exe").cloned(), emit_exe_nyrt: matches.get_one::("emit-exe-nyrt").cloned(), emit_exe_libs: matches.get_one::("emit-exe-libs").cloned(), macro_expand_child: matches.get_one::("macro-expand-child").cloned(), dump_expanded_ast_json: matches.get_flag("dump-expanded-ast-json"), macro_ctx_json: matches.get_one::("macro-ctx-json").cloned(), }; if cfg.cli_verbose { std::env::set_var("NYASH_CLI_VERBOSE", "1"); } if cfg.vm_stats { std::env::set_var("NYASH_VM_STATS", "1"); } if cfg.vm_stats_json { std::env::set_var("NYASH_VM_STATS_JSON", "1"); } if cfg.jit_exec { std::env::set_var("NYASH_JIT_EXEC", "1"); } if cfg.jit_stats { std::env::set_var("NYASH_JIT_STATS", "1"); } if cfg.jit_stats_json { std::env::set_var("NYASH_JIT_STATS_JSON", "1"); } if cfg.jit_dump { std::env::set_var("NYASH_JIT_DUMP", "1"); } if cfg.jit_events { std::env::set_var("NYASH_JIT_EVENTS", "1"); } if cfg.jit_events_compile { std::env::set_var("NYASH_JIT_EVENTS_COMPILE", "1"); } if cfg.jit_events_runtime { std::env::set_var("NYASH_JIT_EVENTS_RUNTIME", "1"); } if let Some(p) = &cfg.jit_events_path { std::env::set_var("NYASH_JIT_EVENTS_PATH", p); } if let Some(t) = cfg.jit_threshold { std::env::set_var("NYASH_JIT_THRESHOLD", t.to_string()); } if cfg.jit_phi_min { std::env::set_var("NYASH_JIT_PHI_MIN", "1"); } if cfg.jit_hostcall { std::env::set_var("NYASH_JIT_HOSTCALL", "1"); } if cfg.jit_handle_debug { std::env::set_var("NYASH_JIT_HANDLE_DEBUG", "1"); } if cfg.jit_native_f64 { std::env::set_var("NYASH_JIT_NATIVE_F64", "1"); } if cfg.jit_native_bool { std::env::set_var("NYASH_JIT_NATIVE_BOOL", "1"); } if cfg.jit_only { std::env::set_var("NYASH_JIT_ONLY", "1"); } if cfg.jit_direct { std::env::set_var("NYASH_JIT_DIRECT", "1"); } if let Some(gc) = &cfg.gc_mode { std::env::set_var("NYASH_GC_MODE", gc); } if matches.get_flag("run-tests") { std::env::set_var("NYASH_RUN_TESTS", "1"); if let Some(filter) = matches.get_one::("test-filter") { std::env::set_var("NYASH_TEST_FILTER", filter); } if let Some(entry) = matches.get_one::("test-entry") { let v = entry.as_str(); if v == "wrap" || v == "override" { std::env::set_var("NYASH_TEST_ENTRY", v); } } if let Some(ret) = matches.get_one::("test-return") { let v = ret.as_str(); if v == "tests" || v == "original" { std::env::set_var("NYASH_TEST_RETURN", v); } } } if matches.get_flag("macro-preexpand") { std::env::set_var("NYASH_MACRO_SELFHOST_PRE_EXPAND", "1"); } if matches.get_flag("macro-preexpand-auto") { std::env::set_var("NYASH_MACRO_SELFHOST_PRE_EXPAND", "auto"); } if matches.get_flag("macro-top-level-allow") { std::env::set_var("NYASH_MACRO_TOPLEVEL_ALLOW", "1"); } if let Some(p) = matches.get_one::("macro-profile") { match p.as_str() { "dev" | "ci-fast" | "strict" => { std::env::set_var("NYASH_MACRO_ENABLE", "1"); std::env::set_var("NYASH_MACRO_STRICT", "1"); std::env::set_var("NYASH_MACRO_TOPLEVEL_ALLOW", "0"); std::env::set_var("NYASH_MACRO_SELFHOST_PRE_EXPAND", "auto"); } _ => {} } } cfg }