#!/bin/sh
# -*- mode: sh-script; sh-shell: ash; -*-
# SPDX-FileCopyrightText: Copyright (c) 2024 s-expressionists
# SPDX-License-Identifier: MIT

# Usage:
#
#   bench [-v] [IMPLEMENTATION...]

set -o nounset
set -o pipefail
set -o errexit

nobench=
tag=
verbose=

abcl() {
  printf -- "--- ABCL ----------------------------------------------------------------------\n"
  if test -n "$verbose"; then
    command abcl --noinform "$@"
  else
    command abcl --noinform "$@" 2>&1 | awk '!keep && /^ +float-integer/ { keep=1; print "" } keep { print }'
  fi
}

ccl() {
  printf -- "--- CCL -----------------------------------------------------------------------\n"
  command ccl --batch "$@"
}

clasp() {
  printf -- "--- Clasp ---------------------------------------------------------------------\n"
  if test -n "$verbose"; then
    command clasp --noinform --disable-debugger "$@"
  else
    command clasp --noinform --disable-debugger "$@" | sed '/^;/d'
  fi
}

ecl() {
  printf -- "--- ECL -----------------------------------------------------------------------\n"
  if test -n "$verbose"; then
    command ecl "$@"
  else
    command ecl "$@" | sed '/^;;;/d'
  fi
}

sbcl() {
  printf -- "--- SBCL ----------------------------------------------------------------------\n"
  if test -n "$verbose"; then
    command sbcl --noinform --disable-debugger "$@"
  else
    command sbcl --noinform --disable-debugger "$@" 2>&1 | awk '!keep && /^ +float-integer/ { keep=1; print "" } keep { print }'
  fi
}

run() {
  local implementation="$1"
  "$implementation" \
    --eval '(require "asdf")' \
    --eval '(asdf:load-system "quaviver/benchmark")' \
    --eval '(defvar *benchmark-name* (format nil "~A~A" (uiop:implementation-identifier) "'"$tag"'"))' \
    --eval '(quaviver/benchmark:float-integer :name *benchmark-name*)' \
    --eval '(quaviver/benchmark:integer-float :name *benchmark-name*)' \
    --eval '(uiop:quit)'
}

bench() {
  local ret=0
  local impl_ret=0
  for implementation in "$@"; do
    case "$implementation" in
    abcl|ccl|clasp|ecl|sbcl)
      if command -v "$implementation" >/dev/null; then
        impl_ret=0
        if test -n "$verbose"; then
          run "$implementation" || impl_ret=1
        else
          run "$implementation" 2>/dev/null || impl_ret=1
        fi
        if test "$impl_ret" -ne 0; then
          printf >&2 "bench: benchmark failed: %s\n" "$implementation"
          ret=1
        fi
        printf "\n"
      else
        printf >&2 "bench: implementation not found: %s\n" "$implementation"
        ret=1
      fi
      ;;
    *)
      printf >&2 "bench: unknown implementation: %s\n" "$implementation"
      ret=1
      ;;
    esac
  done
  return "$ret"
}

while test "$#" -gt 0; do
  case "$1" in
  --)
    shift
    break
    ;;
  -n)
    nobench="nobench"
    shift
    ;;
  -t)
    if test "$#" -lt 2; then
      printf >&2 "bench: missing argument for option: %s\n" "$1"
      exit 1
    fi
    tag="-$2"
    shift 2
    ;;
  -v)
    verbose="verbose"
    shift
    ;;
  -?*)
    printf >&2 "bench: unknown option: %s\n" "$1"
    exit 1
    ;;
  *)
    break
    ;;
  esac
done

if test -n "$nobench"; then
  command sbcl --noinform --disable-debugger \
    --eval '(require "asdf")' \
    --eval '(asdf:load-system "quaviver/benchmark")' \
    --eval '(quaviver/benchmark:report)' \
    --eval '(uiop:quit)'
  exit
fi

if test "$#" -le 0; then
  for implementation in abcl ccl clasp ecl sbcl; do
    if command -v "$implementation" >/dev/null; then
      set -- "$@" "$implementation"
    fi
  done
fi

bench "$@"
