2025-08-26 04:39:16 +09:00
|
|
|
use super::super::NyashRunner;
|
2025-09-05 13:29:17 +09:00
|
|
|
use crate::runner::json_v0_bridge;
|
2025-09-28 12:19:49 +09:00
|
|
|
#[cfg(feature = "interpreter-legacy")]
|
2025-09-26 14:34:42 +09:00
|
|
|
use nyash_rust::{interpreter::NyashInterpreter, parser::NyashParser};
|
2025-09-28 12:19:49 +09:00
|
|
|
#[cfg(not(feature = "interpreter-legacy"))]
|
|
|
|
|
use nyash_rust::parser::NyashParser;
|
2025-09-05 13:29:17 +09:00
|
|
|
// Use the library crate's plugin init module rather than the bin crate root
|
2025-09-26 14:34:42 +09:00
|
|
|
use crate::cli_v;
|
|
|
|
|
use crate::runner::pipeline::{resolve_using_target, suggest_in_base};
|
|
|
|
|
use crate::runner::trace::cli_verbose;
|
2025-09-15 18:44:49 +09:00
|
|
|
use std::io::Read;
|
|
|
|
|
use std::process::Stdio;
|
|
|
|
|
use std::thread::sleep;
|
2025-09-26 14:34:42 +09:00
|
|
|
use std::time::{Duration, Instant};
|
|
|
|
|
use std::{fs, process};
|
2025-08-26 04:39:16 +09:00
|
|
|
|
2025-09-16 00:01:31 +09:00
|
|
|
// (moved) suggest_in_base is now in runner/pipeline.rs
|
2025-09-07 07:36:15 +09:00
|
|
|
|
2025-09-28 12:19:49 +09:00
|
|
|
#[cfg(feature = "interpreter-legacy")]
|
2025-08-26 04:39:16 +09:00
|
|
|
impl NyashRunner {
|
2025-09-22 21:52:39 +09:00
|
|
|
// legacy run_file_legacy removed (was commented out)
|
2025-08-26 04:42:52 +09:00
|
|
|
|
2025-09-17 07:12:15 +09:00
|
|
|
/// Helper: run PyVM harness over a MIR module, returning the exit code
|
2025-09-26 14:34:42 +09:00
|
|
|
fn run_pyvm_harness(
|
|
|
|
|
&self,
|
|
|
|
|
module: &nyash_rust::mir::MirModule,
|
|
|
|
|
tag: &str,
|
|
|
|
|
) -> Result<i32, String> {
|
2025-09-17 20:33:19 +09:00
|
|
|
super::common_util::pyvm::run_pyvm_harness(module, tag)
|
2025-09-17 07:12:15 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Helper: try external selfhost compiler EXE to parse Ny -> JSON v0 and return MIR module
|
|
|
|
|
/// Returns Some(module) on success, None on failure (timeout/invalid output/missing exe)
|
2025-09-26 14:34:42 +09:00
|
|
|
fn exe_try_parse_json_v0(
|
|
|
|
|
&self,
|
|
|
|
|
filename: &str,
|
|
|
|
|
timeout_ms: u64,
|
|
|
|
|
) -> Option<nyash_rust::mir::MirModule> {
|
2025-09-17 20:33:19 +09:00
|
|
|
super::common_util::selfhost_exe::exe_try_parse_json_v0(filename, timeout_ms)
|
2025-09-17 07:12:15 +09:00
|
|
|
}
|
|
|
|
|
|
2025-09-15 01:21:37 +09:00
|
|
|
/// Phase-15.3: Attempt Ny compiler pipeline (Ny -> JSON v0 via Ny program), then execute MIR
|
2025-09-16 00:01:31 +09:00
|
|
|
pub(crate) fn try_run_ny_compiler_pipeline(&self, filename: &str) -> bool {
|
2025-09-17 01:20:15 +09:00
|
|
|
// Delegate to centralized selfhost pipeline to avoid drift
|
2025-09-22 21:52:39 +09:00
|
|
|
self.try_run_selfhost_pipeline(filename)
|
2025-09-15 01:21:37 +09:00
|
|
|
}
|
|
|
|
|
|
2025-08-26 04:39:16 +09:00
|
|
|
/// Execute Nyash file with interpreter (common helper)
|
|
|
|
|
pub(crate) fn execute_nyash_file(&self, filename: &str) {
|
2025-09-07 07:36:15 +09:00
|
|
|
let quiet_pipe = std::env::var("NYASH_JSON_ONLY").ok().as_deref() == Some("1");
|
2025-09-22 21:52:39 +09:00
|
|
|
// Ensure runtime and plugins are initialized via unified helper (idempotent)
|
|
|
|
|
let groups = self.config.as_groups();
|
|
|
|
|
self.init_runtime_and_plugins(&groups);
|
2025-08-26 04:39:16 +09:00
|
|
|
// Read the file
|
|
|
|
|
let code = match fs::read_to_string(filename) {
|
|
|
|
|
Ok(content) => content,
|
2025-09-26 14:34:42 +09:00
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("❌ Error reading file {}: {}", filename, e);
|
|
|
|
|
process::exit(1);
|
|
|
|
|
}
|
2025-08-26 04:39:16 +09:00
|
|
|
};
|
2025-09-17 06:55:39 +09:00
|
|
|
if crate::config::env::cli_verbose() && !quiet_pipe {
|
2025-09-07 07:36:15 +09:00
|
|
|
println!("📝 File contents:\n{}", code);
|
|
|
|
|
println!("\n🚀 Parsing and executing...\n");
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-26 00:27:02 +09:00
|
|
|
// Using handling: AST-based prelude collection (legacy inlining removed)
|
|
|
|
|
let use_ast = crate::config::env::using_ast_enabled();
|
2025-09-07 07:36:15 +09:00
|
|
|
let mut code_ref: &str = &code;
|
|
|
|
|
let cleaned_code_owned;
|
2025-09-25 10:38:06 +09:00
|
|
|
let mut prelude_asts: Vec<nyash_rust::ast::ASTNode> = Vec::new();
|
2025-09-19 02:07:38 +09:00
|
|
|
if crate::config::env::enable_using() {
|
2025-09-26 14:34:42 +09:00
|
|
|
match crate::runner::modes::common_util::resolve::resolve_prelude_paths_profiled(
|
|
|
|
|
self, &code, filename,
|
|
|
|
|
) {
|
2025-09-26 00:27:02 +09:00
|
|
|
Ok((clean, paths)) => {
|
2025-09-26 14:34:42 +09:00
|
|
|
cleaned_code_owned = clean;
|
|
|
|
|
code_ref = &cleaned_code_owned;
|
2025-09-26 00:27:02 +09:00
|
|
|
if !paths.is_empty() && !use_ast {
|
|
|
|
|
eprintln!("❌ using: AST prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines.");
|
|
|
|
|
std::process::exit(1);
|
|
|
|
|
}
|
2025-09-28 01:33:58 +09:00
|
|
|
if use_ast && !paths.is_empty() {
|
|
|
|
|
match crate::runner::modes::common_util::resolve::parse_preludes_to_asts(self, &paths) {
|
|
|
|
|
Ok(v) => prelude_asts = v,
|
|
|
|
|
Err(e) => { eprintln!("❌ {}", e); std::process::exit(1); }
|
2025-09-25 10:38:06 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-26 14:34:42 +09:00
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("❌ {}", e);
|
|
|
|
|
std::process::exit(1);
|
|
|
|
|
}
|
2025-09-07 07:36:15 +09:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-22 07:54:25 +09:00
|
|
|
// Optional dev sugar: @name[:T] = expr → local name[:T] = expr (line-head only)
|
|
|
|
|
let preexpanded_owned;
|
|
|
|
|
{
|
|
|
|
|
let s = crate::runner::modes::common_util::resolve::preexpand_at_local(code_ref);
|
|
|
|
|
preexpanded_owned = s;
|
|
|
|
|
code_ref = &preexpanded_owned;
|
|
|
|
|
}
|
2025-08-26 04:39:16 +09:00
|
|
|
|
|
|
|
|
// Parse the code with debug fuel limit
|
2025-09-19 15:11:57 +09:00
|
|
|
let groups = self.config.as_groups();
|
2025-09-26 14:34:42 +09:00
|
|
|
eprintln!(
|
|
|
|
|
"🔍 DEBUG: Starting parse with fuel: {:?}...",
|
|
|
|
|
groups.debug.debug_fuel
|
|
|
|
|
);
|
|
|
|
|
let main_ast =
|
|
|
|
|
match NyashParser::parse_from_string_with_fuel(code_ref, groups.debug.debug_fuel) {
|
|
|
|
|
Ok(ast) => {
|
|
|
|
|
eprintln!("🔍 DEBUG: Parse completed, AST created");
|
|
|
|
|
ast
|
|
|
|
|
}
|
|
|
|
|
Err(e) => {
|
2025-11-02 04:13:17 +09:00
|
|
|
eprintln!("❌ Parse error in {}: {}", filename, e);
|
2025-09-26 14:34:42 +09:00
|
|
|
process::exit(1);
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-09-25 10:38:06 +09:00
|
|
|
// When using AST prelude mode, combine prelude ASTs + main AST into one Program
|
|
|
|
|
let ast = if use_ast && !prelude_asts.is_empty() {
|
2025-09-28 01:33:58 +09:00
|
|
|
crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main(prelude_asts, &main_ast)
|
|
|
|
|
} else { main_ast };
|
2025-08-26 04:39:16 +09:00
|
|
|
|
2025-09-25 16:03:29 +09:00
|
|
|
// Optional: dump AST statement kinds for quick diagnostics
|
|
|
|
|
if std::env::var("NYASH_AST_DUMP").ok().as_deref() == Some("1") {
|
|
|
|
|
use nyash_rust::ast::ASTNode;
|
|
|
|
|
eprintln!("[ast] dump start");
|
|
|
|
|
if let ASTNode::Program { statements, .. } = &ast {
|
|
|
|
|
for (i, st) in statements.iter().enumerate().take(50) {
|
|
|
|
|
let kind = match st {
|
2025-09-26 14:34:42 +09:00
|
|
|
ASTNode::BoxDeclaration {
|
|
|
|
|
is_static, name, ..
|
|
|
|
|
} => {
|
|
|
|
|
if *is_static {
|
|
|
|
|
format!("StaticBox({})", name)
|
|
|
|
|
} else {
|
|
|
|
|
format!("Box({})", name)
|
|
|
|
|
}
|
2025-09-25 16:03:29 +09:00
|
|
|
}
|
|
|
|
|
ASTNode::FunctionDeclaration { name, .. } => format!("FuncDecl({})", name),
|
|
|
|
|
ASTNode::FunctionCall { name, .. } => format!("FuncCall({})", name),
|
|
|
|
|
ASTNode::MethodCall { method, .. } => format!("MethodCall({})", method),
|
|
|
|
|
ASTNode::ScopeBox { .. } => "ScopeBox".to_string(),
|
|
|
|
|
ASTNode::ImportStatement { path, .. } => format!("Import({})", path),
|
2025-09-26 14:34:42 +09:00
|
|
|
ASTNode::UsingStatement { namespace_name, .. } => {
|
|
|
|
|
format!("Using({})", namespace_name)
|
|
|
|
|
}
|
2025-09-25 16:03:29 +09:00
|
|
|
_ => format!("{:?}", st),
|
|
|
|
|
};
|
|
|
|
|
eprintln!("[ast] {}: {}", i, kind);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
eprintln!("[ast] dump end");
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-08 04:35:50 +09:00
|
|
|
// Stage-0: import loader (top-level only) — resolve path and register in modules registry
|
|
|
|
|
if let nyash_rust::ast::ASTNode::Program { statements, .. } = &ast {
|
|
|
|
|
for st in statements {
|
|
|
|
|
if let nyash_rust::ast::ASTNode::ImportStatement { path, alias, .. } = st {
|
|
|
|
|
// resolve path relative to current file if not absolute
|
|
|
|
|
let mut p = std::path::PathBuf::from(path);
|
|
|
|
|
if p.is_relative() {
|
|
|
|
|
if let Some(dir) = std::path::Path::new(filename).parent() {
|
|
|
|
|
p = dir.join(&p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let exists = p.exists();
|
|
|
|
|
if !exists {
|
|
|
|
|
if std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1") {
|
2025-09-26 14:34:42 +09:00
|
|
|
eprintln!(
|
|
|
|
|
"❌ import: path not found: {} (from {})",
|
|
|
|
|
p.display(),
|
|
|
|
|
filename
|
|
|
|
|
);
|
2025-09-08 04:35:50 +09:00
|
|
|
process::exit(1);
|
2025-09-26 14:34:42 +09:00
|
|
|
} else if crate::config::env::cli_verbose()
|
|
|
|
|
|| std::env::var("NYASH_IMPORT_TRACE").ok().as_deref() == Some("1")
|
|
|
|
|
{
|
2025-09-08 04:35:50 +09:00
|
|
|
eprintln!("[import] path not found (continuing): {}", p.display());
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-26 14:34:42 +09:00
|
|
|
let key = if let Some(a) = alias {
|
|
|
|
|
a.clone()
|
|
|
|
|
} else {
|
2025-09-08 04:35:50 +09:00
|
|
|
std::path::Path::new(path)
|
2025-09-26 14:34:42 +09:00
|
|
|
.file_stem()
|
|
|
|
|
.and_then(|s| s.to_str())
|
2025-09-08 04:35:50 +09:00
|
|
|
.unwrap_or(path)
|
|
|
|
|
.to_string()
|
|
|
|
|
};
|
2025-09-26 14:34:42 +09:00
|
|
|
let value = if exists {
|
|
|
|
|
p.to_string_lossy().to_string()
|
|
|
|
|
} else {
|
|
|
|
|
path.clone()
|
|
|
|
|
};
|
2025-09-08 04:35:50 +09:00
|
|
|
let sb = nyash_rust::box_trait::StringBox::new(value);
|
|
|
|
|
nyash_rust::runtime::modules_registry::set(key, Box::new(sb));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-17 06:55:39 +09:00
|
|
|
if crate::config::env::cli_verbose() && !quiet_pipe {
|
2025-09-26 14:34:42 +09:00
|
|
|
if crate::config::env::cli_verbose() {
|
|
|
|
|
println!("✅ Parse successful!");
|
|
|
|
|
}
|
2025-09-07 07:36:15 +09:00
|
|
|
}
|
2025-08-26 04:39:16 +09:00
|
|
|
|
|
|
|
|
// Execute the AST
|
2025-08-30 08:54:15 +09:00
|
|
|
let mut interpreter = NyashInterpreter::new();
|
2025-08-26 04:39:16 +09:00
|
|
|
eprintln!("🔍 DEBUG: Starting execution...");
|
|
|
|
|
match interpreter.execute(ast) {
|
|
|
|
|
Ok(result) => {
|
2025-09-17 06:55:39 +09:00
|
|
|
if crate::config::env::cli_verbose() && !quiet_pipe {
|
2025-09-26 14:34:42 +09:00
|
|
|
if crate::config::env::cli_verbose() {
|
|
|
|
|
println!("✅ Execution completed successfully!");
|
|
|
|
|
}
|
2025-09-07 07:36:15 +09:00
|
|
|
}
|
2025-09-02 05:11:10 +09:00
|
|
|
// Normalize display via semantics: prefer numeric, then string, then fallback
|
|
|
|
|
let disp = {
|
|
|
|
|
// Special-case: plugin IntegerBox → call .get to fetch numeric value
|
2025-09-26 14:34:42 +09:00
|
|
|
if let Some(p) = result
|
|
|
|
|
.as_any()
|
|
|
|
|
.downcast_ref::<nyash_rust::runtime::plugin_loader_v2::PluginBoxV2>(
|
|
|
|
|
) {
|
2025-09-02 05:11:10 +09:00
|
|
|
if p.box_type == "IntegerBox" {
|
|
|
|
|
// Scope the lock strictly to this block
|
|
|
|
|
let fetched = {
|
|
|
|
|
let host = nyash_rust::runtime::get_global_plugin_host();
|
|
|
|
|
let res = if let Ok(ro) = host.read() {
|
2025-09-26 14:34:42 +09:00
|
|
|
if let Ok(Some(vb)) = ro.invoke_instance_method(
|
|
|
|
|
"IntegerBox",
|
|
|
|
|
"get",
|
|
|
|
|
p.instance_id(),
|
|
|
|
|
&[],
|
|
|
|
|
) {
|
|
|
|
|
if let Some(ib) =
|
|
|
|
|
vb.as_any()
|
|
|
|
|
.downcast_ref::<nyash_rust::box_trait::IntegerBox>()
|
|
|
|
|
{
|
2025-09-02 05:11:10 +09:00
|
|
|
Some(ib.value.to_string())
|
|
|
|
|
} else {
|
|
|
|
|
Some(vb.to_string_box().value)
|
|
|
|
|
}
|
2025-09-26 14:34:42 +09:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
2025-09-02 05:11:10 +09:00
|
|
|
res
|
|
|
|
|
};
|
2025-09-26 14:34:42 +09:00
|
|
|
if let Some(s) = fetched {
|
|
|
|
|
s
|
|
|
|
|
} else {
|
2025-09-02 05:11:10 +09:00
|
|
|
nyash_rust::runtime::semantics::coerce_to_i64(result.as_ref())
|
|
|
|
|
.map(|i| i.to_string())
|
2025-09-26 14:34:42 +09:00
|
|
|
.or_else(|| {
|
|
|
|
|
nyash_rust::runtime::semantics::coerce_to_string(
|
|
|
|
|
result.as_ref(),
|
|
|
|
|
)
|
|
|
|
|
})
|
2025-09-02 05:11:10 +09:00
|
|
|
.unwrap_or_else(|| result.to_string_box().value)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nyash_rust::runtime::semantics::coerce_to_i64(result.as_ref())
|
|
|
|
|
.map(|i| i.to_string())
|
2025-09-26 14:34:42 +09:00
|
|
|
.or_else(|| {
|
|
|
|
|
nyash_rust::runtime::semantics::coerce_to_string(
|
|
|
|
|
result.as_ref(),
|
|
|
|
|
)
|
|
|
|
|
})
|
2025-09-02 05:11:10 +09:00
|
|
|
.unwrap_or_else(|| result.to_string_box().value)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nyash_rust::runtime::semantics::coerce_to_i64(result.as_ref())
|
|
|
|
|
.map(|i| i.to_string())
|
2025-09-26 14:34:42 +09:00
|
|
|
.or_else(|| {
|
|
|
|
|
nyash_rust::runtime::semantics::coerce_to_string(result.as_ref())
|
|
|
|
|
})
|
2025-09-02 05:11:10 +09:00
|
|
|
.unwrap_or_else(|| result.to_string_box().value)
|
|
|
|
|
}
|
|
|
|
|
};
|
2025-09-26 14:34:42 +09:00
|
|
|
if !quiet_pipe {
|
|
|
|
|
println!("Result: {}", disp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-08-26 04:39:16 +09:00
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("❌ Runtime error:\n{}", e.detailed_message(Some(&code)));
|
|
|
|
|
process::exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-28 12:19:49 +09:00
|
|
|
|
|
|
|
|
#[cfg(not(feature = "interpreter-legacy"))]
|
|
|
|
|
impl NyashRunner {
|
|
|
|
|
/// Interpreter backend is disabled in default builds. Use `--backend vm` or `--backend llvm`.
|
|
|
|
|
pub(crate) fn execute_nyash_file(&self, _filename: &str) {
|
|
|
|
|
eprintln!("❌ Interpreter backend (AST) is disabled. Build with --features interpreter-legacy to enable, or use --backend vm/llvm.");
|
|
|
|
|
std::process::exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|