Phase 22.1 WIP: SSOT resolver + TLV infrastructure + Hako MIR builder setup

Setup infrastructure for Phase 22.1 (TLV C shim & Resolver SSOT):

Core changes:
- Add nyash_tlv, nyash_c_core, nyash_kernel_min_c crates (opt-in)
- Implement SSOT resolver bridge (src/using/ssot_bridge.rs)
- Add HAKO_USING_SSOT=1 / HAKO_USING_SSOT_HAKO=1 env support
- Add HAKO_TLV_SHIM=1 infrastructure (requires --features tlv-shim)

MIR builder improvements:
- Fix using/alias consistency in Hako MIR builder
- Add hako.mir.builder.internal.{prog_scan,pattern_util} to nyash.toml
- Normalize LLVM extern calls: nyash.console.* → nyash_console_*

Smoke tests:
- Add phase2211 tests (using_ssot_hako_parity_canary_vm.sh)
- Add phase2220, phase2230, phase2231 test structure
- Add phase2100 S3 backend selector tests
- Improve test_runner.sh with quiet/timeout controls

Documentation:
- Add docs/ENV_VARS.md (Phase 22.1 env vars reference)
- Add docs/development/runtime/C_CORE_ABI.md
- Update de-rust-roadmap.md with Phase 22.x details

Tools:
- Add tools/hakorune_emit_mir.sh (Hako-first MIR emission wrapper)
- Add tools/tlv_roundtrip_smoke.sh placeholder
- Improve ny_mir_builder.sh with better backend selection

Known issues (to be fixed):
- Parser infinite loop in static method parameter parsing
- Stage-B output contamination with "RC: 0" (needs NYASH_JSON_ONLY=1)
- phase2211/using_ssot_hako_parity_canary_vm.sh fork bomb (needs recursion guard)

Next steps: Fix parser infinite loop + Stage-B quiet mode for green tests
This commit is contained in:
nyash-codex
2025-11-09 15:11:18 +09:00
parent 5d2cd5bad0
commit 981ddd890c
62 changed files with 1981 additions and 103 deletions

View File

@ -0,0 +1,39 @@
"""
extern_normalize.py — Single point of truth for extern name normalization.
Policy (MVP):
- Map bare "print"/"println""nyash.console.log"
- Map "env.console.*" (println/log/print/warn/error) → "nyash.console.<method>"
* println is normalized to log (pointer API).
- Keep already-qualified "nyash.console.*" as-is, but normalize ...println → ...log
This module is imported by both instructions.externcall and instructions.mir_call
to avoid duplication and drift.
"""
from typing import Optional
def normalize_extern_name(name: Optional[str]) -> str:
if not name:
return ""
try:
n = str(name)
except Exception:
return ""
try:
if n.startswith("env.console."):
method = n.split(".")[-1]
if method == "println":
method = "log"
return f"nyash.console.{method}"
if n in ("println", "print"):
return "nyash.console.log"
if n.startswith("nyash.console.") and n.endswith("println"):
return "nyash.console.log"
except Exception:
# Fallthrough to original if anything odd happens
pass
return n

View File

@ -6,6 +6,7 @@ Minimal mapping for NyRT-exported symbols (console/log family等)
import llvmlite.ir as ir
from typing import Dict, List, Optional, Any
from instructions.safepoint import insert_automatic_safepoint
from instructions.extern_normalize import normalize_extern_name
def lower_externcall(
builder: ir.IRBuilder,
@ -45,26 +46,17 @@ def lower_externcall(
bb_map = ctx.bb_map
except Exception:
pass
# Normalize extern target names
# Accept full symbol names (e.g., "nyash.console.log", "nyash.string.len_h").
# Also accept legacy/environment names and map them to kernel exports.
llvm_name = func_name
# Normalize extern target names through shared policy
llvm_name = normalize_extern_name(func_name)
# For C linkage, map dot-qualified console names to underscore symbols.
# This keeps the logical name (nyash.console.log) stable at the MIR level
# while emitting a C-friendly symbol (nyash_console_log) for linkage.
c_symbol_name = llvm_name
try:
if func_name.startswith("env.console."):
# Map env.console.* → nyash.console.* (kernel exports)
method = func_name.split(".")[-1]
# println maps to log for now
if method == "println":
method = "log"
llvm_name = f"nyash.console.{method}"
elif func_name == "println" or func_name == "print":
# Bare println/print fallback
llvm_name = "nyash.console.log"
elif func_name.startswith("nyash.console.") and func_name.endswith("println"):
# Normalize nyash.console.println → nyash.console.log
llvm_name = "nyash.console.log"
if llvm_name.startswith("nyash.console."):
c_symbol_name = llvm_name.replace(".", "_")
except Exception:
pass
c_symbol_name = llvm_name
i8 = ir.IntType(8)
i64 = ir.IntType(64)
@ -95,22 +87,22 @@ def lower_externcall(
# Find or declare function with appropriate prototype
func = None
for f in module.functions:
if f.name == llvm_name:
if f.name == c_symbol_name:
func = f
break
if not func:
if llvm_name in sig_map:
ret_ty, arg_tys = sig_map[llvm_name]
fnty = ir.FunctionType(ret_ty, arg_tys)
func = ir.Function(module, fnty, name=llvm_name)
func = ir.Function(module, fnty, name=c_symbol_name)
elif llvm_name.startswith("nyash.console."):
# console.*: (i8*) -> i64
fnty = ir.FunctionType(i64, [i8p])
func = ir.Function(module, fnty, name=llvm_name)
func = ir.Function(module, fnty, name=c_symbol_name)
else:
# Unknown extern: declare as void(...no args...) and call without args
fnty = ir.FunctionType(void, [])
func = ir.Function(module, fnty, name=llvm_name)
func = ir.Function(module, fnty, name=c_symbol_name)
# Prepare/coerce arguments
call_args: List[ir.Value] = []

View File

@ -588,6 +588,10 @@ def lower_extern_call(builder, module, extern_name, args, dst_vid, vmap, resolve
pass
return vmap.get(vid)
# Normalize extern target names via shared normalizer
from instructions.extern_normalize import normalize_extern_name
extern_name = normalize_extern_name(extern_name)
# Look up extern function in module
func = None
for f in module.functions: