mir: implement proper short-circuit lowering (&&/||) via branch+phi; vm: add NYASH_VM_TRACE exec/phi logs and reg_load diagnostics; vm-fallback: minimal Void guards (push/get_position/line/column), MapBox.birth no-op; smokes: filter builtin Array/Map plugin notices; docs: CURRENT_TASK updated
This commit is contained in:
@ -1,5 +1,13 @@
|
||||
use super::super::NyashRunner;
|
||||
use crate::{parser::NyashParser, mir::MirCompiler, backend::MirInterpreter};
|
||||
use crate::{
|
||||
backend::MirInterpreter,
|
||||
box_factory::{BoxFactory, RuntimeError},
|
||||
core::model::BoxDeclaration as CoreBoxDecl,
|
||||
instance_v2::InstanceBox,
|
||||
mir::MirCompiler,
|
||||
parser::NyashParser,
|
||||
};
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{fs, process};
|
||||
|
||||
impl NyashRunner {
|
||||
@ -25,11 +33,74 @@ impl NyashRunner {
|
||||
eprintln!("❌ using: AST prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines.");
|
||||
process::exit(1);
|
||||
}
|
||||
for p in paths {
|
||||
// Normalize initial prelude paths relative to filename or $NYASH_ROOT,
|
||||
// then recursively process prelude files: strip their using-lines and parse cleaned ASTs
|
||||
let mut visited = std::collections::HashSet::<String>::new();
|
||||
let mut stack: Vec<String> = Vec::new();
|
||||
for raw in paths {
|
||||
let mut pb = std::path::PathBuf::from(&raw);
|
||||
if pb.is_relative() {
|
||||
if let Some(dir) = std::path::Path::new(filename).parent() {
|
||||
let cand = dir.join(&pb);
|
||||
if cand.exists() { pb = cand; }
|
||||
}
|
||||
if pb.is_relative() {
|
||||
if let Ok(root) = std::env::var("NYASH_ROOT") {
|
||||
let cand = std::path::Path::new(&root).join(&pb);
|
||||
if cand.exists() { pb = cand; }
|
||||
} else {
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(root) = exe.parent().and_then(|p| p.parent()).and_then(|p| p.parent()) {
|
||||
let cand = root.join(&pb);
|
||||
if cand.exists() { pb = cand; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stack.push(pb.to_string_lossy().to_string());
|
||||
}
|
||||
while let Some(mut p) = stack.pop() {
|
||||
if std::path::Path::new(&p).is_relative() {
|
||||
if let Ok(root) = std::env::var("NYASH_ROOT") {
|
||||
let cand = std::path::Path::new(&root).join(&p);
|
||||
p = cand.to_string_lossy().to_string();
|
||||
}
|
||||
}
|
||||
if !visited.insert(p.clone()) { continue; }
|
||||
match std::fs::read_to_string(&p) {
|
||||
Ok(src) => match NyashParser::parse_from_string(&src) {
|
||||
Ok(ast) => prelude_asts.push(ast),
|
||||
Err(e) => { eprintln!("❌ Parse error in using prelude {}: {}", p, e); process::exit(1); }
|
||||
Ok(src) => match crate::runner::modes::common_util::resolve::collect_using_and_strip(self, &src, &p) {
|
||||
Ok((clean_src, nested)) => {
|
||||
for np in nested {
|
||||
let mut npp = std::path::PathBuf::from(&np);
|
||||
if npp.is_relative() {
|
||||
if let Some(dir) = std::path::Path::new(&p).parent() {
|
||||
let cand = dir.join(&npp);
|
||||
if cand.exists() { npp = cand; }
|
||||
}
|
||||
if npp.is_relative() {
|
||||
if let Ok(root) = std::env::var("NYASH_ROOT") {
|
||||
let cand = std::path::Path::new(&root).join(&npp);
|
||||
if cand.exists() { npp = cand; }
|
||||
} else {
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(root) = exe.parent().and_then(|p| p.parent()).and_then(|p| p.parent()) {
|
||||
let cand = root.join(&npp);
|
||||
if cand.exists() { npp = cand; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let nps = npp.to_string_lossy().to_string();
|
||||
if !visited.contains(&nps) { stack.push(nps); }
|
||||
}
|
||||
match NyashParser::parse_from_string(&clean_src) {
|
||||
Ok(ast) => prelude_asts.push(ast),
|
||||
Err(e) => { eprintln!("❌ Parse error in using prelude {}: {}", p, e); process::exit(1); }
|
||||
}
|
||||
}
|
||||
Err(e) => { eprintln!("❌ {}", e); process::exit(1); }
|
||||
},
|
||||
Err(e) => { eprintln!("❌ Error reading using prelude {}: {}", p, e); process::exit(1); }
|
||||
}
|
||||
@ -82,6 +153,101 @@ impl NyashRunner {
|
||||
eprintln!("[ast] dump end");
|
||||
}
|
||||
let ast = crate::r#macro::maybe_expand_and_dump(&ast_combined, false);
|
||||
|
||||
// Minimal user-defined Box support (Option A):
|
||||
// Collect BoxDeclaration entries from AST and register a lightweight
|
||||
// factory into the unified registry so `new UserBox()` works on the
|
||||
// VM fallback path as well.
|
||||
{
|
||||
use nyash_rust::ast::ASTNode;
|
||||
|
||||
// Collect user-defined (non-static) box declarations at program level.
|
||||
let mut decls: std::collections::HashMap<String, CoreBoxDecl> =
|
||||
std::collections::HashMap::new();
|
||||
if let ASTNode::Program { statements, .. } = &ast {
|
||||
for st in statements {
|
||||
if let ASTNode::BoxDeclaration {
|
||||
name,
|
||||
fields,
|
||||
public_fields,
|
||||
private_fields,
|
||||
methods,
|
||||
constructors,
|
||||
init_fields,
|
||||
weak_fields,
|
||||
is_interface,
|
||||
extends,
|
||||
implements,
|
||||
type_parameters,
|
||||
is_static,
|
||||
..
|
||||
} = st
|
||||
{
|
||||
if *is_static {
|
||||
continue; // modules/static boxes are not user-instantiable
|
||||
}
|
||||
let decl = CoreBoxDecl {
|
||||
name: name.clone(),
|
||||
fields: fields.clone(),
|
||||
public_fields: public_fields.clone(),
|
||||
private_fields: private_fields.clone(),
|
||||
methods: methods.clone(),
|
||||
constructors: constructors.clone(),
|
||||
init_fields: init_fields.clone(),
|
||||
weak_fields: weak_fields.clone(),
|
||||
is_interface: *is_interface,
|
||||
extends: extends.clone(),
|
||||
implements: implements.clone(),
|
||||
type_parameters: type_parameters.clone(),
|
||||
};
|
||||
decls.insert(name.clone(), decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !decls.is_empty() {
|
||||
// Inline factory: minimal User factory backed by collected declarations
|
||||
struct InlineUserBoxFactory {
|
||||
decls: Arc<RwLock<std::collections::HashMap<String, CoreBoxDecl>>>,
|
||||
}
|
||||
impl BoxFactory for InlineUserBoxFactory {
|
||||
fn create_box(
|
||||
&self,
|
||||
name: &str,
|
||||
args: &[Box<dyn crate::box_trait::NyashBox>],
|
||||
) -> Result<Box<dyn crate::box_trait::NyashBox>, RuntimeError> {
|
||||
let opt = { self.decls.read().unwrap().get(name).cloned() };
|
||||
let decl = match opt {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
return Err(RuntimeError::InvalidOperation {
|
||||
message: format!("Unknown Box type: {}", name),
|
||||
})
|
||||
}
|
||||
};
|
||||
let mut inst = InstanceBox::from_declaration(
|
||||
decl.name.clone(),
|
||||
decl.fields.clone(),
|
||||
decl.methods.clone(),
|
||||
);
|
||||
let _ = inst.init(args);
|
||||
Ok(Box::new(inst))
|
||||
}
|
||||
|
||||
fn box_types(&self) -> Vec<&str> { vec![] }
|
||||
|
||||
fn is_available(&self) -> bool { true }
|
||||
|
||||
fn factory_type(
|
||||
&self,
|
||||
) -> crate::box_factory::FactoryType {
|
||||
crate::box_factory::FactoryType::User
|
||||
}
|
||||
}
|
||||
let factory = InlineUserBoxFactory { decls: Arc::new(RwLock::new(decls)) };
|
||||
crate::runtime::unified_registry::register_user_defined_factory(Arc::new(factory));
|
||||
}
|
||||
}
|
||||
let mut compiler = MirCompiler::with_options(!self.config.no_optimize);
|
||||
let compile = match compiler.compile(ast) {
|
||||
Ok(c) => c,
|
||||
|
||||
Reference in New Issue
Block a user