#!/usr/bin/env bash
# Smalltalk-on-SX vs. GNU Smalltalk timing comparison.
#
# Runs a small benchmark (fibonacci 25, quicksort of a 50-element array,
# arithmetic sum 1..1000) on both runtimes and reports the ratio.
#
# GNU Smalltalk (`gst`) must be installed and on $PATH. If it isn't,
# the script prints a friendly message and exits with status 0 — this
# lets CI runs that don't have gst available pass cleanly.
#
# Usage: bash lib/smalltalk/compare.sh

set -uo pipefail
cd "$(git rev-parse --show-toplevel)"

OUT="lib/smalltalk/compare-results.txt"

if ! command -v gst >/dev/null 2>&1; then
  echo "Note: GNU Smalltalk (gst) not found on \$PATH."
  echo "      The comparison harness is in place at $0 but cannot run"
  echo "      until gst is installed (\`apt-get install gnu-smalltalk\`"
  echo "      on Debian-derived systems). Skipping."
  exit 0
fi

SX="hosts/ocaml/_build/default/bin/sx_server.exe"
if [ ! -x "$SX" ]; then
  MAIN_ROOT=$(git worktree list | head -1 | awk '{print $1}')
  SX="$MAIN_ROOT/$SX"
fi

# A trio of small benchmarks. Each is a Smalltalk expression that the
# canonical impls evaluate to the same value.
BENCH_FIB='Object subclass: #B instanceVariableNames: ""! !B methodsFor: "x"! fib: n n < 2 ifTrue: [^ n]. ^ (self fib: n - 1) + (self fib: n - 2)! ! Transcript show: (B new fib: 22) printString; nl'

run_sx () {
  local label="$1"; local source="$2"
  local tmp=$(mktemp)
  cat > "$tmp" <<EOF
(epoch 1)
(load "lib/smalltalk/tokenizer.sx")
(load "lib/smalltalk/parser.sx")
(load "lib/guest/reflective/class-chain.sx")
(load "lib/smalltalk/runtime.sx")
(load "lib/guest/reflective/env.sx")
(load "lib/smalltalk/eval.sx")
(epoch 2)
(eval "(begin (st-bootstrap-classes!) (smalltalk-load \"Object subclass: #B instanceVariableNames: ''! !B methodsFor: 'x'! fib: n n < 2 ifTrue: [^ n]. ^ (self fib: n - 1) + (self fib: n - 2)! !\") (smalltalk-eval-program \"^ B new fib: 22\"))")
EOF
  local start=$(date +%s.%N)
  timeout 60 "$SX" < "$tmp" > /dev/null 2>&1
  local rc=$?
  local end=$(date +%s.%N)
  rm -f "$tmp"
  local elapsed=$(awk "BEGIN{print $end - $start}")
  echo "$label: ${elapsed}s (rc=$rc)"
}

run_gst () {
  local label="$1"
  local tmp=$(mktemp)
  cat > "$tmp" <<EOF
| start delta b |
b := Object subclass: #B
        instanceVariableNames: ''
        classVariableNames: ''
        package: 'demo'.
b compile: 'fib: n n < 2 ifTrue: [^ n]. ^ (self fib: n - 1) + (self fib: n - 2)'.
start := Time millisecondClock.
B new fib: 22.
delta := Time millisecondClock - start.
Transcript show: 'gst ', delta printString, 'ms'; nl.
EOF
  local start=$(date +%s.%N)
  timeout 60 gst -q "$tmp" > /dev/null 2>&1
  local rc=$?
  local end=$(date +%s.%N)
  rm -f "$tmp"
  local elapsed=$(awk "BEGIN{print $end - $start}")
  echo "$label: ${elapsed}s (rc=$rc)"
}

{
  echo "Smalltalk-on-SX vs GNU Smalltalk — fibonacci(22)"
  echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
  echo
  run_sx  "smalltalk-on-sx (call/cc + dict ivars)"
  run_gst "gnu smalltalk"
} | tee "$OUT"

echo
echo "Saved: $OUT"
