| 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@303 | 14 # We need one of Poly/ML, SML/NJ, or MLton. Since we're running a | 
| Chris@303 | 15 # single-file SML program as if it were a script, our order of | 
| Chris@303 | 16 # preference is based on startup speed. | 
| Chris@303 | 17 | 
| Chris@303 | 18 if [ -z "$sml" ]; then | 
| Chris@303 | 19     if sml -h 2>&1 | grep -q 'Standard ML of New Jersey'; then | 
| Chris@303 | 20 	sml="smlnj" | 
| Chris@303 | 21     # We would prefer Poly/ML to SML/NJ, except that Poly v5.7 has a | 
| Chris@303 | 22     # nasty bug that occasionally causes it to deadlock on startup. | 
| Chris@303 | 23     # That appears to be fixed in their repo, so we could promote it | 
| Chris@303 | 24     # up the order again at some point in future | 
| Chris@303 | 25     elif echo | poly -v 2>/dev/null | grep -q 'Poly/ML'; then | 
| Chris@303 | 26 	sml="poly" | 
| Chris@303 | 27     elif mlton 2>&1 | grep -q 'MLton'; then | 
| Chris@303 | 28 	sml="mlton" | 
| Chris@303 | 29     else cat 1>&2 <<EOF | 
| Chris@303 | 30 | 
| Chris@303 | 31 ERROR: No supported SML compiler or interpreter found | 
| Chris@303 | 32 EOF | 
| Chris@303 | 33 	cat <<EOF | 
| Chris@303 | 34 | 
| Chris@303 | 35   The Vext external source code manager needs a Standard ML (SML) | 
| Chris@303 | 36   compiler or interpreter to run. | 
| Chris@303 | 37 | 
| Chris@303 | 38   Please ensure you have one of the following SML implementations | 
| Chris@303 | 39   installed and present in your PATH, and try again. | 
| Chris@303 | 40 | 
| Chris@303 | 41     1. Standard ML of New Jersey | 
| Chris@303 | 42        - often found in a distribution package called: smlnj | 
| Chris@303 | 43        - executable name: sml | 
| Chris@303 | 44 | 
| Chris@303 | 45     2. Poly/ML | 
| Chris@303 | 46        - often found in a distribution package called: polyml | 
| Chris@303 | 47        - executable name: poly | 
| Chris@303 | 48 | 
| Chris@303 | 49     3. MLton | 
| Chris@303 | 50        - often found in a distribution package called: mlton | 
| Chris@303 | 51        - executable name: mlton | 
| Chris@303 | 52 | 
| Chris@303 | 53 EOF | 
| Chris@303 | 54 	exit 2 | 
| Chris@303 | 55     fi | 
| Chris@303 | 56 fi | 
| Chris@303 | 57 | 
| Chris@303 | 58 tmp_sml=$(mktemp /tmp/vext-XXXXXXXX.sml) | 
| Chris@303 | 59 tmp_out=$(mktemp /tmp/vext-XXXXXXXX.bin) | 
| Chris@303 | 60 | 
| Chris@303 | 61 trap 'rm -f $tmp_sml $tmp_out' 0 | 
| Chris@303 | 62 | 
| Chris@303 | 63 arglist="" | 
| Chris@303 | 64 for arg in "$@"; do | 
| Chris@303 | 65     if [ -n "$arglist" ]; then arglist="$arglist,"; fi | 
| Chris@303 | 66     if echo "$arg" | grep -q '[^a-z]' ; then | 
| Chris@303 | 67 	arglist="$arglist\"usage\"" | 
| Chris@303 | 68     else | 
| Chris@303 | 69 	arglist="$arglist\"$arg\"" | 
| Chris@303 | 70     fi | 
| Chris@303 | 71 done | 
| Chris@303 | 72 | 
| Chris@303 | 73 case "$sml" in | 
| Chris@303 | 74     poly) echo 'use "'"$program"'"; vext ['"$arglist"'];' | | 
| Chris@303 | 75 		poly -q --error-exit ;; | 
| Chris@303 | 76     mlton) | 
| Chris@303 | 77 	cat "$program" > "$tmp_sml" | 
| Chris@303 | 78 	echo 'val _ = main ()' >> "$tmp_sml" | 
| Chris@303 | 79 	mlton -output "$tmp_out" "$tmp_sml" | 
| Chris@303 | 80 	"$tmp_out" "$@" ;; | 
| Chris@303 | 81     smlnj) | 
| Chris@303 | 82 	cat "$program" | ( | 
| Chris@303 | 83 	    cat <<EOF | 
| Chris@303 | 84 val smlrun__cp = | 
| Chris@303 | 85     let val x = !Control.Print.out in | 
| Chris@303 | 86         Control.Print.out := { say = fn _ => (), flush = fn () => () }; | 
| Chris@303 | 87         x | 
| Chris@303 | 88     end; | 
| Chris@303 | 89 val smlrun__prev = ref ""; | 
| Chris@303 | 90 Control.Print.out := { | 
| Chris@303 | 91     say = fn s => | 
| Chris@303 | 92         (if String.isSubstring " Error" s | 
| Chris@303 | 93          then (Control.Print.out := smlrun__cp; | 
| Chris@303 | 94                (#say smlrun__cp) (!smlrun__prev); | 
| Chris@303 | 95                (#say smlrun__cp) s) | 
| Chris@303 | 96          else (smlrun__prev := s; ())), | 
| Chris@303 | 97     flush = fn s => () | 
| Chris@303 | 98 }; | 
| Chris@303 | 99 EOF | 
| Chris@303 | 100 	    cat - | 
| Chris@303 | 101 	    cat <<EOF | 
| Chris@303 | 102 val _ = vext [$arglist]; | 
| Chris@303 | 103 val _ = OS.Process.exit (OS.Process.success); | 
| Chris@303 | 104 EOF | 
| Chris@303 | 105             ) > "$tmp_sml" | 
| Chris@303 | 106 	CM_VERBOSE=false sml "$tmp_sml" ;; | 
| Chris@303 | 107     *) | 
| Chris@303 | 108 	echo "Unknown SML implementation name: $sml"; | 
| Chris@303 | 109 	exit 2 ;; | 
| Chris@303 | 110 esac | 
| Chris@303 | 111 |