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