| Chris@303 | 1 #!/bin/bash | 
| Chris@303 | 2 | 
| Chris@303 | 3 # Disable shellcheck warnings for useless-use-of-cat. UUOC is good | 
| Chris@303 | 4 # practice, not bad: clearer, safer, less error-prone. | 
| Chris@303 | 5 # shellcheck disable=SC2002 | 
| Chris@303 | 6 | 
| Chris@303 | 7 sml="$VEXT_SML" | 
| Chris@303 | 8 | 
| Chris@303 | 9 set -eu | 
| Chris@303 | 10 | 
| Chris@303 | 11 mydir=$(dirname "$0") | 
| Chris@303 | 12 program="$mydir/vext.sml" | 
| Chris@303 | 13 | 
| Chris@314 | 14 hasher= | 
| Chris@314 | 15 local_install= | 
| Chris@314 | 16 if [ -w "$mydir" ]; then | 
| Chris@314 | 17     if echo | sha256sum >/dev/null 2>&1 ; then | 
| Chris@314 | 18 	hasher=sha256sum | 
| Chris@314 | 19         local_install=true | 
| Chris@314 | 20     elif echo | shasum >/dev/null 2>&1 ; then | 
| Chris@314 | 21 	hasher=shasum | 
| Chris@314 | 22 	local_install=true | 
| Chris@314 | 23     else | 
| Chris@314 | 24         echo "WARNING: sha256sum or shasum program not found" 1>&2 | 
| Chris@314 | 25     fi | 
| Chris@314 | 26 fi | 
| Chris@314 | 27 | 
| Chris@314 | 28 if [ -n "$local_install" ]; then | 
| Chris@314 | 29     hash=$(echo "$sml" | cat "$program" - | $hasher | cut -c1-16) | 
| Chris@314 | 30     gen_sml=$mydir/.vext-$hash.sml | 
| Chris@314 | 31     gen_out=$mydir/.vext-$hash.bin | 
| Chris@314 | 32     trap 'rm -f $gen_sml' 0 | 
| Chris@314 | 33 else | 
| Chris@314 | 34     gen_sml=$(mktemp /tmp/vext-XXXXXXXX.sml) | 
| Chris@314 | 35     gen_out=$(mktemp /tmp/vext-XXXXXXXX.bin) | 
| Chris@314 | 36     trap 'rm -f $gen_sml $gen_out' 0 | 
| Chris@314 | 37 fi | 
| Chris@314 | 38 | 
| Chris@314 | 39 if [ -x "$gen_out" ]; then | 
| Chris@314 | 40     exec "$gen_out" "$@" | 
| Chris@314 | 41 fi | 
| Chris@314 | 42 | 
| Chris@303 | 43 # We need one of Poly/ML, SML/NJ, or MLton. Since we're running a | 
| Chris@303 | 44 # single-file SML program as if it were a script, our order of | 
| Chris@314 | 45 # preference is based on startup speed, except in the local_install | 
| Chris@314 | 46 # case where we retain a persistent binary. | 
| Chris@303 | 47 | 
| Chris@303 | 48 if [ -z "$sml" ]; then | 
| Chris@314 | 49     if [ -n "$local_install" ] && mlton 2>&1 | grep -q 'MLton'; then | 
| Chris@314 | 50 	sml="mlton" | 
| Chris@314 | 51     elif sml -h 2>&1 | grep -q 'Standard ML of New Jersey'; then | 
| Chris@303 | 52 	sml="smlnj" | 
| Chris@303 | 53     # We would prefer Poly/ML to SML/NJ, except that Poly v5.7 has a | 
| Chris@303 | 54     # nasty bug that occasionally causes it to deadlock on startup. | 
| Chris@303 | 55     # That appears to be fixed in their repo, so we could promote it | 
| Chris@303 | 56     # up the order again at some point in future | 
| Chris@303 | 57     elif echo | poly -v 2>/dev/null | grep -q 'Poly/ML'; then | 
| Chris@303 | 58 	sml="poly" | 
| Chris@303 | 59     elif mlton 2>&1 | grep -q 'MLton'; then | 
| Chris@303 | 60 	sml="mlton" | 
| Chris@303 | 61     else cat 1>&2 <<EOF | 
| Chris@303 | 62 | 
| Chris@303 | 63 ERROR: No supported SML compiler or interpreter found | 
| Chris@303 | 64 EOF | 
| Chris@315 | 65 	cat 1>&2 <<EOF | 
| Chris@303 | 66 | 
| Chris@303 | 67   The Vext external source code manager needs a Standard ML (SML) | 
| Chris@303 | 68   compiler or interpreter to run. | 
| Chris@303 | 69 | 
| Chris@303 | 70   Please ensure you have one of the following SML implementations | 
| Chris@303 | 71   installed and present in your PATH, and try again. | 
| Chris@303 | 72 | 
| Chris@303 | 73     1. Standard ML of New Jersey | 
| Chris@303 | 74        - often found in a distribution package called: smlnj | 
| Chris@303 | 75        - executable name: sml | 
| Chris@303 | 76 | 
| Chris@303 | 77     2. Poly/ML | 
| Chris@303 | 78        - often found in a distribution package called: polyml | 
| Chris@303 | 79        - executable name: poly | 
| Chris@303 | 80 | 
| Chris@303 | 81     3. MLton | 
| Chris@303 | 82        - often found in a distribution package called: mlton | 
| Chris@303 | 83        - executable name: mlton | 
| Chris@303 | 84 | 
| Chris@303 | 85 EOF | 
| Chris@303 | 86 	exit 2 | 
| Chris@303 | 87     fi | 
| Chris@303 | 88 fi | 
| Chris@303 | 89 | 
| Chris@303 | 90 arglist="" | 
| Chris@303 | 91 for arg in "$@"; do | 
| Chris@303 | 92     if [ -n "$arglist" ]; then arglist="$arglist,"; fi | 
| Chris@315 | 93     if echo "$arg" | grep -q '["'"'"']' ; then | 
| Chris@303 | 94 	arglist="$arglist\"usage\"" | 
| Chris@303 | 95     else | 
| Chris@303 | 96 	arglist="$arglist\"$arg\"" | 
| Chris@303 | 97     fi | 
| Chris@303 | 98 done | 
| Chris@303 | 99 | 
| Chris@303 | 100 case "$sml" in | 
| Chris@314 | 101     poly) | 
| Chris@314 | 102         if [ -n "$local_install" ] && polyc --help >/dev/null 2>&1 ; then | 
| Chris@314 | 103             if [ ! -x "$gen_out" ]; then | 
| Chris@314 | 104                 polyc -o "$gen_out" "$program" | 
| Chris@314 | 105             fi | 
| Chris@314 | 106 	    "$gen_out" "$@" | 
| Chris@314 | 107         else | 
| Chris@314 | 108             echo 'use "'"$program"'"; vext ['"$arglist"'];' | | 
| Chris@314 | 109                 poly -q --error-exit | 
| Chris@314 | 110         fi ;; | 
| Chris@303 | 111     mlton) | 
| Chris@314 | 112         if [ ! -x "$gen_out" ]; then | 
| Chris@315 | 113 	    echo "[Precompiling Vext binary...]" 1>&2 | 
| Chris@314 | 114 	    echo "val _ = main ()" | cat "$program" - > "$gen_sml" | 
| Chris@314 | 115 	    mlton -output "$gen_out" "$gen_sml" | 
| Chris@314 | 116         fi | 
| Chris@314 | 117 	"$gen_out" "$@" ;; | 
| Chris@303 | 118     smlnj) | 
| Chris@303 | 119 	cat "$program" | ( | 
| Chris@303 | 120 	    cat <<EOF | 
| Chris@303 | 121 val smlrun__cp = | 
| Chris@303 | 122     let val x = !Control.Print.out in | 
| Chris@303 | 123         Control.Print.out := { say = fn _ => (), flush = fn () => () }; | 
| Chris@303 | 124         x | 
| Chris@303 | 125     end; | 
| Chris@303 | 126 val smlrun__prev = ref ""; | 
| Chris@303 | 127 Control.Print.out := { | 
| Chris@303 | 128     say = fn s => | 
| Chris@303 | 129         (if String.isSubstring " Error" s | 
| Chris@303 | 130          then (Control.Print.out := smlrun__cp; | 
| Chris@303 | 131                (#say smlrun__cp) (!smlrun__prev); | 
| Chris@303 | 132                (#say smlrun__cp) s) | 
| Chris@303 | 133          else (smlrun__prev := s; ())), | 
| Chris@303 | 134     flush = fn s => () | 
| Chris@303 | 135 }; | 
| Chris@303 | 136 EOF | 
| Chris@303 | 137 	    cat - | 
| Chris@303 | 138 	    cat <<EOF | 
| Chris@303 | 139 val _ = vext [$arglist]; | 
| Chris@303 | 140 val _ = OS.Process.exit (OS.Process.success); | 
| Chris@303 | 141 EOF | 
| Chris@314 | 142             ) > "$gen_sml" | 
| Chris@314 | 143 	CM_VERBOSE=false sml "$gen_sml" ;; | 
| Chris@303 | 144     *) | 
| Chris@315 | 145 	echo "ERROR: Unknown SML implementation name: $sml" 1>&2; | 
| Chris@303 | 146 	exit 2 ;; | 
| Chris@303 | 147 esac | 
| Chris@303 | 148 |