phase: 20.49 COMPLETE; 20.50 Flow+String minimal reps; 20.51 selfhost v0/v1 minimal (Option A/B); hv1-inline binop/unop/copy; docs + run_all + CURRENT_TASK -> 21.0
This commit is contained in:
@ -15,34 +15,17 @@ pub fn looks_like_hako_code(s: &str) -> bool {
|
||||
|
||||
/// Remove leading `local ` declarations at line head to keep Nyash parser stable
|
||||
pub fn strip_local_decl(s: &str) -> String {
|
||||
let mut out = String::with_capacity(s.len());
|
||||
for line in s.lines() {
|
||||
let leading = line.len() - line.trim_start().len();
|
||||
let (indent, rest) = line.split_at(leading);
|
||||
if rest.starts_with("local ") || rest.starts_with("local\t") {
|
||||
let bytes = rest.as_bytes();
|
||||
let mut i = 5; // after 'local'
|
||||
while i < bytes.len() && (bytes[i] == b' ' || bytes[i] == b'\t') {
|
||||
i += 1;
|
||||
break;
|
||||
}
|
||||
out.push_str(indent);
|
||||
out.push_str(&rest[i..]);
|
||||
out.push('\n');
|
||||
} else {
|
||||
out.push_str(line);
|
||||
out.push('\n');
|
||||
}
|
||||
}
|
||||
out
|
||||
// Stage‑3 パーサでは 'local' を受理できるため、変換は行わず原文を返す
|
||||
s.to_string()
|
||||
}
|
||||
|
||||
/// Policy toggle: fail fast when Hako-like code enters Nyash VM path
|
||||
/// Default: ON (true)
|
||||
pub fn fail_fast_on_hako() -> bool {
|
||||
// Default: OFF(仕様不変=拡張子だけで拒否しない)。
|
||||
// 明示時のみ ON(bring-up やデバッグ用途)。
|
||||
match std::env::var("HAKO_FAIL_FAST_ON_HAKO_IN_NYASH_VM").ok().as_deref() {
|
||||
Some("0") | Some("false") | Some("off") => false,
|
||||
_ => true,
|
||||
Some("1") | Some("true") | Some("on") => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ pub mod seam;
|
||||
pub mod using_resolution;
|
||||
pub mod prelude_manager;
|
||||
pub mod selfhost_pipeline;
|
||||
pub mod path_util;
|
||||
|
||||
// 📦 箱化モジュールの公開にゃ!
|
||||
pub use using_resolution::{
|
||||
|
||||
20
src/runner/modes/common_util/resolve/path_util.rs
Normal file
20
src/runner/modes/common_util/resolve/path_util.rs
Normal file
@ -0,0 +1,20 @@
|
||||
//! path_util — helpers for using target path detection (SSOT)
|
||||
|
||||
/// Determine if an original using target string should be treated as a file path.
|
||||
/// Original means it may still contain surrounding quotes.
|
||||
pub fn is_using_target_path_original(target: &str) -> bool {
|
||||
if target.starts_with('"') {
|
||||
return true;
|
||||
}
|
||||
let t = target.trim_matches('"');
|
||||
is_using_target_path_unquoted(t)
|
||||
}
|
||||
|
||||
/// Determine if an unquoted using target string is a file path.
|
||||
pub fn is_using_target_path_unquoted(target_unquoted: &str) -> bool {
|
||||
target_unquoted.starts_with("./")
|
||||
|| target_unquoted.starts_with('/')
|
||||
|| target_unquoted.ends_with(".hako")
|
||||
|| target_unquoted.ends_with(".nyash")
|
||||
}
|
||||
|
||||
@ -19,9 +19,8 @@ pub fn collect_using_and_strip(
|
||||
}
|
||||
let using_ctx = runner.init_using_context();
|
||||
let prod = crate::config::env::using_is_prod();
|
||||
let strict = std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1");
|
||||
let verbose = crate::config::env::cli_verbose()
|
||||
|| std::env::var("NYASH_RESOLVE_TRACE").ok().as_deref() == Some("1");
|
||||
let strict = crate::config::env::env_bool("NYASH_USING_STRICT");
|
||||
let verbose = crate::config::env::cli_verbose() || crate::config::env::env_bool("NYASH_RESOLVE_TRACE");
|
||||
let ctx_dir = std::path::Path::new(filename).parent();
|
||||
|
||||
let mut out = String::with_capacity(code.len());
|
||||
@ -61,7 +60,7 @@ pub fn collect_using_and_strip(
|
||||
} else {
|
||||
(rest0.to_string(), None)
|
||||
};
|
||||
// Strip quotes from target for alias/module lookup
|
||||
// Strip quotes from target for alias/module lookup and path detection
|
||||
let target_unquoted = target.trim_matches('"').to_string();
|
||||
|
||||
// Check if this is a known alias or module FIRST before treating as file path
|
||||
@ -73,11 +72,8 @@ pub fn collect_using_and_strip(
|
||||
// Known alias/module - don't treat as file path even if quoted
|
||||
false
|
||||
} else {
|
||||
// Only treat as file path if not a known alias/module
|
||||
target.starts_with("./")
|
||||
|| target.starts_with('/')
|
||||
|| target.ends_with(".nyash")
|
||||
|| target.ends_with(".hako")
|
||||
// SSOT: delegate path pattern check
|
||||
crate::runner::modes::common_util::resolve::path_util::is_using_target_path_unquoted(&target_unquoted)
|
||||
};
|
||||
if is_path {
|
||||
// SSOT: Disallow file-using at top-level; allow only for sources located
|
||||
@ -91,7 +87,7 @@ pub fn collect_using_and_strip(
|
||||
target
|
||||
));
|
||||
}
|
||||
let path = target.trim_matches('"').to_string();
|
||||
let path = target_unquoted.clone();
|
||||
// Resolve relative to current file dir
|
||||
let mut p = std::path::PathBuf::from(&path);
|
||||
if p.is_relative() {
|
||||
@ -197,7 +193,7 @@ pub fn collect_using_and_strip(
|
||||
.file_name()
|
||||
.and_then(|s| s.to_str())
|
||||
.unwrap_or(&pkg_name);
|
||||
base.join(format!("{}.nyash", leaf))
|
||||
base.join(format!("{}.hako", leaf))
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
};
|
||||
@ -257,8 +253,8 @@ pub fn collect_using_and_strip(
|
||||
) {
|
||||
Ok(value) => {
|
||||
// Only file paths are candidates for AST prelude merge
|
||||
if value.ends_with(".nyash") || value.contains('/') || value.contains('\\')
|
||||
{
|
||||
if crate::runner::modes::common_util::resolve::path_util::is_using_target_path_unquoted(&value)
|
||||
{
|
||||
// Resolve relative
|
||||
let mut p = std::path::PathBuf::from(&value);
|
||||
if p.is_relative() {
|
||||
@ -338,7 +334,7 @@ pub fn collect_using_and_strip(
|
||||
out.push('\n');
|
||||
}
|
||||
// Optional prelude boundary comment (helps manual inspection; parser ignores comments)
|
||||
if std::env::var("NYASH_RESOLVE_SEAM_DEBUG").ok().as_deref() == Some("1") {
|
||||
if crate::config::env::env_bool("NYASH_RESOLVE_SEAM_DEBUG") {
|
||||
let mut with_marker = String::with_capacity(out.len() + 64);
|
||||
with_marker.push_str("\n/* --- using boundary (AST) --- */\n");
|
||||
with_marker.push_str(&out);
|
||||
@ -364,7 +360,7 @@ pub fn resolve_prelude_paths_profiled(
|
||||
// must be discovered so that their definitions are present at runtime
|
||||
// (e.g., runner_min -> lower_* boxes). Previously this only ran when
|
||||
// NYASH_USING_AST=1, which caused unresolved calls in inline flows.
|
||||
let ast_on = std::env::var("NYASH_USING_AST").ok().as_deref() == Some("1");
|
||||
let ast_on = crate::config::env::env_bool("NYASH_USING_AST");
|
||||
let mut out: Vec<String> = Vec::new();
|
||||
let mut seen: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
fn normalize_path(path: &str) -> (String, String) {
|
||||
@ -404,14 +400,14 @@ pub fn resolve_prelude_paths_profiled(
|
||||
}
|
||||
// Operator Boxes prelude injection(観測“常時ON”のため)
|
||||
// stringify/compare/add は常に注入(存在時)。その他(bitwise等)は ALL 指定時のみ。
|
||||
let opbox_all = std::env::var("NYASH_OPERATOR_BOX_ALL").ok().as_deref() == Some("1")
|
||||
|| std::env::var("NYASH_BUILDER_OPERATOR_BOX_ALL_CALL").ok().as_deref() == Some("1");
|
||||
let opbox_all = crate::config::env::env_bool("NYASH_OPERATOR_BOX_ALL")
|
||||
|| crate::config::env::env_bool("NYASH_BUILDER_OPERATOR_BOX_ALL_CALL");
|
||||
|
||||
if let Ok(root) = std::env::var("NYASH_ROOT") {
|
||||
let must_have = [
|
||||
"apps/lib/std/operators/stringify.nyash",
|
||||
"apps/lib/std/operators/compare.nyash",
|
||||
"apps/lib/std/operators/add.nyash",
|
||||
"apps/lib/std/operators/stringify.hako",
|
||||
"apps/lib/std/operators/compare.hako",
|
||||
"apps/lib/std/operators/add.hako",
|
||||
];
|
||||
for rel in must_have.iter() {
|
||||
let p = std::path::Path::new(&root).join(rel);
|
||||
@ -427,19 +423,19 @@ pub fn resolve_prelude_paths_profiled(
|
||||
if opbox_all {
|
||||
if let Ok(root) = std::env::var("NYASH_ROOT") {
|
||||
let rels = vec![
|
||||
"apps/lib/std/operators/sub.nyash",
|
||||
"apps/lib/std/operators/mul.nyash",
|
||||
"apps/lib/std/operators/div.nyash",
|
||||
"apps/lib/std/operators/mod.nyash",
|
||||
"apps/lib/std/operators/sub.hako",
|
||||
"apps/lib/std/operators/mul.hako",
|
||||
"apps/lib/std/operators/div.hako",
|
||||
"apps/lib/std/operators/mod.hako",
|
||||
// Shifts / bitwise (parser tokens now supported)
|
||||
"apps/lib/std/operators/shl.nyash",
|
||||
"apps/lib/std/operators/shr.nyash",
|
||||
"apps/lib/std/operators/bitand.nyash",
|
||||
"apps/lib/std/operators/bitor.nyash",
|
||||
"apps/lib/std/operators/bitxor.nyash",
|
||||
"apps/lib/std/operators/neg.nyash",
|
||||
"apps/lib/std/operators/not.nyash",
|
||||
"apps/lib/std/operators/bitnot.nyash",
|
||||
"apps/lib/std/operators/shl.hako",
|
||||
"apps/lib/std/operators/shr.hako",
|
||||
"apps/lib/std/operators/bitand.hako",
|
||||
"apps/lib/std/operators/bitor.hako",
|
||||
"apps/lib/std/operators/bitxor.hako",
|
||||
"apps/lib/std/operators/neg.hako",
|
||||
"apps/lib/std/operators/not.hako",
|
||||
"apps/lib/std/operators/bitnot.hako",
|
||||
];
|
||||
for rel in rels {
|
||||
let p = std::path::Path::new(&root).join(rel);
|
||||
@ -465,7 +461,7 @@ pub fn parse_preludes_to_asts(
|
||||
runner: &NyashRunner,
|
||||
prelude_paths: &[String],
|
||||
) -> Result<Vec<nyash_rust::ast::ASTNode>, String> {
|
||||
let debug = std::env::var("NYASH_STRIP_DEBUG").ok().as_deref() == Some("1");
|
||||
let debug = crate::config::env::env_bool("NYASH_STRIP_DEBUG");
|
||||
if debug {
|
||||
eprintln!("[strip-debug] parse_preludes_to_asts: {} files total", prelude_paths.len());
|
||||
for (idx, p) in prelude_paths.iter().enumerate() {
|
||||
@ -506,7 +502,7 @@ pub fn parse_preludes_to_asts(
|
||||
}
|
||||
Err(e) => {
|
||||
// Always output debug info on parse failure if NYASH_STRIP_DEBUG=1
|
||||
let debug = std::env::var("NYASH_STRIP_DEBUG").ok().as_deref() == Some("1");
|
||||
let debug = crate::config::env::env_bool("NYASH_STRIP_DEBUG");
|
||||
eprintln!("[strip-debug] Parse FAILED for: {} (debug={})", prelude_path, debug);
|
||||
if debug {
|
||||
eprintln!("[strip-debug] Error: {}", e);
|
||||
@ -659,7 +655,7 @@ pub fn merge_prelude_text(
|
||||
source: &str,
|
||||
filename: &str,
|
||||
) -> Result<String, String> {
|
||||
let trace = std::env::var("NYASH_RESOLVE_TRACE").ok().as_deref() == Some("1");
|
||||
let trace = crate::config::env::env_bool("NYASH_RESOLVE_TRACE");
|
||||
|
||||
// First pass: collect and resolve prelude paths
|
||||
let (cleaned_main, prelude_paths) = resolve_prelude_paths_profiled(runner, source, filename)?;
|
||||
@ -737,7 +733,7 @@ pub fn merge_prelude_text(
|
||||
}
|
||||
|
||||
// Add boundary marker if debug mode
|
||||
if std::env::var("NYASH_RESOLVE_SEAM_DEBUG").ok().as_deref() == Some("1") {
|
||||
if crate::config::env::env_bool("NYASH_RESOLVE_SEAM_DEBUG") {
|
||||
merged.push_str("\n/* --- using prelude/main boundary --- */\n\n");
|
||||
}
|
||||
|
||||
|
||||
@ -46,9 +46,9 @@ impl<'a> UsingResolutionBox<'a> {
|
||||
let using_ctx = runner.init_using_context();
|
||||
let config = UsingConfig {
|
||||
prod: crate::config::env::using_is_prod(),
|
||||
strict: std::env::var("NYASH_USING_STRICT").ok().as_deref() == Some("1"),
|
||||
strict: crate::config::env::env_bool("NYASH_USING_STRICT"),
|
||||
verbose: crate::config::env::cli_verbose()
|
||||
|| std::env::var("NYASH_RESOLVE_TRACE").ok().as_deref() == Some("1"),
|
||||
|| crate::config::env::env_bool("NYASH_RESOLVE_TRACE"),
|
||||
allow_file_using: crate::config::env::allow_using_file(),
|
||||
};
|
||||
|
||||
@ -113,10 +113,7 @@ impl<'a> UsingResolutionBox<'a> {
|
||||
let is_path = if is_known_alias_or_module {
|
||||
false
|
||||
} else {
|
||||
target.starts_with("./")
|
||||
|| target.starts_with('/')
|
||||
|| target.ends_with(".nyash")
|
||||
|| target.ends_with(".hako")
|
||||
crate::runner::modes::common_util::resolve::path_util::is_using_target_path_unquoted(&target_unquoted)
|
||||
};
|
||||
|
||||
Some(UsingTarget {
|
||||
|
||||
@ -2,7 +2,7 @@ use std::path::Path;
|
||||
|
||||
/// Run a Nyash program as a child (`nyash --backend vm <program>`) and capture the first JSON v0 line.
|
||||
/// - `exe`: path to nyash executable
|
||||
/// - `program`: path to the Nyash script to run (e.g., apps/selfhost/compiler/compiler.nyash)
|
||||
/// - `program`: path to the Nyash script to run (e.g., apps/selfhost/compiler/compiler.hako)
|
||||
/// - `timeout_ms`: kill child after this duration
|
||||
/// - `extra_args`: additional args to pass after program (e.g., "--", "--read-tmp")
|
||||
/// - `env_remove`: environment variable names to remove for the child
|
||||
|
||||
@ -36,7 +36,7 @@ pub fn run_pyvm_module(module: &MirModule, label: &str) -> Option<i32> {
|
||||
eprintln!("❌ PyVM MIR JSON emit error: {}", e);
|
||||
return None;
|
||||
}
|
||||
if std::env::var("NYASH_CLI_VERBOSE").ok().as_deref() == Some("1") {
|
||||
if crate::config::env::cli_verbose() {
|
||||
eprintln!("[Bridge] using PyVM ({}) → {}", label, mir_json_path.display());
|
||||
}
|
||||
// Select entry (prefer Main.main; top-level main only if allowed)
|
||||
|
||||
Reference in New Issue
Block a user