#!/usr/bin/env bash set -euo pipefail # Lux Full Validation Script # Runs all checks: Rust tests, package tests, type checking, example compilation. # Run after every committable change to ensure no regressions. # cd to repo root (directory containing this script's parent) SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" cd "$SCRIPT_DIR/.." LUX="$(pwd)/target/release/lux" PACKAGES_DIR="$(pwd)/../packages" PROJECTS_DIR="$(pwd)/projects" EXAMPLES_DIR="$(pwd)/examples" RED='\033[0;31m' GREEN='\033[0;32m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' FAILED=0 TOTAL=0 step() { TOTAL=$((TOTAL + 1)) printf "${CYAN}[%d]${NC} %s... " "$TOTAL" "$1" } ok() { printf "${GREEN}ok${NC} %s\n" "${1:-}"; } fail() { printf "${RED}FAIL${NC} %s\n" "${1:-}"; FAILED=$((FAILED + 1)); } # --- Rust checks --- step "cargo check" if nix develop --command cargo check 2>/dev/null; then ok; else fail; fi step "cargo test" OUTPUT=$(nix develop --command cargo test 2>&1 || true) RESULT=$(echo "$OUTPUT" | grep "test result:" || echo "no result") if echo "$RESULT" | grep -q "0 failed"; then ok "$RESULT"; else fail "$RESULT"; fi # --- Build release binary --- step "cargo build --release" if nix develop --command cargo build --release 2>/dev/null; then ok; else fail; fi # --- Package tests --- for pkg in path frontmatter xml rss markdown; do PKG_DIR="$PACKAGES_DIR/$pkg" if [ -d "$PKG_DIR" ]; then step "lux test ($pkg)" OUTPUT=$(cd "$PKG_DIR" && "$LUX" test 2>&1 || true) RESULT=$(echo "$OUTPUT" | grep "passed" | tail -1 || echo "no result") if echo "$RESULT" | grep -q "passed"; then ok "$RESULT"; else fail "$RESULT"; fi fi done # --- Lux check on packages --- for pkg in path frontmatter xml rss markdown; do PKG_DIR="$PACKAGES_DIR/$pkg" if [ -d "$PKG_DIR" ]; then step "lux check ($pkg)" OUTPUT=$(cd "$PKG_DIR" && "$LUX" check 2>&1 || true) RESULT=$(echo "$OUTPUT" | grep "passed" | tail -1 || echo "no result") if echo "$RESULT" | grep -q "passed"; then ok; else fail "$RESULT"; fi fi done # --- Project checks --- for proj_dir in "$PROJECTS_DIR"/*/; do proj=$(basename "$proj_dir") if [ -f "$proj_dir/main.lux" ]; then step "lux check (project: $proj)" OUTPUT=$("$LUX" check "$proj_dir/main.lux" 2>&1 || true) if echo "$OUTPUT" | grep -qi "error"; then fail; else ok; fi fi # Check any standalone .lux files in the project for lux_file in "$proj_dir"/*.lux; do [ -f "$lux_file" ] || continue fname=$(basename "$lux_file") [ "$fname" = "main.lux" ] && continue step "lux check (project: $proj/$fname)" OUTPUT=$("$LUX" check "$lux_file" 2>&1 || true) if echo "$OUTPUT" | grep -qi "error"; then fail; else ok; fi done done # === Compilation & Interpreter Checks === # --- Interpreter: examples --- # Skip: http_api, http, http_router, http_server (network), postgres_demo (db), # random, property_testing (Random effect), shell (Process), json (File I/O), # file_io (File I/O), test_math, test_lists (Test effect), stress_shared_rc, # test_rc_comparison (internal tests), modules/* (need cwd) INTERP_SKIP="http_api http http_router http_server postgres_demo random property_testing shell json file_io test_math test_lists stress_shared_rc test_rc_comparison" for f in "$EXAMPLES_DIR"/*.lux; do name=$(basename "$f" .lux) skip=false for s in $INTERP_SKIP; do [ "$name" = "$s" ] && skip=true; done $skip && continue step "interpreter (examples/$name)" if timeout 10 "$LUX" "$f" >/dev/null 2>&1; then ok; else fail; fi done # --- Interpreter: examples/standard --- # Skip: guessing_game (reads stdin) for f in "$EXAMPLES_DIR"/standard/*.lux; do [ -f "$f" ] || continue name=$(basename "$f" .lux) [ "$name" = "guessing_game" ] && continue step "interpreter (standard/$name)" if timeout 10 "$LUX" "$f" >/dev/null 2>&1; then ok; else fail; fi done # --- Interpreter: examples/showcase --- # Skip: task_manager (parse error in current version) for f in "$EXAMPLES_DIR"/showcase/*.lux; do [ -f "$f" ] || continue name=$(basename "$f" .lux) [ "$name" = "task_manager" ] && continue step "interpreter (showcase/$name)" if timeout 10 "$LUX" "$f" >/dev/null 2>&1; then ok; else fail; fi done # --- Interpreter: projects --- # Skip: guessing-game (Random), rest-api (HttpServer) PROJ_INTERP_SKIP="guessing-game rest-api" for proj_dir in "$PROJECTS_DIR"/*/; do proj=$(basename "$proj_dir") [ -f "$proj_dir/main.lux" ] || continue skip=false for s in $PROJ_INTERP_SKIP; do [ "$proj" = "$s" ] && skip=true; done $skip && continue step "interpreter (project: $proj)" if timeout 10 "$LUX" "$proj_dir/main.lux" >/dev/null 2>&1; then ok; else fail; fi done # --- JS compilation: examples --- # Skip files that fail JS compilation (unsupported features) JS_SKIP="http_api http http_router postgres_demo property_testing json test_lists test_rc_comparison" for f in "$EXAMPLES_DIR"/*.lux; do name=$(basename "$f" .lux) skip=false for s in $JS_SKIP; do [ "$name" = "$s" ] && skip=true; done $skip && continue step "compile JS (examples/$name)" if "$LUX" compile "$f" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi done # --- JS compilation: examples/standard --- # Skip: stdlib_demo (uses String.toUpper not in JS backend) for f in "$EXAMPLES_DIR"/standard/*.lux; do [ -f "$f" ] || continue name=$(basename "$f" .lux) [ "$name" = "stdlib_demo" ] && continue step "compile JS (standard/$name)" if "$LUX" compile "$f" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi done # --- JS compilation: examples/showcase --- # Skip: task_manager (unsupported features) for f in "$EXAMPLES_DIR"/showcase/*.lux; do [ -f "$f" ] || continue name=$(basename "$f" .lux) [ "$name" = "task_manager" ] && continue step "compile JS (showcase/$name)" if "$LUX" compile "$f" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi done # --- JS compilation: projects --- # Skip: json-parser, rest-api (unsupported features) JS_PROJ_SKIP="json-parser rest-api" for proj_dir in "$PROJECTS_DIR"/*/; do proj=$(basename "$proj_dir") [ -f "$proj_dir/main.lux" ] || continue skip=false for s in $JS_PROJ_SKIP; do [ "$proj" = "$s" ] && skip=true; done $skip && continue step "compile JS (project: $proj)" if "$LUX" compile "$proj_dir/main.lux" --target js -o /tmp/lux_validate.js >/dev/null 2>&1; then ok; else fail; fi done # --- C compilation: examples --- # Only compile examples known to work with C backend C_EXAMPLES="hello factorial pipelines tailcall jit_test" for name in $C_EXAMPLES; do f="$EXAMPLES_DIR/$name.lux" [ -f "$f" ] || continue step "compile C (examples/$name)" if "$LUX" compile "$f" -o /tmp/lux_validate_bin >/dev/null 2>&1; then ok; else fail; fi done # --- C compilation: examples/standard --- C_STD_EXAMPLES="hello_world factorial fizzbuzz primes guessing_game" for name in $C_STD_EXAMPLES; do f="$EXAMPLES_DIR/standard/$name.lux" [ -f "$f" ] || continue step "compile C (standard/$name)" if "$LUX" compile "$f" -o /tmp/lux_validate_bin >/dev/null 2>&1; then ok; else fail; fi done # --- Cleanup --- rm -f /tmp/lux_validate.js /tmp/lux_validate_bin # --- Summary --- printf "\n${BOLD}═══ Validation Summary ═══${NC}\n" if [ $FAILED -eq 0 ]; then printf "${GREEN}All %d checks passed.${NC}\n" "$TOTAL" else printf "${RED}%d/%d checks failed.${NC}\n" "$FAILED" "$TOTAL" exit 1 fi