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:
@ -10,6 +10,7 @@
|
||||
use super::*;
|
||||
use std::collections::HashMap;
|
||||
use crate::using::spec::{UsingPackage, PackageKind};
|
||||
use crate::using::ssot_bridge::{call_using_resolve_ssot, SsotCtx};
|
||||
|
||||
/// Using/module resolution context accumulated from config/env/nyash.toml
|
||||
pub(super) struct UsingContext {
|
||||
@ -129,6 +130,19 @@ pub(super) fn resolve_using_target(
|
||||
strict: bool,
|
||||
verbose: bool,
|
||||
) -> Result<String, String> {
|
||||
// Phase 22.1: Thin SSOT hook (future wiring). No behavior change for now.
|
||||
if std::env::var("HAKO_USING_SSOT").ok().as_deref() == Some("1")
|
||||
&& std::env::var("HAKO_USING_SSOT_INVOKING")
|
||||
.ok()
|
||||
.as_deref()
|
||||
!= Some("1")
|
||||
{
|
||||
if let Some(ssot_res) = try_resolve_using_target_ssot(
|
||||
tgt, is_path, modules, using_paths, aliases, packages, context_dir, strict, verbose,
|
||||
) {
|
||||
return Ok(ssot_res);
|
||||
}
|
||||
}
|
||||
// Invalidate and rebuild index/cache if env or nyash.toml changed
|
||||
super::box_index::rebuild_if_env_changed();
|
||||
if is_path {
|
||||
@ -330,6 +344,96 @@ pub(super) fn resolve_using_target(
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Thin SSOT wrapper — returns Some(resolved) when an alternative SSOT path is available.
|
||||
/// MVP: return None to keep current behavior. Future: call into Hako `UsingResolveSSOTBox`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn try_resolve_using_target_ssot(
|
||||
tgt: &str,
|
||||
is_path: bool,
|
||||
modules: &[(String, String)],
|
||||
using_paths: &[String],
|
||||
aliases: &HashMap<String, String>,
|
||||
packages: &HashMap<String, UsingPackage>,
|
||||
context_dir: Option<&std::path::Path>,
|
||||
strict: bool,
|
||||
verbose: bool,
|
||||
) -> Option<String> {
|
||||
// Phase 22.1 MVP: Build context and consult SSOT bridge (modules-only).
|
||||
let trace = verbose || crate::config::env::env_bool("NYASH_RESOLVE_TRACE");
|
||||
let mut map: HashMap<String, String> = HashMap::new();
|
||||
for (k, v) in modules {
|
||||
map.insert(k.clone(), v.clone());
|
||||
}
|
||||
let cwd_str = context_dir.and_then(|p| p.to_str()).map(|s| s.to_string());
|
||||
let ctx = SsotCtx { modules: map, using_paths: using_paths.to_vec(), cwd: cwd_str };
|
||||
if let Some(hit) = call_using_resolve_ssot(tgt, &ctx) {
|
||||
if trace {
|
||||
crate::runner::trace::log(format!("[using/ssot] '{}' -> '{}'", tgt, hit));
|
||||
}
|
||||
return Some(hit);
|
||||
}
|
||||
// Optional relative inference (Runner-side, guarded): prefer cwd > using_paths
|
||||
if std::env::var("HAKO_USING_SSOT_RELATIVE").ok().as_deref() == Some("1") {
|
||||
let rel_hako = tgt.replace('.', "/") + ".hako";
|
||||
let rel_ny = tgt.replace('.', "/") + ".nyash";
|
||||
let mut try_paths: Vec<std::path::PathBuf> = Vec::new();
|
||||
if let Some(dir) = context_dir {
|
||||
try_paths.push(dir.join(&rel_hako));
|
||||
try_paths.push(dir.join(&rel_ny));
|
||||
}
|
||||
for base in using_paths {
|
||||
let p = std::path::Path::new(base);
|
||||
try_paths.push(p.join(&rel_hako));
|
||||
try_paths.push(p.join(&rel_ny));
|
||||
}
|
||||
let mut found: Vec<String> = Vec::new();
|
||||
for p in try_paths {
|
||||
if p.exists() {
|
||||
found.push(p.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
if !found.is_empty() {
|
||||
if found.len() > 1 && strict {
|
||||
if trace {
|
||||
let total = found.len();
|
||||
// Allow customizing the number of shown candidates via env (bounded 1..=10)
|
||||
let n_show: usize = std::env::var("HAKO_USING_SSOT_RELATIVE_AMBIG_FIRST_N")
|
||||
.ok()
|
||||
.and_then(|s| s.parse::<usize>().ok())
|
||||
.map(|n| n.clamp(1, 10))
|
||||
.unwrap_or(3);
|
||||
let shown: Vec<String> = found.iter().take(n_show).cloned().collect();
|
||||
// Standardized message: count + first N + explicit delegation policy
|
||||
crate::runner::trace::log(format!(
|
||||
"[using/ssot:relative ambiguous] name='{}' count={} first=[{}] -> delegate=legacy(strict)",
|
||||
tgt,
|
||||
total,
|
||||
shown.join(", ")
|
||||
));
|
||||
}
|
||||
// Strict ambiguity: delegate to legacy resolver (behavior unchanged)
|
||||
} else {
|
||||
let out = found.remove(0);
|
||||
if trace {
|
||||
crate::runner::trace::log(format!(
|
||||
"[using/ssot:relative] '{}' -> '{}' (priority=cwd>using_paths)",
|
||||
tgt, out
|
||||
));
|
||||
}
|
||||
return Some(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fallback: keep parity by delegating to existing resolver within the same gate
|
||||
let prev = std::env::var("HAKO_USING_SSOT_INVOKING").ok();
|
||||
std::env::set_var("HAKO_USING_SSOT_INVOKING", "1");
|
||||
let res = resolve_using_target(
|
||||
tgt, is_path, modules, using_paths, aliases, packages, context_dir, strict, verbose,
|
||||
);
|
||||
if let Some(val) = prev { std::env::set_var("HAKO_USING_SSOT_INVOKING", val); } else { let _ = std::env::remove_var("HAKO_USING_SSOT_INVOKING"); }
|
||||
res.ok()
|
||||
}
|
||||
|
||||
/// Lint: enforce "fields must be at the top of box" rule.
|
||||
/// - Warns by default (when verbose); when `strict` is true, returns Err on any violation.
|
||||
pub(super) fn lint_fields_top(code: &str, strict: bool, verbose: bool) -> Result<(), String> {
|
||||
|
||||
Reference in New Issue
Block a user