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:
39
src/llvm_py/instructions/extern_normalize.py
Normal file
39
src/llvm_py/instructions/extern_normalize.py
Normal 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
|
||||
|
||||
@ -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] = []
|
||||
|
||||
@ -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:
|
||||
|
||||
Reference in New Issue
Block a user