Chris@1808: #!/bin/bash
Chris@1808: 
Chris@1808: # Disable shellcheck warnings for useless-use-of-cat. UUOC is good
Chris@1808: # practice, not bad: clearer, safer, less error-prone.
Chris@1808: # shellcheck disable=SC2002
Chris@1808: 
Chris@1808: sml="$REPOINT_SML"
Chris@1808: 
Chris@1808: set -eu
Chris@1808: 
Chris@1808: # avoid gussying up output
Chris@1808: export HGPLAIN=true
Chris@1808: 
Chris@1808: mydir=$(dirname "$0")
Chris@1808: program="$mydir/repoint.sml"
Chris@1808: 
Chris@1808: hasher=
Chris@1808: local_install=
Chris@1808: if [ -w "$mydir" ]; then
Chris@1808:     if echo | sha256sum >/dev/null 2>&1 ; then
Chris@1808: 	hasher=sha256sum
Chris@1808:         local_install=true
Chris@1808:     elif echo | shasum >/dev/null 2>&1 ; then
Chris@1808: 	hasher=shasum
Chris@1808: 	local_install=true
Chris@1808:     else
Chris@1808:         echo "WARNING: sha256sum or shasum program not found" 1>&2
Chris@1808:     fi
Chris@1808: fi
Chris@1808: 
Chris@1808: if [ -n "$local_install" ]; then
Chris@1808:     hash=$(echo "$sml" | cat "$program" - | $hasher | cut -c1-16)
Chris@1808:     gen_sml=$mydir/.repoint-$hash.sml
Chris@1808:     gen_out=$mydir/.repoint-$hash.bin
Chris@1808:     trap 'rm -f $gen_sml' 0
Chris@1808: else
Chris@1808:     gen_sml=$(mktemp /tmp/repoint-XXXXXXXX.sml)
Chris@1808:     gen_out=$(mktemp /tmp/repoint-XXXXXXXX.bin)
Chris@1808:     trap 'rm -f $gen_sml $gen_out' 0
Chris@1808: fi
Chris@1808: 
Chris@1808: if [ -x "$gen_out" ]; then
Chris@1808:     exec "$gen_out" "$@"
Chris@1808: fi
Chris@1808: 
Chris@1808: # We need one of Poly/ML, SML/NJ, MLton, or MLKit. Since we're running
Chris@1808: # a single-file SML program as if it were a script, our order of
Chris@1808: # preference is usually based on startup speed. An exception is the
Chris@1808: # local_install case, where we retain a persistent binary
Chris@1808: 
Chris@1808: if [ -z "$sml" ]; then
Chris@1808:     if [ -n "$local_install" ] && mlton 2>&1 | grep -q 'MLton'; then
Chris@1808: 	sml="mlton"
Chris@1808:     elif sml -h 2>&1 | grep -q 'Standard ML of New Jersey'; then
Chris@1808: 	sml="smlnj"
Chris@1808:     # We would prefer Poly/ML to SML/NJ, except that Poly v5.7 has a
Chris@1808:     # nasty bug that occasionally causes it to deadlock on startup.
Chris@1808:     # That is fixed in v5.7.1, so we could promote it up the order
Chris@1808:     # again at some point in future
Chris@1808:     elif echo | poly -v 2>/dev/null | grep -q 'Poly/ML'; then
Chris@1823: 	sml="polyml"
Chris@1808:     elif mlton 2>&1 | grep -q 'MLton'; then
Chris@1808: 	sml="mlton"
Chris@1808:     # MLKit is at the bottom because it leaves compiled files around
Chris@1808:     # in an MLB subdir in the current directory
Chris@1808:     elif mlkit 2>&1 | grep -q 'MLKit'; then
Chris@1808: 	sml="mlkit"
Chris@1808:     else cat 1>&2 <<EOF
Chris@1808: 
Chris@1808: ERROR: No supported SML compiler or interpreter found       
Chris@1808: EOF
Chris@1808: 	cat 1>&2 <<EOF
Chris@1808: 
Chris@1808:   The Repoint external source code manager needs a Standard ML (SML)
Chris@1808:   compiler or interpreter to run.
Chris@1808: 
Chris@1808:   Please ensure you have one of the following SML implementations
Chris@1808:   installed and present in your PATH, and try again.
Chris@1808: 
Chris@1808:     1. Standard ML of New Jersey
Chris@1808:        - may be found in a distribution package called: smlnj
Chris@1808:        - executable name: sml
Chris@1808: 
Chris@1808:     2. Poly/ML
Chris@1808:        - may be found in a distribution package called: polyml
Chris@1808:        - executable name: poly
Chris@1808: 
Chris@1808:     3. MLton
Chris@1808:        - may be found in a distribution package called: mlton
Chris@1808:        - executable name: mlton
Chris@1808: 
Chris@1808:     4. MLKit
Chris@1808:        - may be found in a distribution package called: mlkit
Chris@1808:        - executable name: mlkit
Chris@1808: 
Chris@1808: EOF
Chris@1808: 	exit 2
Chris@1808:     fi
Chris@1808: fi
Chris@1808: 
Chris@1808: arglist=""
Chris@1808: for arg in "$@"; do
Chris@1808:     if [ -n "$arglist" ]; then arglist="$arglist,"; fi
Chris@1808:     if echo "$arg" | grep -q '["'"'"']' ; then
Chris@1808: 	arglist="$arglist\"usage\""
Chris@1808:     else
Chris@1808: 	arglist="$arglist\"$arg\""
Chris@1808:     fi
Chris@1808: done
Chris@1808: 
Chris@1808: case "$sml" in
Chris@1823:     polyml)
Chris@1808:         if [ -n "$local_install" ] && polyc --help >/dev/null 2>&1 ; then
Chris@1808:             if [ ! -x "$gen_out" ]; then
Chris@1808:                 polyc -o "$gen_out" "$program"
Chris@1808:             fi
Chris@1808: 	    "$gen_out" "$@"
Chris@1808:         else
Chris@1808:             echo 'use "'"$program"'"; repoint ['"$arglist"'];' |
Chris@1808:                 poly -q --error-exit
Chris@1808:         fi ;;
Chris@1808:     mlton)
Chris@1808:         if [ ! -x "$gen_out" ]; then
Chris@1808: 	    echo "[Precompiling Repoint binary...]" 1>&2
Chris@1808: 	    echo "val _ = main ()" | cat "$program" - > "$gen_sml"
Chris@1808: 	    mlton -output "$gen_out" "$gen_sml"
Chris@1808:         fi
Chris@1808: 	"$gen_out" "$@" ;;
Chris@1808:     mlkit)
Chris@1808:         if [ ! -x "$gen_out" ]; then
Chris@1808: 	    echo "[Precompiling Repoint binary...]" 1>&2
Chris@1808: 	    echo "val _ = main ()" | cat "$program" - > "$gen_sml"
Chris@1808: 	    mlkit -output "$gen_out" "$gen_sml"
Chris@1808:         fi
Chris@1808: 	"$gen_out" "$@" ;;
Chris@1808:     smlnj)
Chris@1808: 	cat "$program" | (
Chris@1808: 	    cat <<EOF
Chris@1808: val smlrun__cp = 
Chris@1808:     let val x = !Control.Print.out in
Chris@1808:         Control.Print.out := { say = fn _ => (), flush = fn () => () };
Chris@1808:         x
Chris@1808:     end;
Chris@1808: val smlrun__prev = ref "";
Chris@1808: Control.Print.out := { 
Chris@1808:     say = fn s => 
Chris@1808:         (if String.isSubstring " Error" s
Chris@1808:          then (Control.Print.out := smlrun__cp;
Chris@1808:                (#say smlrun__cp) (!smlrun__prev);
Chris@1808:                (#say smlrun__cp) s)
Chris@1808:          else (smlrun__prev := s; ())),
Chris@1808:     flush = fn s => ()
Chris@1808: };
Chris@1808: EOF
Chris@1808: 	    cat -
Chris@1808: 	    cat <<EOF
Chris@1808: val _ = repoint [$arglist];
Chris@1808: val _ = OS.Process.exit (OS.Process.success);
Chris@1808: EOF
Chris@1808:             ) > "$gen_sml"
Chris@1808: 	CM_VERBOSE=false sml "$gen_sml" ;;
Chris@1808:     *)
Chris@1808: 	echo "ERROR: Unknown SML implementation name: $sml" 1>&2;
Chris@1808: 	exit 2 ;;
Chris@1808: esac
Chris@1808: