runner(cli): adopt CliConfig::as_groups across runner modules (dispatch/common/pipe_io/mir/bench). llvm-builder: extract ny_main wrapper to builders.entry; add optional env-gated function_lower delegation; keep default behavior unchanged
This commit is contained in:
@ -47,6 +47,14 @@ Clone() Reduction — Phase 1 (Arc/str)
|
||||
- `types: HashMap<String, Arc<TypeBox>>` → `HashMap<Arc<str>, Arc<TypeBox>>`(内部型名の共有化)。
|
||||
- API互換(`get_type(&str)` は Borrow によりそのまま利用可能)。
|
||||
|
||||
CLI Refactor — Phase A (non‑breaking)
|
||||
- Added grouped view structs without changing existing fields or parsing:
|
||||
- InputConfig, DebugConfig, BackendConfig(+JitConfig), BuildConfig, EmitConfig, ParserPipeConfig
|
||||
- Access via `CliConfig::as_groups()` to enable gradual adoption.
|
||||
|
||||
Python LLVM Builder Split — Phase A (incremental)
|
||||
- Extracted entry wrapper creation to `src/llvm_py/builders/entry.py::ensure_ny_main(builder)` and delegated from `build_from_mir`.
|
||||
- Added scaffolding for function lowering split: `src/llvm_py/builders/function_lower.py` (not yet wired for all paths).
|
||||
Refactor Plan (next 1–2 weeks)
|
||||
1) Split parse_box_declaration (667 lines) in src/parser/declarations/box_definition.rs
|
||||
- Targets (line ranges are indicative):
|
||||
|
||||
161
src/cli.rs
161
src/cli.rs
@ -7,6 +7,7 @@
|
||||
|
||||
use clap::{Arg, ArgMatches, Command};
|
||||
use serde_json;
|
||||
use std::fmt::Debug as _; // for derive Debug consistency
|
||||
|
||||
/// Command-line configuration structure
|
||||
#[derive(Debug, Clone)]
|
||||
@ -77,6 +78,99 @@ pub struct CliConfig {
|
||||
pub emit_exe_libs: Option<String>,
|
||||
}
|
||||
|
||||
/// Grouped views (Phase 1: non-breaking). These structs provide a categorized
|
||||
/// lens over the flat CliConfig without changing public fields.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InputConfig {
|
||||
pub file: Option<String>,
|
||||
pub cli_usings: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DebugConfig {
|
||||
pub debug_fuel: Option<usize>,
|
||||
pub dump_ast: bool,
|
||||
pub dump_mir: bool,
|
||||
pub verify_mir: bool,
|
||||
pub mir_verbose: bool,
|
||||
pub mir_verbose_effects: bool,
|
||||
pub cli_verbose: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BackendConfig {
|
||||
pub backend: String,
|
||||
// VM
|
||||
pub vm_stats: bool,
|
||||
pub vm_stats_json: bool,
|
||||
// JIT
|
||||
pub jit: JitConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct JitConfig {
|
||||
pub exec: bool,
|
||||
pub stats: bool,
|
||||
pub stats_json: bool,
|
||||
pub dump: bool,
|
||||
pub events: bool,
|
||||
pub events_compile: bool,
|
||||
pub events_runtime: bool,
|
||||
pub events_path: Option<String>,
|
||||
pub threshold: Option<u32>,
|
||||
pub phi_min: bool,
|
||||
pub hostcall: bool,
|
||||
pub handle_debug: bool,
|
||||
pub native_f64: bool,
|
||||
pub native_bool: bool,
|
||||
pub only: bool,
|
||||
pub direct: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BuildConfig {
|
||||
pub path: Option<String>,
|
||||
pub app: Option<String>,
|
||||
pub out: Option<String>,
|
||||
pub aot: Option<String>,
|
||||
pub profile: Option<String>,
|
||||
pub target: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EmitConfig {
|
||||
pub emit_cfg: Option<String>,
|
||||
pub emit_mir_json: Option<String>,
|
||||
pub emit_exe: Option<String>,
|
||||
pub emit_exe_nyrt: Option<String>,
|
||||
pub emit_exe_libs: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ParserPipeConfig {
|
||||
pub parser_ny: bool,
|
||||
pub ny_parser_pipe: bool,
|
||||
pub json_file: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CliGroups {
|
||||
pub input: InputConfig,
|
||||
pub debug: DebugConfig,
|
||||
pub backend: BackendConfig,
|
||||
pub build: BuildConfig,
|
||||
pub emit: EmitConfig,
|
||||
pub parser: ParserPipeConfig,
|
||||
pub gc_mode: Option<String>,
|
||||
pub compile_wasm: bool,
|
||||
pub compile_native: bool,
|
||||
pub output_file: Option<String>,
|
||||
pub benchmark: bool,
|
||||
pub iterations: u32,
|
||||
pub run_task: Option<String>,
|
||||
pub load_ny_plugins: bool,
|
||||
}
|
||||
|
||||
impl CliConfig {
|
||||
/// Parse command-line arguments and return configuration
|
||||
pub fn parse() -> Self {
|
||||
@ -101,6 +195,73 @@ impl CliConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/// Non-breaking grouped view for downstream code to gradually adopt.
|
||||
pub fn as_groups(&self) -> CliGroups {
|
||||
CliGroups {
|
||||
input: InputConfig { file: self.file.clone(), cli_usings: self.cli_usings.clone() },
|
||||
debug: DebugConfig {
|
||||
debug_fuel: self.debug_fuel,
|
||||
dump_ast: self.dump_ast,
|
||||
dump_mir: self.dump_mir,
|
||||
verify_mir: self.verify_mir,
|
||||
mir_verbose: self.mir_verbose,
|
||||
mir_verbose_effects: self.mir_verbose_effects,
|
||||
cli_verbose: self.cli_verbose,
|
||||
},
|
||||
backend: BackendConfig {
|
||||
backend: self.backend.clone(),
|
||||
vm_stats: self.vm_stats,
|
||||
vm_stats_json: self.vm_stats_json,
|
||||
jit: JitConfig {
|
||||
exec: self.jit_exec,
|
||||
stats: self.jit_stats,
|
||||
stats_json: self.jit_stats_json,
|
||||
dump: self.jit_dump,
|
||||
events: self.jit_events,
|
||||
events_compile: self.jit_events_compile,
|
||||
events_runtime: self.jit_events_runtime,
|
||||
events_path: self.jit_events_path.clone(),
|
||||
threshold: self.jit_threshold,
|
||||
phi_min: self.jit_phi_min,
|
||||
hostcall: self.jit_hostcall,
|
||||
handle_debug: self.jit_handle_debug,
|
||||
native_f64: self.jit_native_f64,
|
||||
native_bool: self.jit_native_bool,
|
||||
only: self.jit_only,
|
||||
direct: self.jit_direct,
|
||||
},
|
||||
},
|
||||
build: BuildConfig {
|
||||
path: self.build_path.clone(),
|
||||
app: self.build_app.clone(),
|
||||
out: self.build_out.clone(),
|
||||
aot: self.build_aot.clone(),
|
||||
profile: self.build_profile.clone(),
|
||||
target: self.build_target.clone(),
|
||||
},
|
||||
emit: EmitConfig {
|
||||
emit_cfg: self.emit_cfg.clone(),
|
||||
emit_mir_json: self.emit_mir_json.clone(),
|
||||
emit_exe: self.emit_exe.clone(),
|
||||
emit_exe_nyrt: self.emit_exe_nyrt.clone(),
|
||||
emit_exe_libs: self.emit_exe_libs.clone(),
|
||||
},
|
||||
parser: ParserPipeConfig {
|
||||
parser_ny: self.parser_ny,
|
||||
ny_parser_pipe: self.ny_parser_pipe,
|
||||
json_file: self.json_file.clone(),
|
||||
},
|
||||
gc_mode: self.gc_mode.clone(),
|
||||
compile_wasm: self.compile_wasm,
|
||||
compile_native: self.compile_native,
|
||||
output_file: self.output_file.clone(),
|
||||
benchmark: self.benchmark,
|
||||
iterations: self.iterations,
|
||||
run_task: self.run_task.clone(),
|
||||
load_ny_plugins: self.load_ny_plugins,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build the clap Command structure
|
||||
fn build_command() -> Command {
|
||||
Command::new("nyash")
|
||||
|
||||
68
src/llvm_py/builders/entry.py
Normal file
68
src/llvm_py/builders/entry.py
Normal file
@ -0,0 +1,68 @@
|
||||
from typing import Optional
|
||||
|
||||
def ensure_ny_main(builder) -> None:
|
||||
"""Ensure ny_main wrapper exists by delegating to Main.main/1 or main().
|
||||
Modifies builder.module in place; no return value.
|
||||
"""
|
||||
has_ny_main = any(f.name == 'ny_main' for f in builder.module.functions)
|
||||
fn_main_box = None
|
||||
fn_main_plain = None
|
||||
for f in builder.module.functions:
|
||||
if f.name == 'Main.main/1':
|
||||
fn_main_box = f
|
||||
elif f.name == 'main':
|
||||
fn_main_plain = f
|
||||
target_fn = fn_main_box or fn_main_plain
|
||||
if target_fn is None or has_ny_main:
|
||||
return
|
||||
|
||||
# Hide the target to avoid symbol conflicts
|
||||
try:
|
||||
target_fn.linkage = 'private'
|
||||
except Exception:
|
||||
pass
|
||||
# i32 ny_main() { return (i32) Main.main(args) | main(); }
|
||||
from llvmlite import ir
|
||||
ny_main_ty = ir.FunctionType(builder.i64, [])
|
||||
ny_main = ir.Function(builder.module, ny_main_ty, name='ny_main')
|
||||
entry = ny_main.append_basic_block('entry')
|
||||
b = ir.IRBuilder(entry)
|
||||
if fn_main_box is not None:
|
||||
# Build default args = new ArrayBox() via nyash.env.box.new_i64x
|
||||
i64 = builder.i64
|
||||
i8 = builder.i8
|
||||
i8p = builder.i8p
|
||||
# Declare callee
|
||||
callee = None
|
||||
for f in builder.module.functions:
|
||||
if f.name == 'nyash.env.box.new_i64x':
|
||||
callee = f
|
||||
break
|
||||
if callee is None:
|
||||
callee = ir.Function(builder.module, ir.FunctionType(i64, [i8p, i64, i64, i64, i64, i64]), name='nyash.env.box.new_i64x')
|
||||
# Create "ArrayBox\0" global
|
||||
sbytes = b"ArrayBox\0"
|
||||
arr_ty = ir.ArrayType(i8, len(sbytes))
|
||||
g = ir.GlobalVariable(builder.module, arr_ty, name='.ny_main_arraybox')
|
||||
g.linkage = 'private'
|
||||
g.global_constant = True
|
||||
g.initializer = ir.Constant(arr_ty, bytearray(sbytes))
|
||||
c0 = ir.Constant(builder.i32, 0)
|
||||
ptr = b.gep(g, [c0, c0], inbounds=True)
|
||||
zero = ir.Constant(i64, 0)
|
||||
args_handle = b.call(callee, [ptr, zero, zero, zero, zero, zero], name='ny_main_args')
|
||||
rv = b.call(fn_main_box, [args_handle], name='call_Main_main_1')
|
||||
else:
|
||||
# Plain main() fallback
|
||||
if len(fn_main_plain.args) == 0:
|
||||
rv = b.call(fn_main_plain, [], name='call_user_main')
|
||||
else:
|
||||
rv = ir.Constant(builder.i64, 0)
|
||||
if hasattr(rv, 'type') and isinstance(rv.type, ir.IntType) and rv.type.width != 32:
|
||||
rv64 = b.trunc(rv, builder.i64) if rv.type.width > 64 else b.zext(rv, builder.i64)
|
||||
b.ret(rv64)
|
||||
elif hasattr(rv, 'type') and isinstance(rv.type, ir.IntType) and rv.type.width == 64:
|
||||
b.ret(rv)
|
||||
else:
|
||||
b.ret(ir.Constant(builder.i64, 0))
|
||||
|
||||
84
src/llvm_py/builders/function_lower.py
Normal file
84
src/llvm_py/builders/function_lower.py
Normal file
@ -0,0 +1,84 @@
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
def lower_function(builder, func_data: Dict[str, Any]):
|
||||
"""Lower a single MIR function to LLVM IR using the given builder context.
|
||||
|
||||
This helper is a thin wrapper that delegates to the NyashLLVMBuilder's
|
||||
existing methods/attributes, enabling gradual file decomposition without
|
||||
changing semantics.
|
||||
"""
|
||||
name = func_data.get("name", "unknown")
|
||||
builder.current_function_name = name
|
||||
|
||||
import re
|
||||
params = func_data.get("params", [])
|
||||
blocks = func_data.get("blocks", [])
|
||||
|
||||
# Determine function signature
|
||||
if name == "ny_main":
|
||||
func_ty = builder.i32.func_type([])
|
||||
else:
|
||||
m = re.search(r"/(\d+)$", name)
|
||||
arity = int(m.group(1)) if m else len(params)
|
||||
param_types = [builder.i64] * arity
|
||||
func_ty = builder.i64.func_type(param_types)
|
||||
|
||||
try:
|
||||
builder.vmap.clear()
|
||||
except Exception:
|
||||
builder.vmap = {}
|
||||
builder.bb_map = {}
|
||||
builder.preds = {}
|
||||
builder.block_end_values = {}
|
||||
builder.def_blocks = {}
|
||||
builder.predeclared_ret_phis = {}
|
||||
|
||||
# Ensure function exists or create one
|
||||
fn = None
|
||||
for f in builder.module.functions:
|
||||
if f.name == name:
|
||||
fn = f
|
||||
break
|
||||
if fn is None:
|
||||
from llvmlite import ir
|
||||
fn = ir.Function(builder.module, func_ty, name=name)
|
||||
|
||||
# Create all basic blocks first
|
||||
from llvmlite import ir
|
||||
block_by_id = {}
|
||||
for b in blocks:
|
||||
bbid = int(b.get("id", 0))
|
||||
bb = fn.append_basic_block(name=f"bb{bbid}")
|
||||
block_by_id[bbid] = bb
|
||||
builder.bb_map[bbid] = bb
|
||||
|
||||
# Predeclare ret PHIs if needed (if-merge prepass)
|
||||
from prepass.if_merge import plan_ret_phi_predeclare
|
||||
plan = plan_ret_phi_predeclare(block_by_id)
|
||||
if plan:
|
||||
if not hasattr(builder, 'block_phi_incomings') or builder.block_phi_incomings is None:
|
||||
builder.block_phi_incomings = {}
|
||||
for (bbid, pairs) in plan.items():
|
||||
for (ret_vid, preds_list) in pairs.items():
|
||||
builder.block_phi_incomings.setdefault(int(bbid), {}).setdefault(int(ret_vid), [])
|
||||
builder.block_phi_incomings[int(bbid)][int(ret_vid)] = [(int(p), int(ret_vid)) for p in preds_list]
|
||||
|
||||
# Lower instructions per block
|
||||
from llvmlite.ir import IRBuilder
|
||||
from instructions import dispatcher # if exists; else inline lowerers
|
||||
for b in blocks:
|
||||
bbid = int(b.get("id", 0))
|
||||
bb = block_by_id[bbid]
|
||||
builder_bb = IRBuilder(bb)
|
||||
builder.resolver.attach_function_and_block(fn, bb)
|
||||
insts = b.get("insts", [])
|
||||
for inst in insts:
|
||||
op = inst.get("op")
|
||||
# Delegate to existing NyashLLVMBuilder method for now
|
||||
builder.lower_instruction(op, inst, builder_bb)
|
||||
|
||||
# Finalize PHIs after the function is fully lowered
|
||||
from phi_wiring import finalize_phis as _finalize_phis
|
||||
_finalize_phis(builder)
|
||||
|
||||
@ -125,66 +125,35 @@ class NyashLLVMBuilder:
|
||||
for func_data in functions:
|
||||
self.lower_function(func_data)
|
||||
|
||||
# Create ny_main wrapper if necessary
|
||||
has_ny_main = any(f.name == 'ny_main' for f in self.module.functions)
|
||||
# Prefer static box entry: Main.main/1; fallback to plain main (0-arity)
|
||||
fn_main_box = None
|
||||
fn_main_plain = None
|
||||
for f in self.module.functions:
|
||||
if f.name == 'Main.main/1':
|
||||
fn_main_box = f
|
||||
elif f.name == 'main':
|
||||
fn_main_plain = f
|
||||
target_fn = fn_main_box or fn_main_plain
|
||||
if target_fn is not None and not has_ny_main:
|
||||
# Hide the target to avoid symbol conflicts
|
||||
# Create ny_main wrapper if necessary (extracted helper)
|
||||
try:
|
||||
from builders.entry import ensure_ny_main as _ensure_ny_main
|
||||
_ensure_ny_main(self)
|
||||
except Exception:
|
||||
# Fallback to legacy in-place logic if helper import fails
|
||||
try:
|
||||
target_fn.linkage = 'private'
|
||||
has_ny_main = any(f.name == 'ny_main' for f in self.module.functions)
|
||||
fn_main_box = None
|
||||
fn_main_plain = None
|
||||
for f in self.module.functions:
|
||||
if f.name == 'Main.main/1':
|
||||
fn_main_box = f
|
||||
elif f.name == 'main':
|
||||
fn_main_plain = f
|
||||
target_fn = fn_main_box or fn_main_plain
|
||||
if target_fn is not None and not has_ny_main:
|
||||
ny_main_ty = ir.FunctionType(self.i64, [])
|
||||
ny_main = ir.Function(self.module, ny_main_ty, name='ny_main')
|
||||
entry = ny_main.append_basic_block('entry')
|
||||
b = ir.IRBuilder(entry)
|
||||
rv = ir.Constant(self.i64, 0)
|
||||
if fn_main_box is not None:
|
||||
rv = b.call(fn_main_box, [], name='call_Main_main_1')
|
||||
elif fn_main_plain is not None and len(fn_main_plain.args) == 0:
|
||||
rv = b.call(fn_main_plain, [], name='call_user_main')
|
||||
b.ret(rv)
|
||||
except Exception:
|
||||
pass
|
||||
# i32 ny_main() { return (i32) Main.main(args) | main(); }
|
||||
ny_main_ty = ir.FunctionType(self.i64, [])
|
||||
ny_main = ir.Function(self.module, ny_main_ty, name='ny_main')
|
||||
entry = ny_main.append_basic_block('entry')
|
||||
b = ir.IRBuilder(entry)
|
||||
if fn_main_box is not None:
|
||||
# Build default args = new ArrayBox() via nyash.env.box.new_i64x
|
||||
i64 = self.i64
|
||||
i8 = self.i8
|
||||
i8p = self.i8p
|
||||
# Declare callee
|
||||
callee = None
|
||||
for f in self.module.functions:
|
||||
if f.name == 'nyash.env.box.new_i64x':
|
||||
callee = f
|
||||
break
|
||||
if callee is None:
|
||||
callee = ir.Function(self.module, ir.FunctionType(i64, [i8p, i64, i64, i64, i64, i64]), name='nyash.env.box.new_i64x')
|
||||
# Create "ArrayBox\0" global
|
||||
sbytes = b"ArrayBox\0"
|
||||
arr_ty = ir.ArrayType(i8, len(sbytes))
|
||||
g = ir.GlobalVariable(self.module, arr_ty, name='.ny_main_arraybox')
|
||||
g.linkage = 'private'
|
||||
g.global_constant = True
|
||||
g.initializer = ir.Constant(arr_ty, bytearray(sbytes))
|
||||
c0 = ir.Constant(self.i32, 0)
|
||||
ptr = b.gep(g, [c0, c0], inbounds=True)
|
||||
zero = ir.Constant(i64, 0)
|
||||
args_handle = b.call(callee, [ptr, zero, zero, zero, zero, zero], name='ny_main_args')
|
||||
rv = b.call(fn_main_box, [args_handle], name='call_Main_main_1')
|
||||
else:
|
||||
# Plain main() fallback
|
||||
if len(fn_main_plain.args) == 0:
|
||||
rv = b.call(fn_main_plain, [], name='call_user_main')
|
||||
else:
|
||||
rv = ir.Constant(self.i64, 0)
|
||||
if hasattr(rv, 'type') and isinstance(rv.type, ir.IntType) and rv.type.width != 32:
|
||||
rv64 = b.trunc(rv, self.i64) if rv.type.width > 64 else b.zext(rv, self.i64)
|
||||
b.ret(rv64)
|
||||
elif hasattr(rv, 'type') and isinstance(rv.type, ir.IntType) and rv.type.width == 64:
|
||||
b.ret(rv)
|
||||
else:
|
||||
b.ret(ir.Constant(self.i64, 0))
|
||||
|
||||
ir_text = str(self.module)
|
||||
# Optional IR dump to file for debugging
|
||||
@ -215,6 +184,16 @@ class NyashLLVMBuilder:
|
||||
|
||||
def lower_function(self, func_data: Dict[str, Any]):
|
||||
"""Lower a single MIR function to LLVM IR"""
|
||||
# Optional: delegate to external helper when gated (incremental split)
|
||||
try:
|
||||
if os.environ.get('NYASH_LLVM_USE_HELPER_LOWER') == '1':
|
||||
try:
|
||||
from builders.function_lower import lower_function as _lower
|
||||
return _lower(self, func_data)
|
||||
except Exception as _e:
|
||||
trace_debug(f"[Python LLVM] helper lower_function failed, falling back: {_e}")
|
||||
except Exception:
|
||||
pass
|
||||
name = func_data.get("name", "unknown")
|
||||
self.current_function_name = name
|
||||
import re
|
||||
|
||||
@ -19,7 +19,8 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
}
|
||||
|
||||
// Direct v0 bridge when requested via CLI/env
|
||||
let use_ny_parser = runner.config.parser_ny
|
||||
let groups = runner.config.as_groups();
|
||||
let use_ny_parser = groups.parser.parser_ny
|
||||
|| std::env::var("NYASH_USE_NY_PARSER").ok().as_deref() == Some("1");
|
||||
if use_ny_parser {
|
||||
let code = match fs::read_to_string(filename) {
|
||||
@ -43,7 +44,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
}
|
||||
|
||||
// AST dump mode
|
||||
if runner.config.dump_ast {
|
||||
if groups.debug.dump_ast {
|
||||
println!("🧠 Nyash AST Dump - Processing file: {}", filename);
|
||||
let code = match fs::read_to_string(filename) {
|
||||
Ok(content) => content,
|
||||
@ -64,14 +65,14 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
}
|
||||
|
||||
// MIR dump/verify
|
||||
if runner.config.dump_mir || runner.config.verify_mir {
|
||||
if groups.debug.dump_mir || groups.debug.verify_mir {
|
||||
crate::cli_v!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
|
||||
runner.execute_mir_mode(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
// WASM / AOT (feature-gated)
|
||||
if runner.config.compile_wasm {
|
||||
if groups.compile_wasm {
|
||||
#[cfg(feature = "wasm-backend")]
|
||||
{
|
||||
super::modes::wasm::execute_wasm_mode(runner, filename);
|
||||
@ -83,7 +84,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
if runner.config.compile_native {
|
||||
if groups.compile_native {
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
{
|
||||
runner.execute_aot_mode(filename);
|
||||
@ -97,7 +98,7 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
}
|
||||
|
||||
// Backend selection
|
||||
match runner.config.backend.as_str() {
|
||||
match groups.backend.backend.as_str() {
|
||||
"mir" => {
|
||||
crate::cli_v!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
|
||||
runner.execute_mir_mode(filename);
|
||||
@ -154,7 +155,8 @@ pub(crate) fn execute_file_with_backend(runner: &NyashRunner, filename: &str) {
|
||||
impl NyashRunner {
|
||||
pub(crate) fn execute_mir_module(&self, module: &crate::mir::MirModule) {
|
||||
// If CLI requested MIR JSON emit, write to file and exit immediately.
|
||||
if let Some(path) = self.config.emit_mir_json.as_ref() {
|
||||
let groups = self.config.as_groups();
|
||||
if let Some(path) = groups.emit.emit_mir_json.as_ref() {
|
||||
let p = std::path::Path::new(path);
|
||||
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness_bin(module, p) {
|
||||
eprintln!("❌ MIR JSON emit error: {}", e);
|
||||
@ -164,12 +166,12 @@ impl NyashRunner {
|
||||
std::process::exit(0);
|
||||
}
|
||||
// If CLI requested EXE emit, generate JSON then invoke ny-llvmc to link NyRT and exit.
|
||||
if let Some(exe_out) = self.config.emit_exe.as_ref() {
|
||||
if let Some(exe_out) = groups.emit.emit_exe.as_ref() {
|
||||
if let Err(e) = crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_bin(
|
||||
module,
|
||||
exe_out,
|
||||
self.config.emit_exe_nyrt.as_deref(),
|
||||
self.config.emit_exe_libs.as_deref(),
|
||||
groups.emit.emit_exe_nyrt.as_deref(),
|
||||
groups.emit.emit_exe_libs.as_deref(),
|
||||
) {
|
||||
eprintln!("❌ {}", e);
|
||||
std::process::exit(1);
|
||||
|
||||
@ -54,6 +54,7 @@ impl NyashRunner {
|
||||
|
||||
/// Run Nyash based on the configuration
|
||||
pub fn run(&self) {
|
||||
let groups = self.config.as_groups();
|
||||
// Build system (MVP): nyash --build <nyash.toml>
|
||||
if let Some(cfg_path) = self.config.build_path.clone() {
|
||||
if let Err(e) = self.run_build_mvp(&cfg_path) {
|
||||
@ -346,41 +347,41 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
// Optional: enable VM stats via CLI flags
|
||||
if self.config.vm_stats {
|
||||
if groups.backend.vm_stats {
|
||||
std::env::set_var("NYASH_VM_STATS", "1");
|
||||
}
|
||||
if self.config.vm_stats_json {
|
||||
if groups.backend.vm_stats_json {
|
||||
// Prefer explicit JSON flag over any default
|
||||
std::env::set_var("NYASH_VM_STATS_JSON", "1");
|
||||
}
|
||||
// Optional: JIT controls via CLI flags (centralized)
|
||||
{
|
||||
// CLI opt-in for JSONL events
|
||||
if self.config.jit_events {
|
||||
if groups.backend.jit.events {
|
||||
std::env::set_var("NYASH_JIT_EVENTS", "1");
|
||||
}
|
||||
if self.config.jit_events_compile {
|
||||
if groups.backend.jit.events_compile {
|
||||
std::env::set_var("NYASH_JIT_EVENTS_COMPILE", "1");
|
||||
}
|
||||
if self.config.jit_events_runtime {
|
||||
if groups.backend.jit.events_runtime {
|
||||
std::env::set_var("NYASH_JIT_EVENTS_RUNTIME", "1");
|
||||
}
|
||||
if let Some(ref p) = self.config.jit_events_path {
|
||||
if let Some(ref p) = groups.backend.jit.events_path {
|
||||
std::env::set_var("NYASH_JIT_EVENTS_PATH", p);
|
||||
}
|
||||
let mut jc = nyash_rust::jit::config::JitConfig::from_env();
|
||||
jc.exec |= self.config.jit_exec;
|
||||
jc.stats |= self.config.jit_stats;
|
||||
jc.stats_json |= self.config.jit_stats_json;
|
||||
jc.dump |= self.config.jit_dump;
|
||||
if self.config.jit_threshold.is_some() {
|
||||
jc.threshold = self.config.jit_threshold;
|
||||
jc.exec |= groups.backend.jit.exec;
|
||||
jc.stats |= groups.backend.jit.stats;
|
||||
jc.stats_json |= groups.backend.jit.stats_json;
|
||||
jc.dump |= groups.backend.jit.dump;
|
||||
if groups.backend.jit.threshold.is_some() {
|
||||
jc.threshold = groups.backend.jit.threshold;
|
||||
}
|
||||
jc.phi_min |= self.config.jit_phi_min;
|
||||
jc.hostcall |= self.config.jit_hostcall;
|
||||
jc.handle_debug |= self.config.jit_handle_debug;
|
||||
jc.native_f64 |= self.config.jit_native_f64;
|
||||
jc.native_bool |= self.config.jit_native_bool;
|
||||
jc.phi_min |= groups.backend.jit.phi_min;
|
||||
jc.hostcall |= groups.backend.jit.hostcall;
|
||||
jc.handle_debug |= groups.backend.jit.handle_debug;
|
||||
jc.native_f64 |= groups.backend.jit.native_f64;
|
||||
jc.native_bool |= groups.backend.jit.native_bool;
|
||||
// If observability is enabled and no threshold is provided, force threshold=1 so lowering runs and emits events
|
||||
let events_on = std::env::var("NYASH_JIT_EVENTS").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_JIT_EVENTS_COMPILE").ok().as_deref() == Some("1")
|
||||
@ -388,14 +389,14 @@ impl NyashRunner {
|
||||
if events_on && jc.threshold.is_none() {
|
||||
jc.threshold = Some(1);
|
||||
}
|
||||
if self.config.jit_only {
|
||||
if groups.backend.jit.only {
|
||||
std::env::set_var("NYASH_JIT_ONLY", "1");
|
||||
}
|
||||
// Apply runtime capability probe (e.g., disable b1 ABI if unsupported)
|
||||
let caps = nyash_rust::jit::config::probe_capabilities();
|
||||
jc = nyash_rust::jit::config::apply_runtime_caps(jc, caps);
|
||||
// Optional DOT emit via CLI (ensures dump is on when path specified)
|
||||
if let Some(path) = &self.config.emit_cfg {
|
||||
if let Some(path) = &groups.emit.emit_cfg {
|
||||
std::env::set_var("NYASH_JIT_DOT", path);
|
||||
jc.dump = true;
|
||||
}
|
||||
|
||||
@ -176,10 +176,11 @@ impl NyashRunner {
|
||||
// Force JIT mode for this run
|
||||
std::env::set_var("NYASH_JIT_EXEC", "1");
|
||||
std::env::set_var("NYASH_JIT_THRESHOLD", "1");
|
||||
if self.config.jit_stats {
|
||||
let groups = self.config.as_groups();
|
||||
if groups.backend.jit.stats {
|
||||
std::env::set_var("NYASH_JIT_STATS", "1");
|
||||
}
|
||||
if self.config.jit_stats_json {
|
||||
if groups.backend.jit.stats_json {
|
||||
std::env::set_var("NYASH_JIT_STATS_JSON", "1");
|
||||
}
|
||||
let start = std::time::Instant::now();
|
||||
|
||||
@ -27,7 +27,8 @@ impl NyashRunner {
|
||||
}
|
||||
}
|
||||
// Direct v0 bridge when requested via CLI/env
|
||||
let use_ny_parser = self.config.parser_ny || std::env::var("NYASH_USE_NY_PARSER").ok().as_deref() == Some("1");
|
||||
let groups = self.config.as_groups();
|
||||
let use_ny_parser = groups.parser.parser_ny || std::env::var("NYASH_USE_NY_PARSER").ok().as_deref() == Some("1");
|
||||
if use_ny_parser {
|
||||
let code = match fs::read_to_string(filename) {
|
||||
Ok(content) => content,
|
||||
@ -45,7 +46,7 @@ impl NyashRunner {
|
||||
}
|
||||
}
|
||||
// AST dump mode
|
||||
if self.config.dump_ast {
|
||||
if groups.debug.dump_ast {
|
||||
println!("🧠 Nyash AST Dump - Processing file: {}", filename);
|
||||
let code = match fs::read_to_string(filename) {
|
||||
Ok(content) => content,
|
||||
@ -60,20 +61,20 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
// MIR dump/verify
|
||||
if self.config.dump_mir || self.config.verify_mir {
|
||||
if groups.debug.dump_mir || groups.debug.verify_mir {
|
||||
crate::cli_v!("🚀 Nyash MIR Compiler - Processing file: {} 🚀", filename);
|
||||
self.execute_mir_mode(filename);
|
||||
return;
|
||||
}
|
||||
|
||||
// WASM / AOT (feature-gated)
|
||||
if self.config.compile_wasm {
|
||||
if groups.compile_wasm {
|
||||
#[cfg(feature = "wasm-backend")]
|
||||
{ self.execute_wasm_mode(filename); return; }
|
||||
#[cfg(not(feature = "wasm-backend"))]
|
||||
{ eprintln!("❌ WASM backend not available. Please rebuild with: cargo build --features wasm-backend"); process::exit(1); }
|
||||
}
|
||||
if self.config.compile_native {
|
||||
if groups.compile_native {
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
{ self.execute_aot_mode(filename); return; }
|
||||
#[cfg(not(feature = "cranelift-jit"))]
|
||||
@ -81,7 +82,7 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
// Backend selection
|
||||
match self.config.backend.as_str() {
|
||||
match groups.backend.backend.as_str() {
|
||||
"mir" => {
|
||||
crate::cli_v!("🚀 Nyash MIR Interpreter - Executing file: {} 🚀", filename);
|
||||
self.execute_mir_interpreter_mode(filename);
|
||||
|
||||
@ -36,8 +36,9 @@ impl NyashRunner {
|
||||
}
|
||||
};
|
||||
|
||||
let groups = self.config.as_groups();
|
||||
// Verify MIR if requested
|
||||
if self.config.verify_mir {
|
||||
if groups.debug.verify_mir {
|
||||
println!("🔍 Verifying MIR...");
|
||||
match &compile_result.verification_result {
|
||||
Ok(()) => println!("✅ MIR verification passed!"),
|
||||
@ -52,13 +53,13 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
// Dump MIR if requested
|
||||
if self.config.dump_mir {
|
||||
let mut printer = if self.config.mir_verbose {
|
||||
if groups.debug.dump_mir {
|
||||
let mut printer = if groups.debug.mir_verbose {
|
||||
MirPrinter::verbose()
|
||||
} else {
|
||||
MirPrinter::new()
|
||||
};
|
||||
if self.config.mir_verbose_effects {
|
||||
if groups.debug.mir_verbose_effects {
|
||||
printer.set_show_effects_inline(true);
|
||||
}
|
||||
println!("🚀 MIR Output for {}:", filename);
|
||||
@ -66,7 +67,7 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
// Emit MIR JSON if requested and exit
|
||||
if let Some(path) = self.config.emit_mir_json.as_ref() {
|
||||
if let Some(path) = groups.emit.emit_mir_json.as_ref() {
|
||||
let p = std::path::Path::new(path);
|
||||
if let Err(e) = crate::runner::mir_json_emit::emit_mir_json_for_harness(&compile_result.module, p) {
|
||||
eprintln!("❌ MIR JSON emit error: {}", e);
|
||||
@ -77,12 +78,12 @@ impl NyashRunner {
|
||||
}
|
||||
|
||||
// Emit native executable via ny-llvmc (crate) and exit
|
||||
if let Some(exe_out) = self.config.emit_exe.as_ref() {
|
||||
if let Some(exe_out) = groups.emit.emit_exe.as_ref() {
|
||||
if let Err(e) = crate::runner::modes::common_util::exec::ny_llvmc_emit_exe_lib(
|
||||
&compile_result.module,
|
||||
exe_out,
|
||||
self.config.emit_exe_nyrt.as_deref(),
|
||||
self.config.emit_exe_libs.as_deref(),
|
||||
groups.emit.emit_exe_nyrt.as_deref(),
|
||||
groups.emit.emit_exe_libs.as_deref(),
|
||||
) {
|
||||
eprintln!("❌ {}", e);
|
||||
std::process::exit(1);
|
||||
|
||||
@ -15,10 +15,11 @@ impl NyashRunner {
|
||||
/// Try to handle `--ny-parser-pipe` / `--json-file` flow.
|
||||
/// Returns true if the request was handled (program should return early).
|
||||
pub(super) fn try_run_json_v0_pipe(&self) -> bool {
|
||||
if !(self.config.ny_parser_pipe || self.config.json_file.is_some()) {
|
||||
let groups = self.config.as_groups();
|
||||
if !(groups.parser.ny_parser_pipe || groups.parser.json_file.is_some()) {
|
||||
return false;
|
||||
}
|
||||
let json = if let Some(path) = &self.config.json_file {
|
||||
let json = if let Some(path) = &groups.parser.json_file {
|
||||
match std::fs::read_to_string(path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
|
||||
Reference in New Issue
Block a user