From 5de8d8912d06077180f636ed6a5eb631cc39eace Mon Sep 17 00:00:00 2001 From: dimgigov Date: Sun, 19 Jul 2026 23:14:40 +0300 Subject: [PATCH] ci: selfhost smoke for move_field and multi-file #line Add tools/smoke_selfhost.sh and make test-selfhost-smoke (via make selfhost) to the default make test suite, covering field-move ownership and per-file #line paths under buxc2. --- Makefile | 11 +++- docs/BuildAndTest.md | 3 +- docs/QUALITY_PLAN.md | 36 +++++++++++-- tools/smoke_selfhost.sh | 111 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 8 deletions(-) create mode 100755 tools/smoke_selfhost.sh diff --git a/Makefile b/Makefile index 04d61ff..a859870 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ BUILD_DIR := build EXAMPLES := hello fibonacci factorial structs enums methods algebraic_enums generics generics_struct generic_infer generic_infer2 extend_generic pattern_matching strings strings2 map result_option try_operator ownership ownership_checked drop_early_return lifetime_elision ctfe async concurrency os_time process json iter trait_bounds channel sync jwt stdlib_ergonomics tuples func_ptr map_remove array_iter_extra string_extra multi_closure iter_hof closure_control match_let string_interp iter_generic generic_infer_hof struct_tuple_pat match_block nested_patterns match_guards pattern_shadow move_field -.PHONY: all build dev debug test clean clean-all test-examples selfhost test-golden test-errors test-stdlib selfhost-loop lsp fmt-check docs bench test-apps test-dwarf +.PHONY: all build dev debug test clean clean-all test-examples selfhost test-golden test-errors test-stdlib selfhost-loop lsp fmt-check docs bench test-apps test-dwarf test-selfhost-smoke all: build @@ -19,7 +19,7 @@ dev: debug: dev @echo "Debug binary: buxc_debug" -test: build fmt-check test-examples test-errors test-stdlib test-registry test-dwarf test-apps +test: build fmt-check test-examples test-errors test-stdlib test-registry test-dwarf test-apps test-selfhost-smoke @echo "Running lexer tests..." $(NIM) c -r tests/lexer_test.nim @echo "Running parser tests..." @@ -234,3 +234,10 @@ test-dwarf: build @echo "=== DWARF / #line smoke (E.4) ===" @chmod +x tools/smoke_dwarf.sh @tools/smoke_dwarf.sh + +# Selfhost (buxc2): move_field ownership + multi-file #line (session 41/42) +.PHONY: test-selfhost-smoke +test-selfhost-smoke: selfhost + @echo "=== Selfhost smoke (move_field + multi-file #line) ===" + @chmod +x tools/smoke_selfhost.sh + @tools/smoke_selfhost.sh diff --git a/docs/BuildAndTest.md b/docs/BuildAndTest.md index ad7108e..ddc369e 100644 --- a/docs/BuildAndTest.md +++ b/docs/BuildAndTest.md @@ -138,7 +138,8 @@ make test-registry # package registry (local + HTTP index) make test-apps # showcase apps build + simpledb/jwt CLI smoke (in `make test`) make test-dwarf # #line maps + .debug_info + --release (in `make test`) make test-registry # package registry local + HTTP (in `make test`) -make test-lsp # hover + references/rename smokes +make test-selfhost-smoke # buxc2: move_field + multi-file #line (in `make test`) +make test-lsp # hover + references/rename + call hierarchy make bench # micro-benchmarks (Bux + C/Nim/Zig twins) make bench-nexus # wrk throughput vs apps/nexus /api/health ``` diff --git a/docs/QUALITY_PLAN.md b/docs/QUALITY_PLAN.md index 835d76c..8b46dc3 100644 --- a/docs/QUALITY_PLAN.md +++ b/docs/QUALITY_PLAN.md @@ -1,7 +1,7 @@ # Bux — План към „добър“ език (v0.5 → v1.0) > **Дата:** 2026-07-19 -> **Текущо:** v0.5.x — field-move, **multi-file #line**, Nexus KA, LSP 0.8 call hierarchy +> **Текущо:** v0.5.x — multi-file #line, **selfhost CI smoke**, LSP 0.8, Nexus KA > **Цел:** Език, с който се пишат реални проекти комфортно, безопасно (по избор) и с надежден toolchain. --- @@ -656,9 +656,35 @@ A (stdlib ergonomics) → B (compiler holes) → C (ownership depth) --- +## Сесия 41 (selfhost multi-file #line paths) + +1. **`Decl.sourceFile`** stamped when parsing/merging each `.bux` file + (`Cli_StampSourceFile` / `Cli_MergeFileInto` / project `src/` loop) +2. **`HirFunc.sourceFile`** copied in `Lcx_LowerFunc` +3. **C backend:** before each function, set `currentFile` from `sourceFile` + and emit `#line 1 "path"` + per-stmt `#line N "path"` +4. **No env required** — stdlib + user multi-file paths appear automatically + (`lib/Fs.bux`, `./src/Util.bux`, `./src/Main.bux`, …) +5. Overrides: `BUX_DEBUG_FILE` (force one path), `BUX_NO_LINE=1` (disable) +6. Verified: multi-file project runs; `#line` paths distinct per source + +--- + +## Сесия 42 (selfhost CI smoke) + +1. **`tools/smoke_selfhost.sh`:** + - build/use `buxc2` (`make selfhost`) + - **move_field**: run PASS + no `Array_Drop(&items)` after field move + - **multi-file #line**: Util.bux + Main.bux + `lib/*.bux` paths in `main.c` +2. **`make test-selfhost-smoke`** depends on `selfhost` +3. Wired into default **`make test`** +4. Verified: smoke script PASS + +--- + ## Следващи стъпки -1. Selfhost multi-file `#line` paths without BUX_DEBUG_FILE -2. Wire selfhost smoke for move_field into CI -3. Method call hierarchy (receiver methods / interface dispatch) -4. Rename of method receivers / qualified module paths (edge cases) +1. Method call hierarchy (receiver methods / interface dispatch) +2. Rename of method receivers / qualified module paths (edge cases) +3. HirNode-level file for statements spanning multiple files (rare) +4. Optional: selfhost-loop as optional CI job (slow) diff --git a/tools/smoke_selfhost.sh b/tools/smoke_selfhost.sh new file mode 100755 index 0000000..b7acaa4 --- /dev/null +++ b/tools/smoke_selfhost.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash +# Smoke: selfhost compiler (buxc2) — move_field ownership + multi-file #line +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +BUXC2="$ROOT/build/selfhost/build/buxc2" +export BUX_STDLIB="$ROOT/lib" +unset BUX_DEBUG_FILE || true +unset BUX_NO_LINE || true + +if [[ ! -x "$BUXC2" ]]; then + echo "=== building selfhost (buxc2) ===" + (cd "$ROOT" && make selfhost) +fi +if [[ ! -x "$BUXC2" ]]; then + echo "error: buxc2 not found at $BUXC2" >&2 + exit 1 +fi + +TMP=$(mktemp -d) +trap 'rm -rf "$TMP"' EXIT + +# --------------------------------------------------------------------------- +# 1) move_field — Array moved into struct must not UAF; program runs +# --------------------------------------------------------------------------- +echo "=== selfhost: move_field ===" +MF="$TMP/move_field" +mkdir -p "$MF/src" +cp -a "$ROOT/rt" "$MF/" +cat > "$MF/bux.toml" <<'EOF' +[Package] +Name = "move_field" +Version = "0.1.0" +Type = "bin" + +[Build] +Output = "Bin" +EOF +cp "$ROOT/examples/move_field.bux" "$MF/src/Main.bux" + +(cd "$MF" && "$BUXC2" project .) +out=$("$MF/build/move_field") +echo "$out" | tee "$TMP/mf.out" +grep -q 'sum=30' "$TMP/mf.out" +grep -q 'PASS' "$TMP/mf.out" || grep -q 'move_field' "$TMP/mf.out" +# No Drop of moved local in MakeBox +if grep -A20 'MakeBox' "$MF/build/main.c" | grep -q 'Array_Drop_int(&items)'; then + echo "error: MakeBox still drops moved 'items'" >&2 + grep -n 'MakeBox\|Array_Drop_int' "$MF/build/main.c" | head -30 + exit 1 +fi +echo " move_field: PASS (run + no Drop of moved Array)" + +# --------------------------------------------------------------------------- +# 2) multi-file #line — Util.bux + Main.bux + stdlib paths, no BUX_DEBUG_FILE +# --------------------------------------------------------------------------- +echo "=== selfhost: multi-file #line ===" +MF2="$TMP/mfline" +mkdir -p "$MF2/src" +cp -a "$ROOT/rt" "$MF2/" +cat > "$MF2/bux.toml" <<'EOF' +[Package] +Name = "mfline" +Version = "0.1.0" +Type = "bin" + +[Build] +Output = "Bin" +EOF +cat > "$MF2/src/Util.bux" <<'EOF' +module Util { + pub func Util_Double(n: int) -> int { + return n * 2; + } +} +EOF +cat > "$MF2/src/Main.bux" <<'EOF' +import Std::Io::{PrintLine}; +import Std::String::{String_FromInt}; + +func Main() -> int { + let v: int = Util_Double(21); + PrintLine(String_FromInt(v as int64)); + return 0; +} +EOF + +(cd "$MF2" && "$BUXC2" project .) +run_out=$("$MF2/build/mfline") +echo "$run_out" | tee "$TMP/mf2.out" +grep -q '42' "$TMP/mf2.out" + +MAIN_C="$MF2/build/main.c" +test -f "$MAIN_C" +# Distinct source paths in #line +if ! grep -qE '#line [0-9]+ ".*Util\.bux"' "$MAIN_C"; then + echo "error: no #line for Util.bux" >&2 + grep -E '^#line ' "$MAIN_C" | tail -20 + exit 1 +fi +if ! grep -qE '#line [0-9]+ ".*Main\.bux"' "$MAIN_C"; then + echo "error: no #line for Main.bux" >&2 + exit 1 +fi +# Stdlib also stamped +if ! grep -qE '#line [0-9]+ ".*lib/.*\.bux"' "$MAIN_C"; then + echo "error: no #line for stdlib lib/*.bux" >&2 + exit 1 +fi +echo " multi-file #line: PASS (Util + Main + lib)" + +echo "PASS: selfhost smoke (move_field + multi-file #line)"