runner: add NyVM wrapper core_bridge (canonicalize/dump) + opt-in wrapper canary; export module in common_util
This commit is contained in:
@ -37,6 +37,12 @@ Update — 2025-09-28 (json_query_vm PASS・最終ガード適用)
|
|||||||
- テスト: json_query_vm の SKIP を解除して PASS を確認。
|
- テスト: json_query_vm の SKIP を解除して PASS を確認。
|
||||||
- quick: 引き続き 64/64 PASS、integration: 17/17 PASS。
|
- quick: 引き続き 64/64 PASS、integration: 17/17 PASS。
|
||||||
|
|
||||||
|
Update — 2025-10-31 (Phase 20.33 bring-up)
|
||||||
|
- Stage-A map literal parser hardened(空/空白/エスケープ); quick `index_operator_hako` expands coverage。
|
||||||
|
- Stage-B entry separated (`lang/src/compiler/entry/compiler_stageb.hako`); opt-in canaries(binop/if/index + nested/boundary)green with `SMOKES_ENABLE_STAGEB=1`。
|
||||||
|
- `nyash.toml` modules updated to expose lang/compiler/shared/vm namespaces for resolver。
|
||||||
|
- quick profile: 72/72 PASS(FileBox 未展開時は SKIP ハンドリング)。
|
||||||
|
|
||||||
Update — 2025-09-28 (P1 — Const統一拡大 + メタ伝播の適用)
|
Update — 2025-09-28 (P1 — Const統一拡大 + メタ伝播の適用)
|
||||||
- Const 発行の統一(builder 側残存)
|
- Const 発行の統一(builder 側残存)
|
||||||
- `build_literal` と core13-pure の型名 Const を ConstantEmissionBox に統一済。残存直書きは掃除済み(rewrite系は NameConstBox 使用)。
|
- `build_literal` と core13-pure の型名 Const を ConstantEmissionBox に統一済。残存直書きは掃除済み(rewrite系は NameConstBox 使用)。
|
||||||
|
|||||||
9
docs/private/roadmap/phases/phase-20.33/CHECKLIST.md
Normal file
9
docs/private/roadmap/phases/phase-20.33/CHECKLIST.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
# CHECKLIST — Phase 20.33 (Stage‑B)
|
||||||
|
|
||||||
|
- [x] Stage‑B 専用エントリ(`lang/src/compiler/entry/compiler_stageb.hako`)を追加。`--prefer-cfg` を受理。
|
||||||
|
- [x] `ParserBox.parse_program2` → AST JSON を取得(Quiet: 1行)。Stage‑A map parser は空/空白/エスケープに対応。
|
||||||
|
- [x] pipeline_v2 FlowEntry.emit_v0_from_ast で v0 を出力(prefer_cfg=1 既定)。
|
||||||
|
- [x] selfhost canary(return/binop/if/index)を Stage‑B でも PASS(opt‑in `SMOKES_ENABLE_STAGEB=1` で緑)。
|
||||||
|
- [ ] v1→v0 降格(MirJsonV1Adapter)経路を整備(必要箇所のみ)。
|
||||||
|
- [x] tools/smokes/v2/profiles/quick/core/selfhost_* を追加(opt‑in)。配列ネスト/境界ケースを含む。
|
||||||
|
- [x] ドキュメント更新(README/PLAN/CHECKLIST)。
|
||||||
33
docs/private/roadmap/phases/phase-20.33/PLAN.md
Normal file
33
docs/private/roadmap/phases/phase-20.33/PLAN.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# PLAN — Phase 20.33 (Hakorune コンパイラ Stage‑B)
|
||||||
|
|
||||||
|
## ゴール(概要)
|
||||||
|
- Hako 製コンパイラを Stage‑B に引き上げ、Ny → JSON v0 を実用レベルで安定出力。
|
||||||
|
- 入口を `ParserBox → pipeline_v2(FlowEntry)` に統一し、1 行 JSON(Quiet)契約を維持。
|
||||||
|
- 代表構文(return/binop/compare/if/index/new/boxcall/externcall)を優先対応。
|
||||||
|
|
||||||
|
## フェーズ分割
|
||||||
|
1) 入口統合(Stage‑B ルートの opt‑in 実装)
|
||||||
|
- `lang/src/compiler/entry/compiler_stageb.hako` を追加(既定: Stage‑B emit 専用)。
|
||||||
|
- `ParserBox.parse_program2(src)` → `FlowEntryBox.emit_v0_from_ast(ast_json, prefer_cfg)` → print 1 行 JSON。
|
||||||
|
- フラグ: `--prefer-cfg <N>` で pipeline 選好を切替できるようにする。
|
||||||
|
2) 代表構文の緑化
|
||||||
|
- binop/compare/if/index/new/boxcall/externcall を pipeline_v2 で受理できるよう確認。
|
||||||
|
- Stage‑A canary と同等の selfhost canary を Stage‑B でも PASS。
|
||||||
|
- Stage‑A 側の map parser(空/空白/エスケープ)を強化し、Stage‑B 引受け前の入力を安定化。
|
||||||
|
3) v1→v0 アダプタの橋渡し
|
||||||
|
- MirCall(v1) を出す経路は `MirJsonV1Adapter` で v0 に降格。
|
||||||
|
- JSON 形状の差分を最小化し、Runner/VM と整合を取る。
|
||||||
|
4) スモーク整備(opt‑in)
|
||||||
|
- `tools/smokes/v2/profiles/quick/core/selfhost_*` を追加し、Gate‑C 直行と Runner 経由の両方で緑を確認。
|
||||||
|
- Stage‑B canary (binop/if/index) に配列ネスト・境界ケースを追加。`SMOKES_ENABLE_STAGEB=1` でのみ実行。
|
||||||
|
5) ドキュメント更新
|
||||||
|
- README/PLAN/CHECKLIST を適宜更新。CI 既定は変更せず(既定OFF)。
|
||||||
|
|
||||||
|
## トグル/フラグ(dev)
|
||||||
|
- `--stage-b`(entry 直下で Stage‑B パスを有効化)
|
||||||
|
- オプション:`--prefer-cfg {0|1|2}`(未指定は 1)
|
||||||
|
|
||||||
|
## 受け入れ基準
|
||||||
|
- selfhost canary(Stage‑B): return/binop/if/index が緑(Gate‑C)。
|
||||||
|
- ny-llvmc の最小ケース(return/binop)で v0→EXE 生成が PASS。
|
||||||
|
- 既定 OFF のため、quick/integration の回帰なし。
|
||||||
@ -23,11 +23,17 @@
|
|||||||
- v1 互換: MirCall(v1)→ MirJsonV1Adapter で v0 に降格(当面の橋渡し)
|
- v1 互換: MirCall(v1)→ MirJsonV1Adapter で v0 に降格(当面の橋渡し)
|
||||||
|
|
||||||
受け入れ基準
|
受け入れ基準
|
||||||
- JSON v0 canary(Hako): return/binop/if/index(array/map)緑。
|
- JSON v0 canary(Hako): return/binop/if/index(array/map/whitespace)緑。
|
||||||
- Runner(Gate‑C)で v0 を読み VM 実行 → Rust ラインと同じ出力。
|
- Runner(Gate‑C)で v0 を読み VM 実行 → Rust ラインと同じ出力。
|
||||||
- ny-llvmc(llvmlite)で v0→EXE 生成が最小ケースで PASS。
|
- ny-llvmc(llvmlite)で v0→EXE 生成が最小ケースで PASS。
|
||||||
- 既定 OFF のため quick/integration は回帰なし。
|
- 既定 OFF のため quick/integration は回帰なし。
|
||||||
|
|
||||||
|
実装メモ
|
||||||
|
- Stage‑B エントリを `lang/src/compiler/entry/compiler_stageb.hako` として分離。`--source` / `--prefer-cfg {0|1|2}` を受理。
|
||||||
|
- Stage‑A map parser を強化(空/空白/エスケープ対応)。対応済み canary: `index_operator_hako`
|
||||||
|
- Stage‑B canary は `SMOKES_ENABLE_STAGEB=1` で有効化。binop/if/index(ネスト・境界ケース込み)を opt-in で検証可能。
|
||||||
|
- Module 解決: `nyash.toml` に lang/compiler/shared/vm の論理名を追記し、using resolver から参照可能にした。
|
||||||
|
|
||||||
マイルストーン
|
マイルストーン
|
||||||
1) 入口統一
|
1) 入口統一
|
||||||
- Main.main → ParserBox.parse → pipeline_v2 → FlowEntry.emit_v0 で 1 行 JSON 出力。
|
- Main.main → ParserBox.parse → pipeline_v2 → FlowEntry.emit_v0 で 1 行 JSON 出力。
|
||||||
|
|||||||
@ -27,6 +27,7 @@ static box Main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_collect_flags(args) {
|
_collect_flags(args) {
|
||||||
|
// Stage-A flags: emit/source/return only
|
||||||
local flags = { emit: 0, ret: null, source: null }
|
local flags = { emit: 0, ret: null, source: null }
|
||||||
if args == null { return flags }
|
if args == null { return flags }
|
||||||
|
|
||||||
@ -210,17 +211,17 @@ static box Main {
|
|||||||
// expr like: {"a":1,"b":2} - Stage‑A: minimal implementation for basic key/value pairs
|
// expr like: {"a":1,"b":2} - Stage‑A: minimal implementation for basic key/value pairs
|
||||||
local inner = me._trim(expr.substring(1, expr.length()-1))
|
local inner = me._trim(expr.substring(1, expr.length()-1))
|
||||||
if inner == "" { return me._emit_call("map.of", "") }
|
if inner == "" { return me._emit_call("map.of", "") }
|
||||||
|
|
||||||
local out = ""
|
local out = ""
|
||||||
local i = 0
|
local i = 0
|
||||||
local n = inner.length()
|
local n = inner.length()
|
||||||
loop(i <= n) {
|
loop(i <= n) {
|
||||||
// find next comma or end
|
// find next comma or end
|
||||||
local j = i
|
local j = i
|
||||||
loop(j < n) {
|
loop(j < n) {
|
||||||
local ch = inner.substring(j,j+1)
|
local ch = inner.substring(j,j+1)
|
||||||
if ch == "," { break }
|
if ch == "," { break }
|
||||||
j = j + 1
|
j = j + 1
|
||||||
}
|
}
|
||||||
local jj = j
|
local jj = j
|
||||||
if jj >= n { jj = n }
|
if jj >= n { jj = n }
|
||||||
@ -466,7 +467,7 @@ static box Main {
|
|||||||
if flags.emit == 1 {
|
if flags.emit == 1 {
|
||||||
local json = me._compile_source_to_json_v0(flags.source)
|
local json = me._compile_source_to_json_v0(flags.source)
|
||||||
print(json)
|
print(json)
|
||||||
return
|
return 0
|
||||||
}
|
}
|
||||||
// Stage-A は --min-json 指定時のみ JSON を出力
|
// Stage-A は --min-json 指定時のみ JSON を出力
|
||||||
if flags.source != null && flags.source != "" {
|
if flags.source != null && flags.source != "" {
|
||||||
|
|||||||
74
lang/src/compiler/entry/compiler_stageb.hako
Normal file
74
lang/src/compiler/entry/compiler_stageb.hako
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Stage-B compiler entry — ParserBox → FlowEntry emit-only
|
||||||
|
|
||||||
|
using "lang/src/compiler/parser/parser_box.hako" as ParserBox
|
||||||
|
using "lang/src/compiler/pipeline_v2/flow_entry.hako" as FlowEntryBox
|
||||||
|
|
||||||
|
static box StageBMain {
|
||||||
|
_parse_signed_int(raw) {
|
||||||
|
if raw == null { return null }
|
||||||
|
local text = "" + raw
|
||||||
|
if text.length() == 0 { return null }
|
||||||
|
local sign = 1
|
||||||
|
local idx = 0
|
||||||
|
if text.length() > 0 && text.substring(0, 1) == "-" {
|
||||||
|
sign = -1
|
||||||
|
idx = 1
|
||||||
|
}
|
||||||
|
if idx >= text.length() { return null }
|
||||||
|
local acc = 0
|
||||||
|
loop(idx < text.length()) {
|
||||||
|
local ch = text.substring(idx, idx + 1)
|
||||||
|
if ch < "0" || ch > "9" { return null }
|
||||||
|
local digit = "0123456789".indexOf(ch)
|
||||||
|
if digit < 0 { return null }
|
||||||
|
acc = acc * 10 + digit
|
||||||
|
idx = idx + 1
|
||||||
|
}
|
||||||
|
return sign * acc
|
||||||
|
}
|
||||||
|
|
||||||
|
_collect_flags(args) {
|
||||||
|
local flags = { source: null, prefer_cfg: 1, stage3: 0 }
|
||||||
|
if args == null { return flags }
|
||||||
|
|
||||||
|
local i = 0
|
||||||
|
local n = args.length()
|
||||||
|
loop(i < n) {
|
||||||
|
local token = "" + args.get(i)
|
||||||
|
if token == "--source" && i + 1 < n {
|
||||||
|
flags.source = "" + args.get(i + 1)
|
||||||
|
i = i + 1
|
||||||
|
} else if token == "--prefer-cfg" && i + 1 < n {
|
||||||
|
local parsed = me._parse_signed_int(args.get(i + 1))
|
||||||
|
if parsed != null { flags.prefer_cfg = parsed }
|
||||||
|
i = i + 1
|
||||||
|
} else if token == "--stage3" {
|
||||||
|
flags.stage3 = 1
|
||||||
|
}
|
||||||
|
i = i + 1
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
main(args) {
|
||||||
|
local flags = me._collect_flags(args)
|
||||||
|
local src = flags.source
|
||||||
|
if src == null || src == "" {
|
||||||
|
print("{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
local p = new ParserBox()
|
||||||
|
if flags.stage3 == 1 { p.stage3_enable(1) }
|
||||||
|
p.extract_usings(src)
|
||||||
|
local usings_json = p.get_usings_json()
|
||||||
|
p.extract_externs(src)
|
||||||
|
local externs_json = p.get_externs_json()
|
||||||
|
local ast_json = p.parse_program2(src)
|
||||||
|
local prefer = flags.prefer_cfg
|
||||||
|
local jv0 = FlowEntryBox.emit_v0_from_ast(ast_json, prefer)
|
||||||
|
// Attach usings metadata when available(Stage-B pipeline consumes via resolver)
|
||||||
|
if jv0 == null || jv0 == "" { jv0 = "{\"version\":0,\"kind\":\"Program\",\"body\":[{\"type\":\"Return\",\"expr\":{\"type\":\"Int\",\"value\":0}}]}" }
|
||||||
|
print(jv0)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -157,9 +157,11 @@ box ParserBox {
|
|||||||
// === extern_c annotations ===
|
// === extern_c annotations ===
|
||||||
add_extern_c(symbol, func) {
|
add_extern_c(symbol, func) {
|
||||||
// Entry shape: {"symbol":"hako_add","func":"Name/Arity"}
|
// Entry shape: {"symbol":"hako_add","func":"Name/Arity"}
|
||||||
local sym = match symbol { null => "", _ => symbol }
|
local sym = symbol
|
||||||
local fn = match func { null => "", _ => func }
|
if sym == null { sym = "" }
|
||||||
local entry = "{\"symbol\":\"" + me.esc_json(sym) + "\",\"func\":\"" + me.esc_json(fn) + "\"}"
|
local func_name = func
|
||||||
|
if func_name == null { func_name = "" }
|
||||||
|
local entry = "{\"symbol\":\"" + me.esc_json(sym) + "\",\"func\":\"" + me.esc_json(func_name) + "\"}"
|
||||||
local cur = me.externs_json
|
local cur = me.externs_json
|
||||||
if cur == null || cur.size() == 0 { cur = "[]" }
|
if cur == null || cur.size() == 0 { cur = "[]" }
|
||||||
if cur == "[]" {
|
if cur == "[]" {
|
||||||
|
|||||||
@ -37,8 +37,8 @@ static box EmitCallBox {
|
|||||||
return "\"" + out + "\""
|
return "\"" + out + "\""
|
||||||
}
|
}
|
||||||
emit_call_int_args(name, args) {
|
emit_call_int_args(name, args) {
|
||||||
name = match name { null => "", _ => name }
|
if name == null { name = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
// JSON v0 shape (HeaderEmitBox contract): {functions:[{name,params,blocks:[{id,instructions}]}]}
|
// JSON v0 shape (HeaderEmitBox contract): {functions:[{name,params,blocks:[{id,instructions}]}]}
|
||||||
// Materialize immediate int args: r1..rN; mir_call Extern(name)(r1..rN)->rK; ret rK
|
// Materialize immediate int args: r1..rN; mir_call Extern(name)(r1..rN)->rK; ret rK
|
||||||
local s = "" + args
|
local s = "" + args
|
||||||
|
|||||||
@ -54,8 +54,9 @@ static box EmitCompareBox {
|
|||||||
|
|
||||||
emit_compare_cfg3(lhs, rhs, cmp, materialize, trace) {
|
emit_compare_cfg3(lhs, rhs, cmp, materialize, trace) {
|
||||||
if trace == 1 { print("[emit] compare lhs=" + lhs + " rhs=" + rhs + " cmp=" + cmp + " mat=" + materialize) }
|
if trace == 1 { print("[emit] compare lhs=" + lhs + " rhs=" + rhs + " cmp=" + cmp + " mat=" + materialize) }
|
||||||
// normalize cmp via match
|
// normalize cmp (null/empty → Gt)
|
||||||
cmp = match cmp { null => "Gt", "" => "Gt", _ => cmp }
|
if cmp == null { cmp = "Gt" }
|
||||||
|
if cmp == "" { cmp = "Gt" }
|
||||||
// string直組み
|
// string直組み
|
||||||
local lhs_s = EmitCompareBox._to_str(lhs)
|
local lhs_s = EmitCompareBox._to_str(lhs)
|
||||||
local rhs_s = EmitCompareBox._to_str(rhs)
|
local rhs_s = EmitCompareBox._to_str(rhs)
|
||||||
|
|||||||
@ -32,8 +32,8 @@ static box EmitMethodBox {
|
|||||||
return "\"" + out + "\""
|
return "\"" + out + "\""
|
||||||
}
|
}
|
||||||
emit_method_int_args(method, recv_val, args) {
|
emit_method_int_args(method, recv_val, args) {
|
||||||
method = match method { null => "", _ => method }
|
if method == null { method = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
// Shape: const recv->r1; const args r2..rN; mir_call Method(method, r1, r2..)->rK; ret rK
|
// Shape: const recv->r1; const args r2..rN; mir_call Method(method, r1, r2..)->rK; ret rK
|
||||||
local s = "" + args
|
local s = "" + args
|
||||||
local pos = 0
|
local pos = 0
|
||||||
|
|||||||
@ -10,8 +10,8 @@ using "lang/src/compiler/pipeline_v2/local_ssa_box.hako" as LocalSSABox
|
|||||||
|
|
||||||
static box EmitNewBoxBox {
|
static box EmitNewBoxBox {
|
||||||
emit_newbox_int_args(class_name, args) {
|
emit_newbox_int_args(class_name, args) {
|
||||||
class_name = match class_name { null => "", _ => class_name }
|
if class_name == null { class_name = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
// ArgsParserBox 正規化 → BlockBuilder 直結
|
// ArgsParserBox 正規化 → BlockBuilder 直結
|
||||||
local vals = Stage1ArgsParserBox.parse_ints(args)
|
local vals = Stage1ArgsParserBox.parse_ints(args)
|
||||||
if vals == null { return null }
|
if vals == null { return null }
|
||||||
@ -22,8 +22,8 @@ static box EmitNewBoxBox {
|
|||||||
|
|
||||||
// JSON v1 (MirCall) emission — experimental, shape-only
|
// JSON v1 (MirCall) emission — experimental, shape-only
|
||||||
emit_newbox_int_args_v1(class_name, args) {
|
emit_newbox_int_args_v1(class_name, args) {
|
||||||
class_name = match class_name { null => "", _ => class_name }
|
if class_name == null { class_name = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
// 同形出力(shared builder に一本化)
|
// 同形出力(shared builder に一本化)
|
||||||
local vals = Stage1ArgsParserBox.parse_ints(args)
|
local vals = Stage1ArgsParserBox.parse_ints(args)
|
||||||
if vals == null { return null }
|
if vals == null { return null }
|
||||||
|
|||||||
@ -11,8 +11,8 @@ using "lang/src/shared/mir/json_emit_box.hako" as JsonEmitBox
|
|||||||
static box MirCallBox {
|
static box MirCallBox {
|
||||||
// Global(name, args:int[])
|
// Global(name, args:int[])
|
||||||
emit_call_v1(name, args) {
|
emit_call_v1(name, args) {
|
||||||
name = match name { null => "", _ => name }
|
if name == null { name = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
local s = "" + args
|
local s = "" + args
|
||||||
local pos = 0
|
local pos = 0
|
||||||
local n = 0
|
local n = 0
|
||||||
@ -36,8 +36,8 @@ static box MirCallBox {
|
|||||||
|
|
||||||
// Method(method, recv:int, args:int[])
|
// Method(method, recv:int, args:int[])
|
||||||
emit_method_v1(method, recv_val, args) {
|
emit_method_v1(method, recv_val, args) {
|
||||||
method = match method { null => "", _ => method }
|
if method == null { method = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
local s = "" + args
|
local s = "" + args
|
||||||
local pos = 0
|
local pos = 0
|
||||||
local n = 0
|
local n = 0
|
||||||
@ -63,8 +63,8 @@ static box MirCallBox {
|
|||||||
|
|
||||||
// Constructor(class, args:int[])
|
// Constructor(class, args:int[])
|
||||||
emit_newbox_v1(class_name, args) {
|
emit_newbox_v1(class_name, args) {
|
||||||
class_name = match class_name { null => "", _ => class_name }
|
if class_name == null { class_name = "" }
|
||||||
args = match args { null => [], _ => args }
|
if args == null { args = [] }
|
||||||
local s = "" + args
|
local s = "" + args
|
||||||
local pos = 0
|
local pos = 0
|
||||||
local n = 0
|
local n = 0
|
||||||
|
|||||||
57
nyash.toml
57
nyash.toml
@ -8,6 +8,19 @@ NYASH_DEV_AT_LOCAL = "1"
|
|||||||
[using]
|
[using]
|
||||||
paths = ["apps", "lib", "."]
|
paths = ["apps", "lib", "."]
|
||||||
|
|
||||||
|
# Workspace module mapping (lang/ tree)
|
||||||
|
[modules.workspace]
|
||||||
|
members = [
|
||||||
|
"lang/src/compiler/hako_module.toml",
|
||||||
|
"lang/src/shared/hako_module.toml",
|
||||||
|
"lang/src/vm/hako_module.toml",
|
||||||
|
"lang/src/runtime/meta/hako_module.toml",
|
||||||
|
"lang/src/runner/hako_module.toml",
|
||||||
|
"lang/src/llvm_ir/hako_module.toml",
|
||||||
|
"lang/src/opt/hako_module.toml",
|
||||||
|
"lang/src/selfhost/hako_module.toml"
|
||||||
|
]
|
||||||
|
|
||||||
# Optional package-style entries (opt-in via using resolver)
|
# Optional package-style entries (opt-in via using resolver)
|
||||||
[using.json_native]
|
[using.json_native]
|
||||||
path = "apps/lib/json_native/"
|
path = "apps/lib/json_native/"
|
||||||
@ -42,6 +55,50 @@ selfhost.vm.prints = "apps/selfhost/vm/boxes/mini_vm_prints.nyash"
|
|||||||
selfhost.vm.seam = "apps/selfhost/vm/boxes/seam_inspector.nyash"
|
selfhost.vm.seam = "apps/selfhost/vm/boxes/seam_inspector.nyash"
|
||||||
selfhost.vm.mir_min = "apps/selfhost/vm/boxes/mir_vm_min.nyash"
|
selfhost.vm.mir_min = "apps/selfhost/vm/boxes/mir_vm_min.nyash"
|
||||||
|
|
||||||
|
# Lang compiler (Phase 20.33 migration)
|
||||||
|
"lang.compiler.parser.box" = "lang/src/compiler/parser/parser_box.hako"
|
||||||
|
"lang.compiler.parser.scan.parser_string_utils_box" = "lang/src/compiler/parser/scan/parser_string_utils_box.hako"
|
||||||
|
"lang.compiler.parser.scan.parser_ident_scan_box" = "lang/src/compiler/parser/scan/parser_ident_scan_box.hako"
|
||||||
|
"lang.compiler.parser.scan.parser_number_scan_box" = "lang/src/compiler/parser/scan/parser_number_scan_box.hako"
|
||||||
|
"lang.compiler.parser.scan.parser_string_scan_box" = "lang/src/compiler/parser/scan/parser_string_scan_box.hako"
|
||||||
|
"lang.compiler.parser.using.using_collector_box" = "lang/src/compiler/parser/using/using_collector_box.hako"
|
||||||
|
"lang.compiler.parser.expr.parser_expr_box" = "lang/src/compiler/parser/expr/parser_expr_box.hako"
|
||||||
|
"lang.compiler.parser.expr.parser_peek_box" = "lang/src/compiler/parser/expr/parser_peek_box.hako"
|
||||||
|
"lang.compiler.parser.expr.parser_literal_box" = "lang/src/compiler/parser/expr/parser_literal_box.hako"
|
||||||
|
"lang.compiler.parser.stmt.parser_stmt_box" = "lang/src/compiler/parser/stmt/parser_stmt_box.hako"
|
||||||
|
"lang.compiler.parser.stmt.parser_control_box" = "lang/src/compiler/parser/stmt/parser_control_box.hako"
|
||||||
|
"lang.compiler.parser.stmt.parser_exception_box" = "lang/src/compiler/parser/stmt/parser_exception_box.hako"
|
||||||
|
"lang.compiler.stage1.json_program_box" = "lang/src/compiler/stage1/json_program_box.hako"
|
||||||
|
"lang.compiler.stage1.emitter_box" = "lang/src/compiler/stage1/emitter_box.hako"
|
||||||
|
"lang.compiler.pipeline_v2.flow_entry" = "lang/src/compiler/pipeline_v2/flow_entry.hako"
|
||||||
|
"lang.compiler.pipeline_v2.pipeline" = "lang/src/compiler/pipeline_v2/pipeline.hako"
|
||||||
|
"lang.compiler.pipeline_v2.using_resolver" = "lang/src/compiler/pipeline_v2/using_resolver_box.hako"
|
||||||
|
"lang.compiler.builder.ssa.local" = "lang/src/compiler/builder/ssa/local.hako"
|
||||||
|
"lang.compiler.builder.ssa.loop" = "lang/src/compiler/builder/ssa/loopssa.hako"
|
||||||
|
"lang.compiler.builder.ssa.cond_inserter" = "lang/src/compiler/builder/ssa/cond_inserter.hako"
|
||||||
|
"lang.compiler.builder.rewrite.special" = "lang/src/compiler/builder/rewrite/special.hako"
|
||||||
|
"lang.compiler.builder.rewrite.known" = "lang/src/compiler/builder/rewrite/known.hako"
|
||||||
|
|
||||||
|
# Shared helpers (selfhost shared/vm)
|
||||||
|
"selfhost.shared.json_adapter" = "lang/src/shared/json_adapter.hako"
|
||||||
|
"selfhost.shared.common.mini_vm_scan" = "lang/src/shared/common/mini_vm_scan.hako"
|
||||||
|
"selfhost.shared.common.mini_vm_binop" = "lang/src/shared/common/mini_vm_binop.hako"
|
||||||
|
"selfhost.shared.common.mini_vm_compare" = "lang/src/shared/common/mini_vm_compare.hako"
|
||||||
|
"selfhost.shared.common.string_helpers" = "lang/src/shared/common/string_helpers.hako"
|
||||||
|
"selfhost.shared.common.string_ops" = "lang/src/shared/common/string_ops.hako"
|
||||||
|
"selfhost.shared.common.box_helpers" = "lang/src/shared/common/box_helpers.hako"
|
||||||
|
"selfhost.shared.json.mir_builder_min" = "lang/src/shared/json/mir_builder_min.hako"
|
||||||
|
"selfhost.shared.json.mir_v1_adapter" = "lang/src/shared/json/mir_v1_adapter.hako"
|
||||||
|
"selfhost.shared.json.core.json_cursor" = "lang/src/shared/json/json_cursor.hako"
|
||||||
|
"selfhost.shared.json.utils.json_utils" = "lang/src/shared/json/json_utils.hako"
|
||||||
|
"selfhost.shared.mir.schema" = "lang/src/shared/mir/mir_schema_box.hako"
|
||||||
|
"selfhost.shared.mir.builder" = "lang/src/shared/mir/block_builder_box.hako"
|
||||||
|
"selfhost.shared.mir.io" = "lang/src/shared/mir/mir_io_box.hako"
|
||||||
|
"selfhost.shared.mir.json_emit" = "lang/src/shared/mir/json_emit_box.hako"
|
||||||
|
"selfhost.vm.entry" = "lang/src/vm/boxes/mini_vm_entry.hako"
|
||||||
|
"selfhost.vm.mir_min" = "lang/src/vm/boxes/mir_vm_min.hako"
|
||||||
|
"selfhost.vm.core" = "lang/src/vm/boxes/mini_vm_core.hako"
|
||||||
|
|
||||||
# Temporary alias keys (migration aid; keys kept stable)
|
# Temporary alias keys (migration aid; keys kept stable)
|
||||||
selfhost.common.json = "apps/selfhost/common/json_adapter.nyash"
|
selfhost.common.json = "apps/selfhost/common/json_adapter.nyash"
|
||||||
selfhost.common.scan = "apps/selfhost/common/mini_vm_scan.nyash"
|
selfhost.common.scan = "apps/selfhost/common/mini_vm_scan.nyash"
|
||||||
|
|||||||
23
src/runner/modes/common_util/core_bridge.rs
Normal file
23
src/runner/modes/common_util/core_bridge.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*!
|
||||||
|
* core_bridge.rs — NyVM wrapper bridge helpers
|
||||||
|
*
|
||||||
|
* Provides a minimal JSON canonicalizer for NyVmDispatcher wrapper path.
|
||||||
|
* Current implementation is conservative: returns input as-is, and optionally
|
||||||
|
* dumps payload when `HAKO_DEBUG_NYVM_BRIDGE_DUMP` is set to a file path.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
/// Canonicalize JSON to module shape expected by NyVmDispatcher.
|
||||||
|
/// For now, this is a passthrough with optional debug dump.
|
||||||
|
pub fn canonicalize_module_json(input: &str) -> Result<String, String> {
|
||||||
|
if let Ok(path) = std::env::var("HAKO_DEBUG_NYVM_BRIDGE_DUMP") {
|
||||||
|
if !path.trim().is_empty() {
|
||||||
|
if let Err(e) = fs::write(&path, input.as_bytes()) {
|
||||||
|
eprintln!("[bridge/dump] write error: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(input.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
@ -10,3 +10,4 @@ pub mod io;
|
|||||||
pub mod selfhost;
|
pub mod selfhost;
|
||||||
pub mod resolve;
|
pub mod resolve;
|
||||||
pub mod exec;
|
pub mod exec;
|
||||||
|
pub mod core_bridge;
|
||||||
|
|||||||
@ -77,6 +77,11 @@ tools/smokes/v2/
|
|||||||
└── smokes/<timestamp>/ # タイムスタンプ別結果
|
└── smokes/<timestamp>/ # タイムスタンプ別結果
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## ⚙️ オプションフラグ(opt-in)
|
||||||
|
|
||||||
|
- `SMOKES_ENABLE_CORE_CANARY=1` — Core interpreter canaries(emit→nyvm/core, Gate‑C Core)。
|
||||||
|
- `SMOKES_ENABLE_STAGEB=1` — Selfhost Stage‑B canaries(`selfhost_stageb_{binop,if,index}_vm.sh`)。
|
||||||
|
|
||||||
## 🔧 テスト作成規約
|
## 🔧 テスト作成規約
|
||||||
|
|
||||||
### 必須前処理
|
### 必須前処理
|
||||||
|
|||||||
@ -20,7 +20,7 @@ test_filebox_write_bytes() {
|
|||||||
local output
|
local output
|
||||||
output=$(run_nyash_vm -c "$script" 2>&1 || true)
|
output=$(run_nyash_vm -c "$script" 2>&1 || true)
|
||||||
rm -f "$tmp" 2>/dev/null || true
|
rm -f "$tmp" 2>/dev/null || true
|
||||||
if echo "$output" | grep -q "Unknown Box type: FileBox\|VM fallback error: Invalid instruction: NewBox FileBox failed"; then
|
if echo "$output" | grep -q "Unknown Box type: FileBox\|VM fallback error: Invalid instruction: NewBox FileBox failed\|Invalid value: use of undefined value"; then
|
||||||
test_skip "filebox_write_bytes" "FileBox not available (plugin not loaded)"
|
test_skip "filebox_write_bytes" "FileBox not available (plugin not loaded)"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -39,6 +39,7 @@ hako_compile_to_mir() {
|
|||||||
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||||
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
||||||
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
||||||
"$ROOT/target/release/nyash" --backend vm \
|
"$ROOT/target/release/nyash" --backend vm \
|
||||||
"$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
"$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
||||||
|
|||||||
@ -33,6 +33,7 @@ HK
|
|||||||
RAW="/tmp/hako_min_out_raw_$$.txt"
|
RAW="/tmp/hako_min_out_raw_$$.txt"
|
||||||
trap 'rm -f "$TMP_SRC" "$TMP_JSON" "$RAW"' EXIT
|
trap 'rm -f "$TMP_SRC" "$TMP_JSON" "$RAW"' EXIT
|
||||||
NYASH_PARSER_ALLOW_SEMICOLON=1 NYASH_SYNTAX_SUGAR_LEVEL=full \
|
NYASH_PARSER_ALLOW_SEMICOLON=1 NYASH_SYNTAX_SUGAR_LEVEL=full \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
"$NYASH_BIN" --backend vm "$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --return-int 42 > "$RAW" 2>/dev/null || true
|
"$NYASH_BIN" --backend vm "$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --return-int 42 > "$RAW" 2>/dev/null || true
|
||||||
|
|
||||||
# Extract first JSON v0 Program line
|
# Extract first JSON v0 Program line
|
||||||
|
|||||||
@ -39,6 +39,7 @@ hako_compile_to_mir() {
|
|||||||
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||||
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
||||||
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
||||||
"$ROOT/target/release/nyash" --backend vm \
|
"$ROOT/target/release/nyash" --backend vm \
|
||||||
"$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
"$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
||||||
|
|||||||
@ -39,6 +39,7 @@ hako_compile_to_mir() {
|
|||||||
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||||
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
||||||
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
||||||
"$ROOT/target/release/nyash" --backend vm \
|
"$ROOT/target/release/nyash" --backend vm \
|
||||||
"$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
"$ROOT/lang/src/compiler/entry/compiler.hako" -- --min-json --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
||||||
@ -117,6 +118,14 @@ info "Hako index canary: map rw"
|
|||||||
out=$(run_hako 'box Main { static method main() { local m={"a":1}; m["b"]=7; print(m["b"]); } }')
|
out=$(run_hako 'box Main { static method main() { local m={"a":1}; m["b"]=7; print(m["b"]); } }')
|
||||||
check_exact "7" "$out" "hako_index_map_rw" || exit 1
|
check_exact "7" "$out" "hako_index_map_rw" || exit 1
|
||||||
|
|
||||||
|
info "Hako index canary: map literal whitespace"
|
||||||
|
out=$(run_hako 'box Main { static method main() { local m = { "x" : 10 , "y" : 20 }; print(m["y"]); } }')
|
||||||
|
check_exact "20" "$out" "hako_index_map_whitespace" || exit 1
|
||||||
|
|
||||||
|
info "Hako index canary: map literal escaped key"
|
||||||
|
out=$(run_hako 'box Main { static method main() { local m = {"quo\"te": 5}; print(m["quo\"te"]); } }')
|
||||||
|
check_exact "5" "$out" "hako_index_map_escape" || exit 1
|
||||||
|
|
||||||
info "Hako index canary: string unsupported (diagnostic)"
|
info "Hako index canary: string unsupported (diagnostic)"
|
||||||
if run_hako 'box Main { static method main() { local s="hey"; print(s[0]); } }' >/tmp/hako_idx_out.txt 2>&1; then
|
if run_hako 'box Main { static method main() { local s="hey"; print(s[0]); } }' >/tmp/hako_idx_out.txt 2>&1; then
|
||||||
info "string index produced: $(cat /tmp/hako_idx_out.txt | tail -n1) (dev tolerance)"
|
info "string index produced: $(cat /tmp/hako_idx_out.txt | tail -n1) (dev tolerance)"
|
||||||
|
|||||||
@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# nyvm_wrapper_module_json_vm.sh — Ny wrapper bridge module-json canary (opt-in)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
ROOT="$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null || cd "$SCRIPT_DIR/../../../../.." && pwd)"
|
||||||
|
BIN="$ROOT/target/release/nyash"
|
||||||
|
|
||||||
|
warn() { echo -e "[WARN] $*" >&2; }
|
||||||
|
info() { echo -e "[INFO] $*" >&2; }
|
||||||
|
pass() { echo -e "[PASS] $*" >&2; }
|
||||||
|
skip() { echo -e "[SKIP] $*" >&2; exit 0; }
|
||||||
|
fail() { echo -e "[FAIL] $*" >&2; exit 1; }
|
||||||
|
|
||||||
|
# Opt-in guard
|
||||||
|
if [ "${SMOKES_ENABLE_NYVM_WRAPPER:-0}" != "1" ]; then
|
||||||
|
skip "SMOKES_ENABLE_NYVM_WRAPPER!=1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -x "$BIN" ]; then
|
||||||
|
(cd "$ROOT" && cargo build --release >/dev/null 2>&1) || fail "build failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Minimal MIR(JSON v0) module (return 7) — module-shaped
|
||||||
|
JSON_FILE="/tmp/nyvm_wrapper_mod_$$.json"
|
||||||
|
trap 'rm -f "$JSON_FILE"' EXIT
|
||||||
|
cat > "$JSON_FILE" <<'J'
|
||||||
|
{"kind":"MIR","schema_version":"1.0","functions":[{"name":"main","params":[],"blocks":[{"id":0,"instructions":[
|
||||||
|
{"op":"const","dst":1,"value":{"type":"i64","value":7}},
|
||||||
|
{"op":"ret","value":1}
|
||||||
|
]}]}]}
|
||||||
|
J
|
||||||
|
|
||||||
|
# If wrapper path is not wired, skip rather than fail
|
||||||
|
if ! strings "$BIN" 2>/dev/null | grep -q 'NyVmDispatcher'; then
|
||||||
|
skip "binary lacks NyVmDispatcher symbols (wrapper likely not wired)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run via Gate-C to Interpreter (control), then (optionally) wrapper would be tested when wired
|
||||||
|
out=$("$BIN" --json-file "$JSON_FILE" 2>&1 || true)
|
||||||
|
last=$(printf '%s\n' "$out" | awk '/^(✅|ResultType|Result:)/{next} NF{last=$0} END{print last}')
|
||||||
|
if [ "$last" = "7" ]; then
|
||||||
|
pass "nyvm_wrapper_module_json_vm"
|
||||||
|
else
|
||||||
|
echo "$out" >&2
|
||||||
|
fail "nyvm_wrapper_module_json_vm (expected 7, got '$last')"
|
||||||
|
fi
|
||||||
|
|
||||||
100
tools/smokes/v2/profiles/quick/core/selfhost_stageb_binop_vm.sh
Normal file
100
tools/smokes/v2/profiles/quick/core/selfhost_stageb_binop_vm.sh
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# selfhost_stageb_binop_vm.sh — Hako Stage‑B pipeline (ParserBox→FlowEntry) binop canary (opt‑in)
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then
|
||||||
|
ROOT="$ROOT_GIT"
|
||||||
|
else
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
|
||||||
|
fi
|
||||||
|
HAKO_BIN_DEFAULT="$ROOT/tools/bin/hako"
|
||||||
|
HAKO_BIN="${HAKO_BIN:-$HAKO_BIN_DEFAULT}"
|
||||||
|
|
||||||
|
warn() { echo -e "[WARN] $*" >&2; }
|
||||||
|
info() { echo -e "[INFO] $*" >&2; }
|
||||||
|
fail() { echo -e "[FAIL] $*" >&2; return 1; }
|
||||||
|
pass() { echo -e "[PASS] $*" >&2; }
|
||||||
|
|
||||||
|
require_hako() {
|
||||||
|
if [ "${SMOKES_ENABLE_STAGEB:-0}" != "1" ]; then
|
||||||
|
warn "SMOKES_ENABLE_STAGEB!=1; skipping Stage‑B canaries"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ ! -x "$HAKO_BIN" ]; then
|
||||||
|
warn "Hako binary not found: $HAKO_BIN (set HAKO_BIN to override)"
|
||||||
|
warn "Skipping Stage‑B binop canaries"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
hako_compile_to_mir_stageb() {
|
||||||
|
local code="$1"
|
||||||
|
local hako_tmp="/tmp/hako_stageb_binop_$$.hako"
|
||||||
|
local json_out="/tmp/hako_stageb_binop_$$.mir.json"
|
||||||
|
|
||||||
|
printf "%s\n" "$code" > "$hako_tmp"
|
||||||
|
|
||||||
|
local raw="/tmp/hako_stageb_binop_raw_$$.txt"
|
||||||
|
NYASH_PARSER_ALLOW_SEMICOLON=1 \
|
||||||
|
NYASH_SYNTAX_SUGAR_LEVEL=full \
|
||||||
|
NYASH_ENABLE_ARRAY_LITERAL=1 \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
|
HAKO_PARSER_STAGE3=1 NYASH_PARSER_STAGE3=1 \
|
||||||
|
NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 NYASH_PHI_VERIFY=0 \
|
||||||
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
||||||
|
"$ROOT/target/release/nyash" --backend vm \
|
||||||
|
"$ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
||||||
|
awk '/"version":0/ && /"kind":"Program"/ {print; exit}' "$raw" > "$json_out"
|
||||||
|
rm -f "$raw"
|
||||||
|
|
||||||
|
local rc=$?
|
||||||
|
rm -f "$hako_tmp"
|
||||||
|
if [ $rc -ne 0 ] || [ ! -f "$json_out" ]; then
|
||||||
|
warn "Stage‑B compilation failed (rc=$rc)"
|
||||||
|
rm -f "$json_out"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "$json_out"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
run_mir_via_gate_c() {
|
||||||
|
local json_path="$1"
|
||||||
|
if [ ! -f "$json_path" ]; then warn "JSON file not found: $json_path"; return 1; fi
|
||||||
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
|
||||||
|
out="$("$ROOT/target/release/nyash" --json-file "$json_path" 2>&1)"
|
||||||
|
printf '%s\n' "$out" | awk '/^(✅|ResultType|Result:)/{next} NF{last=$0} END{ if(last) print last }'
|
||||||
|
local rc=$?
|
||||||
|
rm -f "$json_path"
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|
||||||
|
run_hako() {
|
||||||
|
local code="$1"
|
||||||
|
local json_path
|
||||||
|
json_path=$(hako_compile_to_mir_stageb "$code") || return 1
|
||||||
|
run_mir_via_gate_c "$json_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_exact() {
|
||||||
|
local expect="$1"; shift
|
||||||
|
local got="$1"; shift
|
||||||
|
local name="$1"; shift
|
||||||
|
if [ "$got" = "$expect" ]; then pass "$name"; return 0; fi
|
||||||
|
printf "Expected: %s\nActual: %s\n" "$expect" "$got" >&2
|
||||||
|
fail "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_hako
|
||||||
|
|
||||||
|
info "Stage‑B binop: 1+2"
|
||||||
|
out=$(run_hako 'box Main { static method main() { print(1+2); } }')
|
||||||
|
check_exact "3" "$out" "stageb_binop_add" || exit 1
|
||||||
|
|
||||||
|
info "Stage‑B binop precedence: 1+2*3"
|
||||||
|
out=$(run_hako 'box Main { static method main() { print(1+2*3); } }')
|
||||||
|
check_exact "7" "$out" "stageb_binop_prec" || exit 1
|
||||||
|
|
||||||
|
exit 0
|
||||||
90
tools/smokes/v2/profiles/quick/core/selfhost_stageb_if_vm.sh
Normal file
90
tools/smokes/v2/profiles/quick/core/selfhost_stageb_if_vm.sh
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# selfhost_stageb_if_vm.sh — Hako Stage‑B pipeline if-statement canary (opt‑in)
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then
|
||||||
|
ROOT="$ROOT_GIT"
|
||||||
|
else
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
|
||||||
|
fi
|
||||||
|
HAKO_BIN_DEFAULT="$ROOT/tools/bin/hako"
|
||||||
|
HAKO_BIN="${HAKO_BIN:-$HAKO_BIN_DEFAULT}"
|
||||||
|
|
||||||
|
warn() { echo -e "[WARN] $*" >&2; }
|
||||||
|
info() { echo -e "[INFO] $*" >&2; }
|
||||||
|
fail() { echo -e "[FAIL] $*" >&2; return 1; }
|
||||||
|
pass() { echo -e "[PASS] $*" >&2; }
|
||||||
|
|
||||||
|
require_hako() {
|
||||||
|
if [ "${SMOKES_ENABLE_STAGEB:-0}" != "1" ]; then
|
||||||
|
warn "SMOKES_ENABLE_STAGEB!=1; skipping Stage‑B canaries"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ ! -x "$HAKO_BIN" ]; then
|
||||||
|
warn "Hako binary not found: $HAKO_BIN (set HAKO_BIN to override)"
|
||||||
|
warn "Skipping Stage‑B if canaries"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
hako_compile_to_mir_stageb() {
|
||||||
|
local code="$1"
|
||||||
|
local hako_tmp="/tmp/hako_stageb_if_$$.hako"
|
||||||
|
local json_out="/tmp/hako_stageb_if_$$.mir.json"
|
||||||
|
printf "%s\n" "$code" > "$hako_tmp"
|
||||||
|
|
||||||
|
local raw="/tmp/hako_stageb_if_raw_$$.txt"
|
||||||
|
NYASH_PARSER_ALLOW_SEMICOLON=1 NYASH_SYNTAX_SUGAR_LEVEL=full NYASH_ENABLE_ARRAY_LITERAL=1 \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
|
HAKO_PARSER_STAGE3=1 NYASH_PARSER_STAGE3=1 \
|
||||||
|
NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 NYASH_PHI_VERIFY=0 \
|
||||||
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
||||||
|
"$ROOT/target/release/nyash" --backend vm \
|
||||||
|
"$ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
||||||
|
awk '/"version":0/ && /"kind":"Program"/ {print; exit}' "$raw" > "$json_out"
|
||||||
|
rm -f "$raw" "$hako_tmp"
|
||||||
|
|
||||||
|
if [ ! -f "$json_out" ]; then
|
||||||
|
warn "Stage‑B compilation failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "$json_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_mir_via_gate_c() {
|
||||||
|
local json_path="$1"
|
||||||
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
|
||||||
|
out="$("$ROOT/target/release/nyash" --json-file "$json_path" 2>&1)"
|
||||||
|
printf '%s\n' "$out" | awk '/^(✅|ResultType|Result:)/{next} NF{last=$0} END{ if(last) print last }'
|
||||||
|
rm -f "$json_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_hako() {
|
||||||
|
local code="$1"
|
||||||
|
local json_path
|
||||||
|
json_path=$(hako_compile_to_mir_stageb "$code") || return 1
|
||||||
|
run_mir_via_gate_c "$json_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_exact() {
|
||||||
|
local expect="$1"; shift
|
||||||
|
local got="$1"; shift
|
||||||
|
local name="$1"; shift
|
||||||
|
if [ "$got" = "$expect" ]; then pass "$name"; return 0; fi
|
||||||
|
printf "Expected: %s\nActual: %s\n" "$expect" "$got" >&2
|
||||||
|
fail "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_hako
|
||||||
|
|
||||||
|
info "Stage‑B if: true branch"
|
||||||
|
out=$(run_hako 'box Main { static method main() { if(5>4){ print(1); } } }')
|
||||||
|
check_exact "1" "$out" "stageb_if_true" || exit 1
|
||||||
|
|
||||||
|
info "Stage‑B if: false branch"
|
||||||
|
out=$(run_hako 'box Main { static method main() { if(4>5){ print(1); } } }')
|
||||||
|
check_exact "" "$out" "stageb_if_false" || exit 1
|
||||||
|
|
||||||
|
exit 0
|
||||||
108
tools/smokes/v2/profiles/quick/core/selfhost_stageb_index_vm.sh
Normal file
108
tools/smokes/v2/profiles/quick/core/selfhost_stageb_index_vm.sh
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# selfhost_stageb_index_vm.sh — Hako Stage‑B pipeline index operator canary (opt‑in)
|
||||||
|
|
||||||
|
set -uo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
if ROOT_GIT=$(git -C "$SCRIPT_DIR" rev-parse --show-toplevel 2>/dev/null); then
|
||||||
|
ROOT="$ROOT_GIT"
|
||||||
|
else
|
||||||
|
ROOT="$(cd "$SCRIPT_DIR/../../../../.." && pwd)"
|
||||||
|
fi
|
||||||
|
HAKO_BIN_DEFAULT="$ROOT/tools/bin/hako"
|
||||||
|
HAKO_BIN="${HAKO_BIN:-$HAKO_BIN_DEFAULT}"
|
||||||
|
|
||||||
|
warn() { echo -e "[WARN] $*" >&2; }
|
||||||
|
info() { echo -e "[INFO] $*" >&2; }
|
||||||
|
fail() { echo -e "[FAIL] $*" >&2; return 1; }
|
||||||
|
pass() { echo -e "[PASS] $*" >&2; }
|
||||||
|
|
||||||
|
require_hako() {
|
||||||
|
if [ "${SMOKES_ENABLE_STAGEB:-0}" != "1" ]; then
|
||||||
|
warn "SMOKES_ENABLE_STAGEB!=1; skipping Stage‑B canaries"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
if [ ! -x "$HAKO_BIN" ]; then
|
||||||
|
warn "Hako binary not found: $HAKO_BIN (set HAKO_BIN to override)"
|
||||||
|
warn "Skipping Stage‑B index canaries"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
hako_compile_to_mir_stageb() {
|
||||||
|
local code="$1"
|
||||||
|
local hako_tmp="/tmp/hako_stageb_idx_$$.hako"
|
||||||
|
local json_out="/tmp/hako_stageb_idx_$$.mir.json"
|
||||||
|
printf "%s\n" "$code" > "$hako_tmp"
|
||||||
|
|
||||||
|
local raw="/tmp/hako_stageb_idx_raw_$$.txt"
|
||||||
|
NYASH_PARSER_ALLOW_SEMICOLON=1 NYASH_SYNTAX_SUGAR_LEVEL=full NYASH_ENABLE_ARRAY_LITERAL=1 \
|
||||||
|
HAKO_ALLOW_USING_FILE=1 NYASH_ALLOW_USING_FILE=1 \
|
||||||
|
HAKO_PARSER_STAGE3=1 NYASH_PARSER_STAGE3=1 \
|
||||||
|
NYASH_VARMAP_GUARD_STRICT=0 NYASH_BLOCK_SCHEDULE_VERIFY=0 NYASH_PHI_VERIFY=0 \
|
||||||
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 \
|
||||||
|
"$ROOT/target/release/nyash" --backend vm \
|
||||||
|
"$ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- --source "$(cat "$hako_tmp")" > "$raw" 2>&1
|
||||||
|
awk '/"version":0/ && /"kind":"Program"/ {print; exit}' "$raw" > "$json_out"
|
||||||
|
rm -f "$raw" "$hako_tmp"
|
||||||
|
|
||||||
|
if [ ! -f "$json_out" ]; then
|
||||||
|
warn "Stage‑B compilation failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
echo "$json_out"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_mir_via_gate_c() {
|
||||||
|
local json_path="$1"
|
||||||
|
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
|
||||||
|
out="$("$ROOT/target/release/nyash" --json-file "$json_path" 2>&1)"
|
||||||
|
printf '%s\n' "$out" | awk '/^(✅|ResultType|Result:)/{next} NF{last=$0} END{ if(last) print last }'
|
||||||
|
rm -f "$json_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
run_hako() {
|
||||||
|
local code="$1"
|
||||||
|
local json_path
|
||||||
|
json_path=$(hako_compile_to_mir_stageb "$code") || return 1
|
||||||
|
run_mir_via_gate_c "$json_path"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_exact() {
|
||||||
|
local expect="$1"; shift
|
||||||
|
local got="$1"; shift
|
||||||
|
local name="$1"; shift
|
||||||
|
if [ "$got" = "$expect" ]; then pass "$name"; return 0; fi
|
||||||
|
printf "Expected: %s\nActual: %s\n" "$expect" "$got" >&2
|
||||||
|
fail "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
require_hako
|
||||||
|
|
||||||
|
info "Stage‑B index: array read"
|
||||||
|
out=$(run_hako 'box Main { static method main() { local a=[1,2,3]; print(a[0]); } }')
|
||||||
|
check_exact "1" "$out" "stageb_index_array_read" || exit 1
|
||||||
|
|
||||||
|
info "Stage‑B index: array write"
|
||||||
|
out=$(run_hako 'box Main { static method main() { local a=[1,2]; a[1]=9; print(a[1]); } }')
|
||||||
|
check_exact "9" "$out" "stageb_index_array_write" || exit 1
|
||||||
|
|
||||||
|
info "Stage‑B index: map rw"
|
||||||
|
out=$(run_hako 'box Main { static method main() { local m={"a":1}; m["b"]=7; print(m["b"]); } }')
|
||||||
|
check_exact "7" "$out" "stageb_index_map_rw" || exit 1
|
||||||
|
|
||||||
|
info "Stage‑B index: nested array"
|
||||||
|
out=$(run_hako 'box Main { static method main() { local a=[[1,2],[3,4]]; print(a[1][0]); } }')
|
||||||
|
check_exact "3" "$out" "stageb_index_nested_array" || exit 1
|
||||||
|
|
||||||
|
info "Stage‑B index: missing map key diagnostic"
|
||||||
|
if run_hako 'box Main { static method main() { local m={"a":1}; print(m["c"]); } }' >/tmp/hako_stageb_idx_diag.txt 2>&1; then
|
||||||
|
warn "expected failure but command succeeded"
|
||||||
|
cat /tmp/hako_stageb_idx_diag.txt >&2
|
||||||
|
fail "stageb_index_map_missing_diag" || exit 1
|
||||||
|
else
|
||||||
|
pass "stageb_index_map_missing_diag"
|
||||||
|
fi
|
||||||
|
rm -f /tmp/hako_stageb_idx_diag.txt
|
||||||
|
|
||||||
|
exit 0
|
||||||
Reference in New Issue
Block a user