Files
hakorune/tools/selfhost/selfhost_build.sh

137 lines
4.7 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# selfhost_build.sh — Hybrid selfhost build (StageB → Program(JSON v0) → optional run via CoreDirect)
#
# Goals (80/20):
# - Take a Hako source (.hako), compile with Hakorune StageB to Program(JSON v0).
# - Optionally run via GateC/Core Direct (inproc) to verify exit code.
# - (Future) Optionally convert to MIR and build an executable via ny-llvmc.
#
# Usage:
# tools/selfhost/selfhost_build.sh --in source.hako [--json out.json] [--run]
# Env:
# NYASH_BIN: path to hakorune/nyash binary (auto-detected if omitted)
# NYASH_ROOT: repo root (auto-detected)
#
set -euo pipefail
ROOT="${NYASH_ROOT:-$(cd "$(dirname "$0")/../.." && pwd)}"
BIN="${NYASH_BIN:-}"
if [ -z "${BIN}" ]; then
if [ -x "$ROOT/target/release/hakorune" ]; then BIN="$ROOT/target/release/hakorune";
elif [ -x "$ROOT/target/release/nyash" ]; then BIN="$ROOT/target/release/nyash";
else echo "[selfhost] error: NYASH_BIN not set and no binary found under target/release" >&2; exit 2; fi
fi
IN=""
JSON_OUT=""
MIR_OUT=""
EXE_OUT=""
DO_RUN=0
while [ $# -gt 0 ]; do
case "$1" in
--in) IN="$2"; shift 2;;
--json) JSON_OUT="$2"; shift 2;;
--run) DO_RUN=1; shift;;
--mir) MIR_OUT="$2"; shift 2;;
--exe) EXE_OUT="$2"; shift 2;;
*) echo "[selfhost] unknown arg: $1" >&2; exit 2;;
esac
done
if [ -z "$IN" ]; then echo "[selfhost] --in <file.hako> is required" >&2; exit 2; fi
if [ ! -f "$IN" ]; then echo "[selfhost] input not found: $IN" >&2; exit 2; fi
tmp_json="${JSON_OUT:-/tmp/hako_stageb_$$.json}"
# Emit Program(JSON v0; prefer BuildBox for emit-only when HAKO_USE_BUILDBOX=1)
RAW="/tmp/hako_stageb_raw_$$.txt"
SRC_CONTENT="$(cat "$IN")"
if [ "${HAKO_USE_BUILDBOX:-0}" = "1" ] && [ "$DO_RUN" = "0" ] && [ -z "$EXE_OUT" ]; then
WRAP="/tmp/hako_buildbox_wrap_$$.hako"
cat > "$WRAP" <<'HAKO'
include "lang/src/compiler/build/build_box.hako"
static box Main { method main(args) {
local src = env.get("HAKO_SRC");
local j = BuildBox.emit_program_json_v0(src, null);
print(j);
return 0;
} }
HAKO
(
export HAKO_SRC="$SRC_CONTENT"
export NYASH_QUIET=0 HAKO_QUIET=0 NYASH_CLI_VERBOSE=0
cd "$ROOT" && "$BIN" --backend vm "$WRAP"
) > "$RAW" 2>&1 || true
rm -f "$WRAP" 2>/dev/null || true
else
(
export NYASH_PARSER_ALLOW_SEMICOLON=1
export NYASH_ALLOW_USING_FILE=0
export HAKO_ALLOW_USING_FILE=0
export NYASH_USING_AST=1
export HAKO_PARSER_STAGE3=1
export NYASH_PARSER_STAGE3=1
export NYASH_VARMAP_GUARD_STRICT=0
export NYASH_BLOCK_SCHEDULE_VERIFY=0
export NYASH_QUIET=0 HAKO_QUIET=0 NYASH_CLI_VERBOSE=0
cd "$ROOT" && \
"$BIN" --backend vm \
"$ROOT/lang/src/compiler/entry/compiler_stageb.hako" -- \
--source "$SRC_CONTENT"
) > "$RAW" 2>&1 || true
fi
if ! awk '(/"version":0/ && /"kind":"Program"/){print;found=1;exit} END{exit(found?0:1)}' "$RAW" > "$tmp_json"; then
echo "[selfhost] StageB emit failed" >&2
tail -n 120 "$RAW" >&2 || true
rm -f "$RAW" 2>/dev/null || true
exit 1
fi
rm -f "$RAW" 2>/dev/null || true
if [ -n "$JSON_OUT" ]; then
echo "[selfhost] JSON v0 written: $tmp_json" >&2
fi
# Optional: emit MIR(JSON) from source (runner compiles .hako directly; StageB JSON is for reference)
if [ -n "$MIR_OUT" ]; then
echo "[selfhost] emitting MIR JSON → $MIR_OUT" >&2
"$BIN" --backend mir --emit-mir-json "$MIR_OUT" "$IN" >/dev/null
fi
# Optional: build native EXE via ny-llvmc harness (fallback path; parses original source)
if [ -n "$EXE_OUT" ]; then
# Requirements: ny-llvmc present and harness envs
NYLL="${NYASH_NY_LLVM_COMPILER:-$ROOT/target/release/ny-llvmc}"
if [ ! -x "$NYLL" ] && [ ! -f "$NYLL" ]; then
echo "[selfhost] ny-llvmc not found: $NYLL (skip EXE). Set NYASH_NY_LLVM_COMPILER or build ny-llvmc" >&2
exit 2
fi
NYRT_DIR="${NYASH_EMIT_EXE_NYRT:-$ROOT/target/release}"
export NYASH_LLVM_USE_HARNESS=1
export NYASH_NY_LLVM_COMPILER="$NYLL"
export NYASH_EMIT_EXE_NYRT="$NYRT_DIR"
echo "[selfhost] emitting EXE via ny-llvmc → $EXE_OUT" >&2
# Note: This path compiles the original Hako source via LLVM backend. StageB JSON is emitted above for reference.
"$BIN" --backend llvm --emit-exe "$EXE_OUT" "$IN"
# Done
if [ -z "$JSON_OUT" ]; then rm -f "$tmp_json" 2>/dev/null || true; fi
exit 0
fi
if [ "$DO_RUN" = "1" ]; then
# Run via CoreDirect (inproc), quiet
set +e
NYASH_GATE_C_CORE=1 HAKO_GATE_C_CORE=1 HAKO_CORE_DIRECT=1 HAKO_CORE_DIRECT_INPROC=1 \
NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
"$BIN" --json-file "$tmp_json" >/dev/null 2>&1
rc=$?
set -e
if [ -z "$JSON_OUT" ]; then rm -f "$tmp_json" 2>/dev/null || true; fi
exit $rc
else
# Emit-only
echo "$tmp_json"
fi