restore(lang): full lang tree from ff3ef452 (306 files) — compiler, vm, shared, runner, c-abi, etc.\n\n- Restores lang/ directory (files≈306, dirs≈64) as per historical branch with selfhost sources\n- Keeps our recent parser index changes in compiler/* (merged clean by checkout)\n- Unblocks selfhost development and documentation references

This commit is contained in:
nyash-codex
2025-10-31 20:45:46 +09:00
parent dbc285f2b1
commit e5f697eb22
244 changed files with 16915 additions and 47 deletions

View File

@ -0,0 +1,252 @@
// LLVMAotFacadeBox — IR 文字列(JSON v0)をファイルに書き出し、AotBox で compile/link する薄い委譲層
using "lang/src/llvm_ir/boxes/builder.hako" as LLVMBuilderBox
// Note: Convenience wrappers build JSON inline to avoid nested resolver issues
static box LLVMAotFacadeBox {
_truthy(s){ if !s { return 0 } local l = s.toLowerCase(); return (l=="1"||l=="true"||l=="on"||l=="yes") }
_route(){
// Decide route by env (read-only). Default = lib (via AotBox)
// HAKO_AOT_USE_FFI=1 → ffi, HAKO_AOT_USE_PLUGIN=1 → plugin, else lib
local ffi = call("env.local.get/1", "HAKO_AOT_USE_FFI"); if LLVMAotFacadeBox._truthy(ffi) { return "ffi" }
local plug = call("env.local.get/1", "HAKO_AOT_USE_PLUGIN"); if LLVMAotFacadeBox._truthy(plug) { return "plugin" }
return "lib"
}
_q(s){ return "\"" + s + "\"" }
_i(n){ return "" + n }
_inst_const(dst, val){
return "{\"op\":\"const\",\"dst\":" + me._i(dst) + ",\"value\":{\"type\":\"i64\",\"value\":" + me._i(val) + "}}"
}
_inst_ret(val){ return "{\"op\":\"ret\",\"value\":" + me._i(val) + "}" }
_map_binop_kind(opk){
if opk == "+" { return "Add" }
if opk == "-" { return "Sub" }
if opk == "*" { return "Mul" }
if opk == "/" { return "Div" }
if opk == "%" { return "Mod" }
return opk
}
_inst_binop(kind, lhs, rhs, dst){
return "{\"op\":\"binop\",\"op_kind\":" + me._q(kind) + ",\"lhs\":" + me._i(lhs) + ",\"rhs\":" + me._i(rhs) + ",\"dst\":" + me._i(dst) + "}"
}
_wrap_fn(body_json){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + body_json + "] } ] } ] }"
}
compile_link_json(json_text, obj_out, exe_out, flags){
// FailFast: validate args
if !json_text || !obj_out || !exe_out { return -1 }
// Write JSON to a temp file next to obj_out
local fb = new FileBox()
local json_path = obj_out + ".json"
// Ensure file is created and truncated
fb.open(json_path, "w")
fb.write(json_text)
fb.close()
// Delegate to AotBox (route is read-only; actual path is handled by CABI/env)
local _r = LLVMAotFacadeBox._route()
local a = new AotBox()
local rc1 = a.compile(json_path, obj_out)
if rc1 != 0 { return rc1 }
local rc2 = a.link(obj_out, exe_out, flags ? flags : "")
return rc2
}
// Convenience wrappers (delegate to LLVMBuilderBox when gate=on; else inline JSON)
compile_link_ret0(obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
if on && (LLVMAotFacadeBox._truthy(on)) {
local json = LLVMBuilderBox.program_ret0()
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// Inline JSON fallback to avoid nested using resolver dependencies
local body = me._inst_const(1, 0) + "," + me._inst_ret(1)
local json = me._wrap_fn(body)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
compile_link_ret_i64(v, obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
if on && (LLVMAotFacadeBox._truthy(on)) {
local json = LLVMBuilderBox.program_ret_i64(v)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
local body = me._inst_const(1, v) + "," + me._inst_ret(1)
local json = me._wrap_fn(body)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
compile_link_binop_i64(lhs, rhs, opk, obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
if on && (LLVMAotFacadeBox._truthy(on)) {
local json = LLVMBuilderBox.program_binop_i64(lhs, rhs, opk)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// Inline JSON fallback
local kind = me._map_binop_kind(opk)
local body = me._inst_const(1, lhs) + "," + me._inst_const(2, rhs) + "," + me._inst_binop(kind, 1, 2, 3) + "," + me._inst_ret(3)
local json = me._wrap_fn(body)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// v1(compare minimal) — emit a compare (Eq) but return 0 to keep exe exit code stable
// This exercises the compare path in AOT while ensuring the process exit is 0.
compile_link_compare_eq_i64(lhs, rhs, obj_out, exe_out, flags){
// Build: const 1=lhs, const 2=rhs, compare(dst=3, operation==, lhs=1, rhs=2),
// then const 4=0, binop(dst=5, op="*", lhs=3, rhs=4), ret 5
local inst_c1 = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + me._i(lhs) + "}}"
local inst_c2 = "{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + me._i(rhs) + "}}"
local inst_cmp = "{\"op\":\"compare\",\"dst\":3,\"operation\":\"==\",\"lhs\":1,\"rhs\":2}"
local inst_c0 = "{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}"
local inst_mul = "{\"op\":\"binop\",\"dst\":5,\"operation\":\"*\",\"lhs\":3,\"rhs\":4}"
local inst_ret = "{\"op\":\"ret\",\"value\":5}"
local body = inst_c1 + "," + inst_c2 + "," + inst_cmp + "," + inst_c0 + "," + inst_mul + "," + inst_ret
local json = me._wrap_fn(body)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// v1(compare+branch minimal) — generate multi-block JSON with conditional branch; both paths return 0
compile_link_compare_branch_i64(lhs, rhs, opk, obj_out, exe_out, flags){
local op = opk ? opk : ">"
// blocks: 0=cmp+branch, 1=then(ret 0), 2=else(ret 0)
local b0 = "{\"id\":0,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + me._i(lhs) + "}}," +
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + me._i(rhs) + "}}," +
"{\"op\":\"compare\",\"dst\":3,\"operation\":" + me._q(op) + ",\"lhs\":1,\"rhs\":2}," +
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}] }"
local b1 = "{\"id\":1,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":4}] }"
local b2 = "{\"id\":2,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":5}] }"
local json = "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "] } ] }"
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// v1(phi-if minimal) — diamond shape with PHI at merge; returns 0 to keep exit code stable
compile_link_phi_if_i64(val_then, val_else, obj_out, exe_out, flags){
// 0: jump->1 always via const(true) compare; 1: const then; 2: const else; 3: phi merge; ret 0
local b0 = "{\"id\":0,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":1}}," +
"{\"op\":\"compare\",\"dst\":2,\"operation\":\"==\",\"lhs\":1,\"rhs\":1}," +
"{\"op\":\"branch\",\"cond\":2,\"then\":1,\"else\":2}] }"
local b1 = "{\"id\":1,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":" + me._i(val_then) + "}}," +
"{\"op\":\"jump\",\"target\":3}] }"
local b2 = "{\"id\":2,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + me._i(val_else) + "}}," +
"{\"op\":\"jump\",\"target\":3}] }"
local b3 = "{\"id\":3,\"instructions\":[" +
"{\"op\":\"phi\",\"dst\":5,\"type\":\"i64\",\"incoming\":[{\"block\":1,\"value\":3},{\"block\":2,\"value\":4}]}," +
"{\"op\":\"const\",\"dst\":6,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":6}] }"
local json = "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "," + b3 + "] } ] }"
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// extern call convenience wrappers (console.*) — build via Builder and link
compile_link_call_console_log(obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_console_log_ret0() }
else {
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"hello\"}}," +
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.log\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
compile_link_call_console_warn(obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_console_warn_ret0() }
else {
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"warn-message\"}}," +
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.warn\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
compile_link_call_console_error(obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_console_error_ret0() }
else {
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"error-message\"}}," +
"{\"op\":\"mir_call\",\"dst\":\"null\",\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.error\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// Negative helper for smoke: invalid extern name to observe FailFast
compile_link_call_console_invalid(obj_out, exe_out, flags){
// Construct minimal JSON inline to avoid depending on Builder for invalid case
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"hello\"}}," +
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.console.nope\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
local json = me._wrap_fn(body)
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// time.now_ms — build via Builder when gate, else inline JSON; ret 0
compile_link_call_time_now_ms(obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_time_now_ms_ret0() }
else {
local body = "{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.time.now_ms\"},\"args\":[],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// JSON.stringify(any) — via nyash.json.stringify_h; ret 0
compile_link_call_json_stringify(obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_json_stringify_ret0() }
else {
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":42}}," +
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"nyash.json.stringify_h\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// env.mem.alloc/free wrapper — ret 0
compile_link_call_mem_alloc_free(sz, obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_mem_alloc_free_ret0(sz) }
else {
local s = sz ? sz : 16
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + me._i(s) + "}}," +
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.mem.alloc\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"mir_call\",\"dst\":3,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.mem.free\"},\"args\":[2],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":4}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
// env.local.get wrapper — ret 0 (value ignored)
compile_link_call_env_local_get(key, obj_out, exe_out, flags){
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
local json
if on && (LLVMAotFacadeBox._truthy(on)) { json = LLVMBuilderBox.program_call_env_local_get_ret0(key) }
else {
local k = key ? key : "SMOKES_ENV_LOCAL_GET"
local body = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"string\",\"value\":\"" + k + "\"}}," +
"{\"op\":\"mir_call\",\"dst\":2,\"mir_call\":{\"callee\":{\"type\":\"Extern\",\"name\":\"env.local.get\"},\"args\":[1],\"effects\":[]}}," +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":3}"
json = me._wrap_fn(body)
}
return LLVMAotFacadeBox.compile_link_json(json, obj_out, exe_out, flags)
}
}

View File

@ -0,0 +1,162 @@
// aot_prep.hako — AotPrepBox (pre-MIR normalizer/optimizer; skeleton)
// 入出力(最小仕様)
// - AotPrepBox.prep/1(json_in_path: String) -> String (json_out_path)
// 責務
// - JSON(MIR v0) の軽量正規化(キー順/冗長キー削除)と安全な const/binop(+,-,*)/ret の単一ブロック畳み込み
// - 既定ではパススルーRust 側 maybe_prepare_mir_json が実体)。段階的にこちらへ移管する
using "lang/src/shared/mir/mir_io_box.hako" as MirIoBox
using "lang/src/shared/common/string_helpers.hako" as StringHelpers
static box AotPrepBox {
// AotPrepBox.prep
// 入力: JSONファイルパスMIR v0
// 出力: 正規化後のJSONを書き出したパス<in>.prep.json。失敗時は入力パスを返すFailFastはRust側が継続
prep(json_in_path) {
if !json_in_path { return json_in_path }
// Read input
local fb = new FileBox()
fb.open(json_in_path, "r")
local src = fb.read()
fb.close()
if !src { return json_in_path }
// Phase1: 文字列正規化(安定化)
// いまは canonicalize は恒等将来はHostBridgeでキー順安定化
local canon = MirIoBox.normalize(src)
// Phase2: 安全な単一ブロック const/binop(+,-,*)/ret の畳み込み(最小実装)
// 備考: まずは main 関数を優先対象とし、成立時のみ最小 JSON に置換(今後は inplace 置換へ段階移行)。
local out = AotPrepBox._try_fold_const_binop_ret(canon)
if !out { out = canon }
// Decide output path
local out_path = json_in_path + ".prep.json"
fb.open(out_path, "w")
fb.write(out)
fb.close()
return out_path
}
// 内部: 最小の安全畳み込みJSON文字列ベース
_try_fold_const_binop_ret(json) {
if !json { return null }
// Helper: find the [ ... ] span of the first block's instructions for the function near `start_from`.
local find_instr_span_from = fun(s, start_from) {
local key = "\"instructions\":["
local pos = s.indexOf(key, start_from)
if pos < 0 { return [-1, -1] }
local ls = s.indexOf("[", pos)
if ls < 0 { return [-1, -1] }
local depth = 0
local i = ls
local L = s.size()
local rs = -1
loop(i < L) {
local ch = s.substring(i, i+1)
if ch == "[" { depth = depth + 1 }
if ch == "]" { depth = depth - 1; if depth == 0 { rs = i; break } }
i = i + 1
}
return [ls, rs]
}
// Helper: attempt to fold within a given [arr_start, arr_end] span; return replaced JSON on success
local try_fold_in_span = fun(s, arr_start, arr_end) {
if arr_start < 0 || arr_end < 0 { return null }
local body = s.substring(arr_start, arr_end+1)
// Need two const, a binop, and a ret in this span
local p1 = body.indexOf("\"op\":\"const\"")
local p2 = body.indexOf("\"op\":\"const\"", (p1>=0 ? (p1+1) : 0))
local pb = body.indexOf("\"op\":\"binop\"", (p2>=0 ? (p2+1) : 0))
local pr = body.indexOf("\"op\":\"ret\"", (pb>=0 ? (pb+1) : 0))
if p1 < 0 || p2 < 0 || pb < 0 || pr < 0 { return null }
// parse helpers within body
local parse_dst = fun(ss, pos) {
local k = "\"dst\":"
local i = ss.indexOf(k, pos)
if i < 0 { return -1 }
i = i + k.size()
local digs = StringHelpers.read_digits(ss, i)
if digs == "" { return -1 }
return StringHelpers.to_i64(digs)
}
local parse_val = fun(ss, pos) {
local k = "\"value\":{\"type\":\"i64\",\"value\":"
local i = ss.indexOf(k, pos)
if i < 0 { return null }
i = i + k.size()
local digs = StringHelpers.read_digits(ss, i)
if digs == "" { return null }
return StringHelpers.to_i64(digs)
}
local d1 = parse_dst(body, p1)
local a = parse_val(body, p1)
local d2 = parse_dst(body, p2)
local b = parse_val(body, p2)
if d1 < 0 || d2 < 0 || a == null || b == null { return null }
local find_num = fun(ss, key, pos) {
local k = key
local i = ss.indexOf(k, pos)
if i < 0 { return -1 }
i = i + k.size()
local digs = StringHelpers.read_digits(ss, i)
if digs == "" { return -1 }
return StringHelpers.to_i64(digs)
}
local find_op = fun(ss, pos) {
local k = "\"operation\":\""
local i = ss.indexOf(k, pos)
if i < 0 { return "" }
i = i + k.size()
local j = ss.indexOf("\"", i)
if j < 0 { return "" }
return ss.substring(i, j)
}
local lhs = find_num(body, "\"lhs\":", pb)
local rhs = find_num(body, "\"rhs\":", pb)
local bop = find_op(body, pb)
local d3 = find_num(body, "\"dst\":", pb)
if lhs != d1 || rhs != d2 || d3 < 0 { return null }
local rv = find_num(body, "\"value\":", pr)
if rv != d3 { return null }
// binop allowed: +,-,* only
local res = 0
if bop == "+" { res = a + b } else { if bop == "-" { res = a - b } else { if bop == "*" { res = a * b } else { return null } } }
// build new array and replace in-place
local new_insts = "[" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":" + StringHelpers.int_to_str(d1) + ",\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + StringHelpers.int_to_str(res) + "}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":" + StringHelpers.int_to_str(d1) + "}]"
local head = s.substring(0, arr_start)
local tail = s.substring(arr_end + 1, s.size())
return head + new_insts + tail
}
// Pass 1: prefer name:"main"
local fn_pos = json.indexOf("\"name\":\"main\"")
if fn_pos >= 0 {
local span = find_instr_span_from(json, fn_pos)
local ls = span[0]; local rs = span[1]
local repl = try_fold_in_span(json, ls, rs)
if repl { return repl }
}
// Pass 2: scan functions sequentially and attempt per function
local froot = json.indexOf("\"functions\":[")
if froot < 0 { return null }
local scan = froot
local tries = 0
loop(tries < 16) {
local np = json.indexOf("\"name\":\"", scan+1)
if np < 0 { break }
local span2 = find_instr_span_from(json, np)
local ls2 = span2[0]; local rs2 = span2[1]
if ls2 >= 0 && rs2 >= 0 {
local repl2 = try_fold_in_span(json, ls2, rs2)
if repl2 { return repl2 }
scan = rs2 + 1
} else {
scan = np + 8
}
tries = tries + 1
}
return null
}
}

View File

@ -0,0 +1,128 @@
// LLVMBuilderBox — 命令構築v0: const/binop/ret の骨格)
static box LLVMBuilderBox {
program_ret0(){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":0}},{\"op\":\"ret\",\"value\":1}] } ] } ] }"
}
program_binop_i64(lhs, rhs, opk){
local op = opk ? opk : "+"
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs + "}}," +
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs + "}}," +
"{\"op\":\"binop\",\"dst\":3,\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2}," +
"{\"op\":\"ret\",\"value\":3}] } ] } ] }"
}
program_ret_i64(v){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + v + "}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":1}] } ] } ] }"
}
const_i64(fn_handle, value){
local strict = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER_STRICT");
if strict && strict != "0" && strict != "false" { print("UNSUPPORTED: const_i64 (stub)"); return -1 }
return 0
}
binop_add(fn_handle, lhs, rhs){
local strict = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER_STRICT");
if strict && strict != "0" && strict != "false" { print("UNSUPPORTED: binop_add (stub)"); return -1 }
return 0
}
ret(fn_handle, val){
local strict = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER_STRICT");
if strict && strict != "0" && strict != "false" { print("UNSUPPORTED: ret (stub)"); return -1 }
return 0
}
// v1 programs (JSON emitters) — behavior: return JSON string for AOT facade
program_compare_branch_ret0(lhs, rhs, opk){
local op = opk ? opk : ">"
local b0 = "{\"id\":0,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + lhs + "}}," +
"{\"op\":\"const\",\"dst\":2,\"value\":{\"type\":\"i64\",\"value\":" + rhs + "}}," +
"{\"op\":\"compare\",\"dst\":3,\"operation\":\"" + op + "\",\"lhs\":1,\"rhs\":2}," +
"{\"op\":\"branch\",\"cond\":3,\"then\":1,\"else\":2}] }"
local b1 = "{\"id\":1,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":4}] }"
local b2 = "{\"id\":2,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":5,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":5}] }"
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "] } ] }"
}
program_phi_if_ret0(val_then, val_else){
local b0 = "{\"id\":0,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":1}}," +
"{\"op\":\"compare\",\"dst\":2,\"operation\":\"==\",\"lhs\":1,\"rhs\":1}," +
"{\"op\":\"branch\",\"cond\":2,\"then\":1,\"else\":2}] }"
local b1 = "{\"id\":1,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":3,\"value\":{\"type\":\"i64\",\"value\":" + val_then + "}}," +
"{\"op\":\"jump\",\"target\":3}] }"
local b2 = "{\"id\":2,\"instructions\":[" +
"{\"op\":\"const\",\"dst\":4,\"value\":{\"type\":\"i64\",\"value\":" + val_else + "}}," +
"{\"op\":\"jump\",\"target\":3}] }"
local b3 = "{\"id\":3,\"instructions\":[" +
"{\"op\":\"phi\",\"dst\":5,\"type\":\"i64\",\"incoming\":[{\"block\":1,\"value\":3},{\"block\":2,\"value\":4}]}," +
"{\"op\":\"const\",\"dst\":6,\"value\":{\"type\":\"i64\",\"value\":0}}," +
"{\"op\":\"ret\",\"value\":6}] }"
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "," + b3 + "] } ] }"
}
// v2 extern calls (console.*) — return JSON for AOT facade
program_call_console_log_ret0(){
// const s="hello"; mir_call Extern(env.console.log) s; ret 0
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"string\\\",\\\"value\\\":\\\"hello\\\"}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.console.log\\\"},\\\"args\\\":[1],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }"
}
program_call_console_warn_ret0(){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"string\\\",\\\"value\\\":\\\"warn-message\\\"}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.console.warn\\\"},\\\"args\\\":[1],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }"
}
program_call_console_error_ret0(){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"string\\\",\\\"value\\\":\\\"error-message\\\"}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.console.error\\\"},\\\"args\\\":[1],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }"
}
// env.mem.alloc/free roundtrip; return 0
program_call_mem_alloc_free_ret0(size){
local sz = size ? size : 16
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":" + sz + "}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.mem.alloc\\\"},\\\"args\\\":[1],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":3,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.mem.free\\\"},\\\"args\\\":[2],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":4,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":4}] } ] } ] }"
}
// env.local.get (value unused); return 0
program_call_env_local_get_ret0(key){
local k = key ? key : "SMOKES_ENV_LOCAL_GET"
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"string\\\",\\\"value\\\":\\\"" + k + "\\\"}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.local.get\\\"},\\\"args\\\":[1],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }"
}
// v2 extern calls (time.now_ms / JSON.stringify)
// Call env.time.now_ms() and return 0 (exe exit code stable)
program_call_time_now_ms_ret0(){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"env.time.now_ms\\\"},\\\"args\\\":[],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }"
}
// Call JSON.stringify(any) via nyash.json.stringify_h and return 0
program_call_json_stringify_ret0(){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":1,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":42}}," +
"{\\\"op\\\":\\\"mir_call\\\",\\\"dst\\\":2,\\\"mir_call\\\":{\\\"callee\\\":{\\\"type\\\":\\\"Extern\\\",\\\"name\\\":\\\"nyash.json.stringify_h\\\"},\\\"args\\\":[1],\\\"effects\\\":[]}}," +
"{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," +
"{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }"
}
}

View File

@ -0,0 +1,9 @@
// LLVMEmitBox — オブジェクト出力当面は委譲予定・MVPはFailFast stub
static box LLVMEmitBox {
write_object(mod_handle, path){
// まだスクリプト内で IR→obj を完結させない方針。委譲前提のためFailFast。
print("UNSUPPORTED: write_object (delegate to AotBox/libhako_aot)");
return -1
}
}

View File

@ -0,0 +1,10 @@
// LLVMFunctionBox — 関数定義と基本ブロック操作MVPは形のみ
static box LLVMFunctionBox {
append_block(fn_handle, name){
return 1
}
set_insert_point(fn_handle, bb_handle){
return 0
}
}

View File

@ -0,0 +1,21 @@
// LLVMModuleBox — IR 構築の起点MVPは形のみ
static box LLVMModuleBox {
new(name, triple, dl){
// Gate: optin のみ
local on = call("env.local.get/1", "HAKO_LLVM_SCRIPT_BUILDER");
if !on || on == "0" || on == "false" { return -1 }
// For MVP, just return a dummy handle (=1)
return 1
}
set_target_triple(handle, triple){
return 0
}
set_data_layout(handle, dl){
return 0
}
add_function(handle, name, ret_ty, args_array){
// Return a dummy function handle (=1)
return 1
}
}

View File

@ -0,0 +1,10 @@
// LLVMTypesBox — 代表的なプリミティブ型のクエリv0
static box LLVMTypesBox {
i1(){ return "i1" }
i8(){ return "i8" }
i32(){ return "i32" }
i64(){ return "i64" }
f64(){ return "f64" }
ptr(ty){ return ty + "*" }
}

View File

@ -0,0 +1,44 @@
// LLVMV0BuilderBox — v0: 最小 MIR(JSON v0) を直接生成する軽量ビルダ(依存レス)
// 目的: スモークでの AOT 経路確認を最小依存で実現する。
static box LLVMV0BuilderBox {
_q(s){ return "\"" + s + "\"" }
_i(n){ return "" + n }
_inst_const(dst, val){
return "{\"op\":\"const\",\"dst\":" + me._i(dst) + ",\"value\":{\"type\":\"i64\",\"value\":" + me._i(val) + "}}"
}
_inst_ret(val){ return "{\"op\":\"ret\",\"value\":" + me._i(val) + "}" }
_map_binop_kind(opk){
if opk == "+" { return "Add" }
if opk == "-" { return "Sub" }
if opk == "*" { return "Mul" }
if opk == "/" { return "Div" }
if opk == "%" { return "Mod" }
return opk
}
_inst_binop(kind, lhs, rhs, dst){
return "{\"op\":\"binop\",\"op_kind\":" + me._q(kind) + ",\"lhs\":" + me._i(lhs) + ",\"rhs\":" + me._i(rhs) + ",\"dst\":" + me._i(dst) + "}"
}
_wrap_fn(body_json){
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + body_json + "] } ] } ] }"
}
// return 0v0代表
ret0(){
local body = me._inst_const(1, 0) + "," + me._inst_ret(1)
return me._wrap_fn(body)
}
// return <v>
ret_i64(v){
local body = me._inst_const(1, v) + "," + me._inst_ret(1)
return me._wrap_fn(body)
}
// (<lhs> <op> <rhs>) → return op: +|-|*|/|%
binop_i64(lhs, rhs, opk){
local kind = me._map_binop_kind(opk)
local body = me._inst_const(1, lhs) + "," + me._inst_const(2, rhs) + "," + me._inst_binop(kind, 1, 2, 3) + "," + me._inst_ret(3)
return me._wrap_fn(body)
}
}