Files
hakorune/tools/selfhost/selfhost_build.sh

147 lines
4.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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
KEEP_TMP=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;;
--keep-tmp) KEEP_TMP=1; shift;;
--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 NYASH_FEATURES="${NYASH_FEATURES:-stage3}"
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 (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"
# Convert Program(JSON v0) → MIR(JSON) via runner
MIR_TMP="${MIR_OUT:-/tmp/hako_stageb_mir_$$.json}"
echo "[selfhost] converting Program(JSON v0) → MIR(JSON) → EXE" >&2
"$BIN" --json-file "$tmp_json" --program-json-to-mir "$MIR_TMP"
# Build EXE via ny-llvmc
"$NYLL" --in "$MIR_TMP" --emit exe --nyrt "$NYRT_DIR" --out "$EXE_OUT"
# Cleanup
if [ "$KEEP_TMP" != "1" ]; then
if [ -z "$JSON_OUT" ]; then rm -f "$tmp_json" 2>/dev/null || true; fi
if [ -z "$MIR_OUT" ]; then rm -f "$MIR_TMP" 2>/dev/null || true; fi
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 [ "$KEEP_TMP" != "1" ] && [ -z "$JSON_OUT" ]; then rm -f "$tmp_json" 2>/dev/null || true; fi
exit $rc
else
# Emit-only
echo "$tmp_json"
fi