Phase 21.3 WIP: Hako Source Checker improvements
## 🎯 Checker/Analyzer拡張 ### ✅ 実装追加 - テストフレームワーク追加(tools/hako_check/tests/) - ルール改善(HC003グローバルassign、HC040静的箱トップレベルassign) - テストランナー(run_tests.sh) ### 🔧 Rust側修正 - AST utilities拡張(src/ast/utils.rs) - MIR lowerers新設(src/mir/lowerers/) - Parser制御フロー改善(src/parser/statements/control_flow.rs) - Tokenizer識別子処理改善(src/tokenizer/lex_ident.rs) ### 📁 主要変更 - tools/hako_check/cli.hako - CLI改善 - tools/hako_check/hako_source_checker.hako - Checker core更新 - tools/hako_check/tests/ - NEW (テストケース追加) - tools/hako_check/run_tests.sh - NEW (テストランナー) - src/mir/lowerers/ - NEW (MIR lowering utilities) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -26,71 +26,47 @@ impl NyashRunner {
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
// Using preprocessing: AST prelude merge(.hako/Hakoライクは強制AST)
|
||||
let mut code2 = code.clone();
|
||||
if crate::config::env::enable_using() {
|
||||
let mut use_ast = crate::config::env::using_ast_enabled();
|
||||
let is_hako = filename.ends_with(".hako")
|
||||
|| crate::runner::modes::common_util::hako::looks_like_hako_code(&code2);
|
||||
if is_hako { use_ast = true; }
|
||||
if use_ast {
|
||||
match crate::runner::modes::common_util::resolve::resolve_prelude_paths_profiled(self, &code2, filename) {
|
||||
Ok((clean, paths)) => {
|
||||
// If any prelude is .hako, prefer text-merge (Hakorune surface is not Nyash AST)
|
||||
let has_hako = paths.iter().any(|p| p.ends_with(".hako"));
|
||||
if has_hako {
|
||||
match crate::runner::modes::common_util::resolve::merge_prelude_text(self, &code2, filename) {
|
||||
Ok(merged) => {
|
||||
if std::env::var("NYASH_RESOLVE_TRACE").ok().as_deref() == Some("1") {
|
||||
eprintln!("[using/text-merge] preludes={} (vm-fallback)", paths.len());
|
||||
}
|
||||
code2 = merged;
|
||||
|
||||
let trace = crate::config::env::cli_verbose()
|
||||
|| crate::config::env::env_bool("NYASH_RESOLVE_TRACE");
|
||||
|
||||
// Unified using/prelude handling (SSOT, parity with vm.rs):
|
||||
// - resolve_prelude_paths_profiled で preludes を発見
|
||||
// - merge_prelude_text で text-merge(.hako は AST parse しない)
|
||||
let mut code2 = if crate::config::env::enable_using() {
|
||||
match crate::runner::modes::common_util::resolve::resolve_prelude_paths_profiled(
|
||||
self,
|
||||
&code,
|
||||
filename,
|
||||
) {
|
||||
Ok((_, prelude_paths)) => {
|
||||
if !prelude_paths.is_empty() {
|
||||
match crate::runner::modes::common_util::resolve::merge_prelude_text(
|
||||
self,
|
||||
&code,
|
||||
filename,
|
||||
) {
|
||||
Ok(merged) => {
|
||||
if trace {
|
||||
eprintln!(
|
||||
"[using/text-merge] preludes={} (vm-fallback)",
|
||||
prelude_paths.len()
|
||||
);
|
||||
}
|
||||
Err(e) => { eprintln!("❌ {}", e); process::exit(1); }
|
||||
merged
|
||||
}
|
||||
// Fall through to normal parse of merged text below
|
||||
} else {
|
||||
// AST prelude merge path
|
||||
code2 = clean;
|
||||
let preexpanded = crate::runner::modes::common_util::resolve::preexpand_at_local(&code2);
|
||||
code2 = preexpanded;
|
||||
if crate::runner::modes::common_util::hako::looks_like_hako_code(&code2) {
|
||||
code2 = crate::runner::modes::common_util::hako::strip_local_decl(&code2);
|
||||
}
|
||||
let main_ast = match NyashParser::parse_from_string(&code2) {
|
||||
Ok(ast) => ast,
|
||||
Err(e) => { eprintln!("❌ Parse error in {}: {}", filename, e); process::exit(1); }
|
||||
};
|
||||
if !paths.is_empty() {
|
||||
match crate::runner::modes::common_util::resolve::parse_preludes_to_asts(self, &paths) {
|
||||
Ok(v) => {
|
||||
if std::env::var("NYASH_RESOLVE_TRACE").ok().as_deref() == Some("1") {
|
||||
eprintln!("[using/ast-merge] preludes={} (vm-fallback)", v.len());
|
||||
}
|
||||
let ast = crate::runner::modes::common_util::resolve::merge_prelude_asts_with_main(v, &main_ast);
|
||||
self.execute_vm_fallback_from_ast(filename, ast);
|
||||
return; // done
|
||||
}
|
||||
Err(e) => { eprintln!("❌ {}", e); process::exit(1); }
|
||||
}
|
||||
} else {
|
||||
self.execute_vm_fallback_from_ast(filename, main_ast);
|
||||
return;
|
||||
Err(e) => {
|
||||
eprintln!("❌ {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
code.clone()
|
||||
}
|
||||
Err(e) => { eprintln!("❌ {}", e); process::exit(1); }
|
||||
}
|
||||
} else {
|
||||
// Fallback: text-prelude merge(言語非依存)
|
||||
match crate::runner::modes::common_util::resolve::merge_prelude_text(self, &code2, filename) {
|
||||
Ok(merged) => {
|
||||
if std::env::var("NYASH_RESOLVE_TRACE").ok().as_deref() == Some("1") {
|
||||
eprintln!("[using/text-merge] applied (vm-fallback): {} bytes", merged.len());
|
||||
}
|
||||
code2 = merged;
|
||||
}
|
||||
Err(e) => { eprintln!("❌ using text merge error: {}", e); process::exit(1); }
|
||||
Err(e) => {
|
||||
eprintln!("❌ {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -101,14 +77,25 @@ impl NyashRunner {
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
code
|
||||
};
|
||||
|
||||
// Dev sugar pre-expand: @name = expr → local name = expr
|
||||
code2 = crate::runner::modes::common_util::resolve::preexpand_at_local(&code2);
|
||||
// Hako-friendly normalize: strip leading `local ` at line head for Nyash parser compatibility.
|
||||
if crate::runner::modes::common_util::hako::looks_like_hako_code(&code2) {
|
||||
|
||||
// Hako-friendly normalize
|
||||
if crate::runner::modes::common_util::hako::looks_like_hako_code(&code2)
|
||||
|| filename.ends_with(".hako")
|
||||
{
|
||||
code2 = crate::runner::modes::common_util::hako::strip_local_decl(&code2);
|
||||
}
|
||||
|
||||
if trace && (std::env::var("NYASH_PARSER_STAGE3").ok() == Some("1".into())
|
||||
|| std::env::var("HAKO_PARSER_STAGE3").ok() == Some("1".into()))
|
||||
{
|
||||
eprintln!("[vm-fallback] Stage-3: enabled (env) for {}", filename);
|
||||
}
|
||||
|
||||
// Fail‑Fast (opt‑in): Hako 構文を Nyash VM 経路で実行しない
|
||||
// 目的: .hako は Hakorune VM、MIR は Core/LLVM に役割分離するためのガード
|
||||
{
|
||||
@ -436,7 +423,6 @@ impl NyashRunner {
|
||||
let mut interp = MirInterpreter::new();
|
||||
match interp.execute_module(&module) {
|
||||
Ok(result) => {
|
||||
// Normalize display (avoid nonexistent coerce_to_exit_code here)
|
||||
use nyash_rust::box_trait::{BoolBox, IntegerBox};
|
||||
let rc = if let Some(ib) = result.as_any().downcast_ref::<IntegerBox>() {
|
||||
ib.value as i32
|
||||
@ -448,13 +434,15 @@ impl NyashRunner {
|
||||
// For C‑API pure pipeline, suppress "RC:" text to keep last line = exe path
|
||||
let capi = std::env::var("NYASH_LLVM_USE_CAPI").ok().as_deref() == Some("1");
|
||||
let pure = std::env::var("HAKO_CAPI_PURE").ok().as_deref() == Some("1");
|
||||
if capi && pure {
|
||||
process::exit(rc);
|
||||
} else {
|
||||
if !(capi && pure) {
|
||||
println!("RC: {}", rc);
|
||||
}
|
||||
process::exit(rc);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("❌ VM fallback runtime error: {}", e);
|
||||
process::exit(1);
|
||||
}
|
||||
Err(e) => { eprintln!("❌ VM fallback runtime error: {}", e); process::exit(1); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user