vm/router: minimal special-method extension (equals/1); toString mapping kept

mir: add TypeCertainty to Callee::Method (diagnostic only); plumb through builder/JSON/printer; backends ignore behaviorally

using: confirm unified prelude resolver entry for all runner modes

docs: update Callee architecture with certainty; update call-instructions; CURRENT_TASK note

tests: quick 40/40 PASS; integration (LLVM) 17/17 PASS
This commit is contained in:
nyash-codex
2025-09-28 01:33:58 +09:00
parent 8ea95c9d76
commit 34be7d2d79
63 changed files with 5008 additions and 356 deletions

View File

@ -76,32 +76,10 @@ impl NyashRunner {
eprintln!("❌ using: AST prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines.");
std::process::exit(1);
}
if use_ast {
for prelude_path in paths {
match std::fs::read_to_string(&prelude_path) {
Ok(src) => {
match crate::runner::modes::common_util::resolve::collect_using_and_strip(self, &src, &prelude_path) {
Ok((clean_src, nested)) => {
// Nested entries have already been expanded by DFS; ignore `nested` here.
match NyashParser::parse_from_string(&clean_src) {
Ok(ast) => prelude_asts.push(ast),
Err(e) => {
eprintln!("❌ Parse error in using prelude {}: {}", prelude_path, e);
std::process::exit(1);
}
}
}
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
}
}
Err(e) => {
eprintln!("❌ Error reading using prelude {}: {}", prelude_path, e);
std::process::exit(1);
}
}
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); }
}
}
}
@ -138,23 +116,8 @@ impl NyashRunner {
};
// When using AST prelude mode, combine prelude ASTs + main AST into one Program
let ast = if use_ast && !prelude_asts.is_empty() {
use nyash_rust::ast::ASTNode;
let mut combined: Vec<ASTNode> = Vec::new();
for a in prelude_asts {
if let ASTNode::Program { statements, .. } = a {
combined.extend(statements);
}
}
if let ASTNode::Program { statements, .. } = main_ast.clone() {
combined.extend(statements);
}
ASTNode::Program {
statements: combined,
span: nyash_rust::ast::Span::unknown(),
}
} else {
main_ast
};
crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main(prelude_asts, &main_ast)
} else { main_ast };
// Optional: dump AST statement kinds for quick diagnostics
if std::env::var("NYASH_AST_DUMP").ok().as_deref() == Some("1") {

View File

@ -1,11 +1,29 @@
/*!
* Using resolver utilities (split)
* - strip: remove `using` lines, inline modules, register aliases/modules
* - seam: seam logging and optional brace-fix at join points
* Using resolver utilities — static resolution line (SSOT + AST)
*
* Separation of concerns:
* - Static (using-time): Resolve packages/aliases from nyash.toml (SSOT),
* strip `using` lines, collect prelude file paths, and (when enabled)
* parse/merge them as AST before macro expansion.
* - Dynamic (runtime): Plugin/extern dispatch only. User instance BoxCall
* fallback is disallowed in prod; builder must rewrite obj.method() to
* a function call.
*
* Modules:
* - strip: profile-aware resolution (`collect_using_and_strip`,
* `resolve_prelude_paths_profiled`) — single entrypoints used by all
* runner modes to avoid drift.
* - seam: seam logging and optional boundary markers (for diagnostics).
*/
pub mod strip;
pub mod seam;
// Public re-exports to preserve existing call sites
pub use strip::{preexpand_at_local, collect_using_and_strip, resolve_prelude_paths_profiled};
pub use strip::{
preexpand_at_local,
collect_using_and_strip,
resolve_prelude_paths_profiled,
parse_preludes_to_asts,
merge_prelude_asts_with_main,
};

View File

@ -1,8 +1,14 @@
use crate::runner::NyashRunner;
/// Collect using targets and strip using lines, without inlining.
/// Returns (cleaned_source, prelude_paths) where prelude_paths are resolved file paths
/// to be parsed separately and AST-merged (when NYASH_USING_AST=1).
/// Collect using targets and strip using lines (no inlining).
/// Returns (cleaned_source, prelude_paths) where `prelude_paths` are resolved
/// file paths to be parsed separately and AST-merged (when `NYASH_USING_AST=1`).
///
/// Notes
/// - This function enforces profile policies (prod: disallow file-using; only
/// packages/aliases from nyash.toml are accepted).
/// - SSOT: Resolution sources and aliases come exclusively from nyash.toml.
/// - All runner modes use this static path to avoid logic drift.
pub fn collect_using_and_strip(
runner: &NyashRunner,
code: &str,
@ -322,9 +328,11 @@ pub fn collect_using_and_strip(
Ok((out, prelude_paths))
}
/// Profile-aware prelude resolution wrapper.
/// Currently delegates to `collect_using_and_strip`, but provides a single
/// entry point for callers (common and vm_fallback) to avoid logic drift.
/// Profile-aware prelude resolution wrapper (single entrypoint).
/// - Delegates to `collect_using_and_strip` for the first pass.
/// - When AST using is enabled, resolves nested preludes via DFS and injects
/// OperatorBox preludes when available (stringify/compare/add).
/// - All runners call this helper; do not fork resolution logic elsewhere.
pub fn resolve_prelude_paths_profiled(
runner: &NyashRunner,
code: &str,
@ -427,6 +435,54 @@ pub fn resolve_prelude_paths_profiled(
Ok((cleaned, out))
}
/// Parse prelude source files into ASTs (single helper for all runner modes).
/// - Reads each path, strips nested `using`, and parses to AST.
/// - Returns a Vec of Program ASTs (one per prelude file), preserving DFS order.
pub fn parse_preludes_to_asts(
runner: &NyashRunner,
prelude_paths: &[String],
) -> Result<Vec<nyash_rust::ast::ASTNode>, String> {
let mut out: Vec<nyash_rust::ast::ASTNode> = Vec::with_capacity(prelude_paths.len());
for prelude_path in prelude_paths {
let src = std::fs::read_to_string(prelude_path)
.map_err(|e| format!("using: error reading {}: {}", prelude_path, e))?;
let (clean_src, _nested) = collect_using_and_strip(runner, &src, prelude_path)?;
match crate::parser::NyashParser::parse_from_string(&clean_src) {
Ok(ast) => out.push(ast),
Err(e) => return Err(format!(
"Parse error in using prelude {}: {}",
prelude_path, e
)),
}
}
Ok(out)
}
/// Merge prelude ASTs with the main AST into a single Program node.
/// - Collects statements from each prelude Program in order, then appends
/// statements from the main Program.
/// - If the main AST is not a Program, returns it unchanged (defensive).
pub fn merge_prelude_asts_with_main(
prelude_asts: Vec<nyash_rust::ast::ASTNode>,
main_ast: &nyash_rust::ast::ASTNode,
) -> nyash_rust::ast::ASTNode {
use nyash_rust::ast::{ASTNode, Span};
let mut combined: Vec<ASTNode> = Vec::new();
for a in prelude_asts.into_iter() {
if let ASTNode::Program { statements, .. } = a {
combined.extend(statements);
}
}
if let ASTNode::Program { statements, .. } = main_ast.clone() {
let mut all = combined;
all.extend(statements);
ASTNode::Program { statements: all, span: Span::unknown() }
} else {
// Defensive: unexpected shape; preserve main AST unchanged.
main_ast.clone()
}
}
/// Pre-expand line-head `@name[: Type] = expr` into `local name[: Type] = expr`.
/// Minimal, safe, no semantics change. Applies only at line head (after spaces/tabs).
pub fn preexpand_at_local(src: &str) -> String {

View File

@ -37,31 +37,10 @@ impl NyashRunner {
eprintln!("❌ using: AST prelude merge is disabled in this profile. Enable NYASH_USING_AST=1 or remove 'using' lines.");
std::process::exit(1);
}
if use_ast {
for prelude_path in paths {
match std::fs::read_to_string(&prelude_path) {
Ok(src) => {
match crate::runner::modes::common_util::resolve::collect_using_and_strip(self, &src, &prelude_path) {
Ok((clean_src, _nested)) => {
match NyashParser::parse_from_string(&clean_src) {
Ok(ast) => prelude_asts.push(ast),
Err(e) => {
eprintln!("❌ Parse error in using prelude {}: {}", prelude_path, e);
std::process::exit(1);
}
}
}
Err(e) => {
eprintln!("{}", e);
std::process::exit(1);
}
}
}
Err(e) => {
eprintln!("❌ Error reading using prelude {}: {}", prelude_path, e);
std::process::exit(1);
}
}
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); }
}
}
}
@ -85,20 +64,8 @@ impl NyashRunner {
};
// Merge preludes + main when enabled
let ast = if use_ast && !prelude_asts.is_empty() {
use nyash_rust::ast::ASTNode;
let mut combined: Vec<ASTNode> = Vec::new();
for a in prelude_asts {
if let ASTNode::Program { statements, .. } = a {
combined.extend(statements);
}
}
if let ASTNode::Program { statements, .. } = main_ast.clone() {
combined.extend(statements);
}
ASTNode::Program { statements: combined, span: nyash_rust::ast::Span::unknown() }
} else {
main_ast
};
crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main(prelude_asts, &main_ast)
} else { main_ast };
// Macro expansion (env-gated) after merge
let ast = crate::r#macro::maybe_expand_and_dump(&ast, false);
let ast = crate::runner::modes::macro_child::normalize_core_pass(&ast);

View File

@ -38,30 +38,10 @@ 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 prelude_path in paths {
match std::fs::read_to_string(&prelude_path) {
Ok(src) => {
match crate::runner::modes::common_util::resolve::collect_using_and_strip(self, &src, &prelude_path) {
Ok((clean_src, nested)) => {
// Nested entries have already been expanded by DFS; ignore `nested` here.
match NyashParser::parse_from_string(&clean_src) {
Ok(ast) => prelude_asts.push(ast),
Err(e) => {
eprintln!("❌ Parse error in using prelude {}: {}", prelude_path, e);
process::exit(1);
}
}
}
Err(e) => {
eprintln!("{}", e);
process::exit(1);
}
}
}
Err(e) => {
eprintln!("❌ Error reading using prelude {}: {}", prelude_path, e);
process::exit(1);
}
if use_ast_prelude && !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); process::exit(1); }
}
}
}
@ -84,23 +64,8 @@ impl NyashRunner {
};
// When using AST prelude mode, combine prelude ASTs + main AST into one Program before macro expansion
let ast_combined = if use_ast_prelude && !prelude_asts.is_empty() {
use nyash_rust::ast::ASTNode;
let mut combined: Vec<ASTNode> = Vec::new();
for a in prelude_asts {
if let ASTNode::Program { statements, .. } = a {
combined.extend(statements);
}
}
if let ASTNode::Program { statements, .. } = main_ast.clone() {
combined.extend(statements);
}
ASTNode::Program {
statements: combined,
span: nyash_rust::ast::Span::unknown(),
}
} else {
main_ast
};
crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main(prelude_asts, &main_ast)
} else { main_ast };
// 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;