├── .appveyor.yml ├── .hgignore ├── .travis.yml ├── COPYING ├── README.md ├── mlb-coverage ├── mlb-dependencies ├── mlb-dependencies.ps1 ├── mlb-expand ├── mlton.bat ├── polybuild ├── polybuild.bat ├── polybuild.ps1 ├── polyrepl ├── polyrun ├── polyrun.ps1 ├── smlbuild-include.ps1 ├── smlbuild-include.sh ├── smlrepl ├── smlrun ├── smlrun.ps1 ├── test ├── main.sml ├── regression │ ├── annotate.txt │ ├── coverage.txt │ ├── dependencies.txt │ └── expand.txt ├── simple.mlb ├── simple.sml ├── test.ps1 └── test.sh ├── with-mlb-dependencies ├── with-mlb-dependencies.bat └── with-mlb-dependencies.ps1 /.appveyor.yml: -------------------------------------------------------------------------------- 1 | 2 | configuration: 3 | - Release 4 | 5 | install: 6 | - cinst --allow-empty-checksums smlnj 7 | 8 | before_build: 9 | - set PATH=%PATH%;C:\Program Files (x86)\SMLNJ\bin 10 | 11 | build_script: 12 | - ps: test\test.ps1 13 | 14 | -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *~ 3 | test/fxp 4 | *.orig 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: 2 | - trusty 3 | 4 | language: 5 | - cpp 6 | 7 | sudo: 8 | - false 9 | 10 | os: 11 | - osx 12 | 13 | addons: 14 | apt: 15 | packages: 16 | - mlton 17 | - smlnj 18 | - libsmlnj-smlnj 19 | - polyml 20 | 21 | before_install: 22 | - if [[ "$TRAVIS_OS_NAME" = "osx" ]] ; then brew update ; brew install mlton polyml rlwrap ; brew cask install smlnj ; fi 23 | 24 | script: 25 | - ./test/test.sh 26 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | 2 | Permission is hereby granted, free of charge, to any person 3 | obtaining a copy of this software and associated documentation 4 | files (the "Software"), to deal in the Software without 5 | restriction, including without limitation the rights to use, copy, 6 | modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be 11 | included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 14 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 15 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 16 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 17 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 18 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 19 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | SML build scripts 3 | ================== 4 | 5 | A set of scripts to compile and run Standard ML programs defined in 6 | `.mlb` files. 7 | 8 | All of these are Bash scripts for Unix-like systems, apart from one 9 | PowerShell script for Windows. 10 | 11 | [![Build Status](https://travis-ci.org/cannam/sml-buildscripts.svg?branch=master)](https://travis-ci.org/cannam/sml-buildscripts) 12 | [![Build status](https://ci.appveyor.com/api/projects/status/0tdilpimotvv71yp/branch/master?svg=true)](https://ci.appveyor.com/project/cannam/sml-buildscripts/branch/master) 13 | 14 | 15 | Motivation 16 | ---------- 17 | 18 | The `.mlb` file format (http://mlton.org/MLBasis) is, at its most 19 | basic, a list of the input files that constitute a Standard ML 20 | program. This appealingly simple format is supported by the 21 | [MLton](http://mlton.org) and [MLKit](http://www.elsman.com/mlkit/) 22 | compilers. A `.mlb` file can be compiled using either of these without 23 | any additional scripting: 24 | 25 | ``` 26 | $ mlton file.mlb # compile with MLton 27 | $ mlkit file.mlb # or compile with MLKit 28 | ``` 29 | 30 | But neither compiler is completely ideal on its own. MLton is slow to 31 | run, although it produces fast programs. MLKit runs faster but 32 | produces somewhat slower output. Neither of them is easy to use on 33 | Windows, and neither of them has an interactive environment. 34 | 35 | It would be nice to be able to use the same input files with 36 | [Poly/ML](http://polyml.org/), which has an excellent balance between 37 | the speed of the compiler and of the generated code, or 38 | [SML/NJ](http://smlnj.org/). Both run on Windows as well as Linux and 39 | macOS, and provide interactive environments. But, as of 2018 and the 40 | Poly/ML 5.7 and SML/NJ v110.82 releases, neither of them supports 41 | `.mlb` files directly. 42 | 43 | 44 | Build, run, and REPL scripts 45 | ---------------------------- 46 | 47 | The Bash script `polybuild` takes a `.mlb` file and builds an 48 | executable from it using the Poly/ML compiler: 49 | 50 | ``` 51 | $ polybuild file.mlb 52 | $ ./file 53 | ``` 54 | 55 | This compiles much faster than MLton and still produces a reasonably 56 | quick native executable. 57 | 58 | The Bash script `polyrun` takes a `.mlb` file and runs it once 59 | immediately in the Poly/ML environment, instead of creating an 60 | executable file as polybuild does. 61 | 62 | The Bash script `polyrepl` takes a `.mlb` file and loads it into the 63 | Poly/ML interactive environment, leaving you at the interactive prompt 64 | with your program's contents present in the current environment. 65 | 66 | The Bash script `smlrun` takes a `.mlb` file and runs it immediately 67 | using the SML/NJ environment. 68 | 69 | The PowerShell script `smlrun.ps1`, for Windows, takes a `.mlb` file 70 | and runs it immediately using the SML/NJ environment. 71 | 72 | 73 | Code coverage 74 | ------------- 75 | 76 | The Bash script `mlb-coverage` uses MLton's profile tool to print out 77 | line coverage reports for the files making up a program. Run 78 | 79 | ``` 80 | $ ./mlb-coverage file.mlb 81 | ``` 82 | 83 | to compile and print an overall coverage summary for the program 84 | defined in `file.mlb`, or 85 | 86 | ``` 87 | $ ./mlb-coverage -f sourcefile file.mlb 88 | ``` 89 | 90 | to compile `file.mlb` and print detailed coverage for the single 91 | source file `sourcefile.sml`. 92 | 93 | 94 | Makefile dependency generation 95 | ------------------------------ 96 | 97 | The Bash script `mlb-dependencies` reads a `.mlb` file and prints to 98 | stdout a list of file dependencies in a format suitable to include in 99 | a Makefile. 100 | 101 | 102 | MLB environments 103 | ---------------- 104 | 105 | If a `.mlb` file refers to other `.mlb` files, these scripts simply 106 | interpolate their contents into the parent. This is not the way `.mlb` 107 | files are supposed to work: each new `.mlb` is supposed to be 108 | elaborated into a new empty environment, which is then brought into 109 | the parent environment. 110 | 111 | This difference can cause incompatibilities in both directions: 112 | programs that build with MLton but not with `polybuild`, and also vice 113 | versa. I haven't yet met an incompatibility that couldn't be worked 114 | around though. (I think it is possible to define programs that build 115 | both ways but work differently, although I don't think this is likely 116 | by accident.) Treat your MLton build as definitive. 117 | 118 | 119 | Main function and top-level code 120 | -------------------------------- 121 | 122 | Different compilers have different conventions for the main entry 123 | points they generate in a stand-alone executable. MLton produces an 124 | executable that, when run, invokes any code that was found at the top 125 | level during compilation. The entry point of the executable is 126 | therefore the start of the top-level code. 127 | 128 | Compilers such as Poly/ML, that start from an interactive environment, 129 | usually evaluate top-level code "at compile time" instead. Therefore 130 | Poly/ML expects to find a separate function called "main" that it will 131 | make into the entry point for the executable. 132 | 133 | The convention used by these scripts is that your program will have a 134 | `main.sml` file listed at the bottom of your main `.mlb` file, and 135 | that `main.sml` will simply call out (at the top level) to a main 136 | function that presumably has already been defined in an earlier file 137 | of code. Thus `main.sml` provides the entry point for MLton. 138 | 139 | Then the polybuild script will *remove* any file called `main.sml` 140 | when it compiles for Poly/ML, leaving the main function that this file 141 | would have called as the entry point. 142 | 143 | That is, if you create a file called `main.sml`, containing a line of 144 | code like 145 | 146 | ``` 147 | val () = main () 148 | ``` 149 | 150 | and list that file as the last item in your `.mlb` file, then MLton 151 | will treat this line of code as the entry point for the executable, 152 | and so call `main ()` when the executable is run; while the 153 | `polybuild` script will remove this line, leaving Poly/ML simply 154 | calling `main` function as its entry point as usual. So both will have 155 | the same effect in the end. 156 | 157 | You will still run into differences if you have other top-level code 158 | with side-effects: best to avoid that if you can. 159 | 160 | 161 | Further notes 162 | ------------- 163 | 164 | * [Standard ML and how I'm compiling it](https://thebreakfastpost.com/2015/06/10/standard-ml-and-how-im-compiling-it/) (precursor to this repo) 165 | * [SML and OCaml: So, why was the OCaml faster?](https://thebreakfastpost.com/2015/05/10/sml-and-ocaml-so-why-was-the-ocaml-faster/) (including a quick survey of SML compilers) 166 | 167 | 168 | Author, copyright, and licence 169 | ------------------------------ 170 | 171 | Written by Chris Cannam, copyright 2015-2022. 172 | 173 | These scripts are provided under the MIT licence: 174 | 175 | Permission is hereby granted, free of charge, to any person 176 | obtaining a copy of this software and associated documentation 177 | files (the "Software"), to deal in the Software without 178 | restriction, including without limitation the rights to use, copy, 179 | modify, merge, publish, distribute, sublicense, and/or sell copies 180 | of the Software, and to permit persons to whom the Software is 181 | furnished to do so, subject to the following conditions: 182 | 183 | The above copyright notice and this permission notice shall be 184 | included in all copies or substantial portions of the Software. 185 | 186 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 187 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 188 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 189 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 190 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 191 | CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 192 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 193 | 194 | 195 | -------------------------------------------------------------------------------- /mlb-coverage: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # mlb-coverage - compile and run an SML program defined in a MLB file 4 | # using MLton and print a code coverage report 5 | # 6 | # Chris Cannam, 2015-2018. MIT licence 7 | 8 | logfile=mlb-coverage.log 9 | 10 | usage () { 11 | cat 1>&2 <&2 83 | 84 | set +u # or else bash on osx erroneously (I think?) complains the arrays 85 | # are undefined when they are simply empty 86 | 87 | mlton -profile count -profile-branch true -profile-val true "${mlton_args[@]}" "$PROGRAM.mlb" "${object_args[@]}" 88 | 89 | echo "+++ Executing program $PROGRAM..." 1>&2 90 | 91 | if ./"$PROGRAM" "${program_args[@]}" >"$logfile" ; then 92 | echo "+++ Program completed: stdout is in $logfile" 1>&2 93 | else 94 | echo "--- Program returned exit code $?: stdout is in $logfile" 1>&2 95 | fi 96 | 97 | set -u 98 | 99 | tmpfile=/tmp/"$$"_cov 100 | trap "rm -f $tmpfile" 0 101 | 102 | # Mangle the output of mlprof into a series of lines of the form 103 | # filename,lineno,yes (or no) 104 | # indicating whether the given line of the given file has been 105 | # executed. 106 | 107 | # Mlprof sometimes outputs more than one result for a given source 108 | # line; we want to remove these duplicates because we use the line 109 | # count to calculate our %ages, and also if it outputs both "yes" and 110 | # "no", we want to keep only the "yes". The "sort -r | perl" business 111 | # does that, by sorting on filename and line and then with "yes" 112 | # before "no", and then keeping only the first in any sequence of 113 | # lines with a common filename and line. 114 | 115 | mlprof -raw true -show-line true "$PROGRAM" mlmon.out | 116 | grep '\.sml: [0-9]' | 117 | sed 's|^.* \([A-Za-z][^ ]*\.sml\)|\1|' | 118 | sed 's|: | |' | 119 | awk '{ print $1","$2","$4 }' | 120 | sed 's|(0)|no|g' | 121 | sed 's|([0-9,]*)|yes|g' | 122 | sort -r | 123 | perl -e 'while (<>) { ($f, $n, $b) = split /,/; next if ($f eq $pf and $n eq $pn); print; $pf = $f; $pn = $n }' > "$tmpfile" 124 | 125 | summarise_for() { 126 | what=$(canonicalise "$1") 127 | yes=$(fgrep "$what" "$tmpfile" | grep ",yes$" | wc -l | sed 's/ //g') 128 | no=$(fgrep "$what" "$tmpfile" | grep ",no$" | wc -l | sed 's/ //g') 129 | total=$(($yes + $no)) 130 | if [ "$total" = "0" ]; then 131 | echo " --% $what (0/0)" 132 | else 133 | percent=$(((100 * $yes) / $total)) 134 | if [ "$percent" = 100 ]; then 135 | echo " 100% $what ($yes/$total)" 136 | elif [ "$percent" -lt 10 ]; then 137 | echo " $percent% $what ($yes/$total)" 138 | else 139 | echo " $percent% $what ($yes/$total)" 140 | fi 141 | fi 142 | } 143 | 144 | if [ "$srcfile" = "" ]; then 145 | 146 | summarise_for "sml" 147 | expand_arg -u "$mlb" | grep -v '^/' | grep -v '\.sig$' | LANG=C LC_ALL=C sort | 148 | while read x; do 149 | summarise_for "$x" ; 150 | done 151 | 152 | else 153 | 154 | # A monumentally inefficient way to show the lines lacking 155 | # coverage from a given source file 156 | cat -n "$srcfile" | 157 | sed 's|^ *||' | 158 | while read x; do 159 | n=${x%%[^0-9]*} 160 | if grep -q "$srcfile,$n,no" "$tmpfile" ; 161 | then echo " ### $x"; 162 | else echo " $x"; 163 | fi; 164 | done | \ 165 | grep -C2 '^ ###' 166 | fi 167 | 168 | -------------------------------------------------------------------------------- /mlb-dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # mlb-dependencies - read a MLB file defining an SML program and print 4 | # out a dependency list in Makefile format 5 | # 6 | # Chris Cannam, 2015-2022. MIT licence 7 | 8 | set -e 9 | 10 | arg="$1" 11 | 12 | if [ -z "$arg" ]; then 13 | echo "Usage: $0 file.sml" 1>&2 14 | echo " $0 file.mlb" 1>&2 15 | exit 2 16 | fi 17 | 18 | set -u 19 | 20 | mydir=$(dirname "$0") 21 | . "$mydir/smlbuild-include.sh" 22 | 23 | base=$(get_outfile "$arg") 24 | 25 | # I wanted to pipe this through fmt, but that turned out to produce 26 | # slightly different results between GNU and BSD (/ Mac) tools and 27 | # resolving the distinction (in order to keep regression tests passing 28 | # across platforms) was too much of a faff for a small aesthetic gain 29 | 30 | expand_arg -u "$arg" | sed 's|^|'"$base"': |' 31 | 32 | -------------------------------------------------------------------------------- /mlb-dependencies.ps1: -------------------------------------------------------------------------------- 1 | 2 | Set-StrictMode -Version 2.0 3 | $ErrorActionPreference = "Stop" 4 | 5 | if ($args.Count -ne 1) { 6 | "Usage: mlb-dependencies file.mlb" 7 | exit 1 8 | } 9 | 10 | $mlb = $args[0] 11 | 12 | if ($mlb -notmatch "[.]mlb$") { 13 | "Error: argument must be a .mlb file" 14 | exit 1 15 | } 16 | 17 | $mydir = Split-Path -Parent $PSCommandPath 18 | 19 | . $mydir/smlbuild-include.ps1 20 | 21 | $lines = @(listMLB $mlb) 22 | 23 | if ($lines -match "^Error: ") { 24 | $lines -match "^Error: " 25 | exit 1 26 | } 27 | 28 | $target = $mlb -replace "[.]mlb$",".exe" 29 | 30 | if (!([System.IO.Path]::IsPathRooted($target))) { 31 | $target = (Join-Path $mydir $target) 32 | } 33 | 34 | foreach ($line in $lines) { 35 | "${target}: $line" 36 | } 37 | 38 | -------------------------------------------------------------------------------- /mlb-expand: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # mlb-dependencies - read a MLB file defining an SML program and print 4 | # out a list of the files referred to by it and any subsidiary MLB files 5 | # 6 | # Chris Cannam, 2015-2022. MIT licence 7 | 8 | set -e 9 | 10 | unique=no 11 | if [ "$1" = "-u" ]; then 12 | unique=yes 13 | shift 14 | fi 15 | 16 | arg="$1" 17 | 18 | if [ -z "$arg" ]; then 19 | echo "Usage: $0 [-u] file.mlb" 1>&2 20 | echo " where" 1>&2 21 | echo " -u: List each file only the first time it appears (unique list)" 1>&2 22 | exit 2 23 | fi 24 | 25 | set -u 26 | 27 | mydir=$(dirname "$0") 28 | . "$mydir/smlbuild-include.sh" 29 | 30 | base=$(get_outfile "$arg") 31 | 32 | if [ "$unique" = "yes" ]; then 33 | expand_arg -u "$arg" 34 | else 35 | expand_arg "$arg" 36 | fi 37 | 38 | -------------------------------------------------------------------------------- /mlton.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set args=%* 3 | "C:\msys64\usr\bin\bash.exe" -x -c 'export PATH=/usr/bin:/mingw64/bin:$PATH ; /c/mlton-20201002-1.amd64-mingw-gmp-dynamic/bin/mlton %args%' 4 | -------------------------------------------------------------------------------- /polybuild: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # polybuild - compile a SML program defined in a MLB file using Poly/ML 4 | # 5 | # Chris Cannam, 2015-2022. MIT licence 6 | 7 | set -e 8 | 9 | usage() { 10 | me=$(basename "$0") 11 | echo 1>&2 12 | echo "$me: Compile a SML program defined in a MLB file using Poly/ML" 1>&2 13 | echo 1>&2 14 | echo "Usage: $me [-o output] file.sml" 1>&2 15 | echo " $me [-u] [-o output] file.mlb" 1>&2 16 | echo " where" 1>&2 17 | echo " -u: Unique: \"use\" each file only once, regardless of how many times it" 1>&2 18 | echo " appears in the MLB file and its dependencies. The default is to use" 1>&2 19 | echo " a file again each time it appears." 1>&2 20 | echo " Neither mode complies with the official interpretation for MLB files" 1>&2 21 | echo " in this respect (that's much harder to do). Both modes may compile" 1>&2 22 | echo " code that the other mode does not!" 1>&2 23 | echo " Unique mode is usually faster and is never much slower." 1>&2 24 | echo 1>&2 25 | echo "This script is not part of Poly/ML and has no official status." 1>&2 26 | echo "Written by Chris Cannam, 2015-2022." 1>&2 27 | echo 1>&2 28 | exit 2 29 | } 30 | 31 | unique_arg="" 32 | if [ "$1" = "-u" ]; then 33 | unique_arg="-u" 34 | shift 35 | fi 36 | 37 | arg="$1" 38 | 39 | [ -n "$arg" ] || usage 40 | 41 | out="" 42 | if [ t"$arg" = "t-o" ]; then 43 | shift 44 | out="$1" 45 | [ -n "$out" ] || usage 46 | shift 47 | arg="$1" 48 | [ -n "$arg" ] || usage 49 | fi 50 | 51 | shift 52 | set -u 53 | 54 | mydir=$(dirname "$0") 55 | 56 | . "$mydir/smlbuild-include.sh" 57 | 58 | if [ -z "$out" ]; then 59 | out=$(get_outfile "$arg") 60 | fi 61 | 62 | tmpobj=$(get_tmpobjfile "$arg") 63 | 64 | trap "rm -f ${tmpobj}" 0 65 | 66 | ( expand_arg $unique_arg "$arg" | 67 | sed 's|^\(.*\)$|use "\1";|' ; # wrap filenames in REPL use calls 68 | echo 'PolyML.export("'"$tmpobj"'", main);' ) | # ask poly to export object file 69 | poly -q --error-exit && 70 | polyc -o "$out" "$tmpobj" # compile object to executable 71 | 72 | -------------------------------------------------------------------------------- /polybuild.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set args=%* 3 | PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& %~dpn0.ps1 %args%" 4 | -------------------------------------------------------------------------------- /polybuild.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | 4 | .SYNOPSIS 5 | Use Poly/ML to compile a Standard ML program defined in a .mlb file 6 | 7 | .EXAMPLE 8 | polybuild example.mlb 9 | Compile the Standard ML program defined in example.mlb using Poly/ML. 10 | 11 | The environment variable POLY_DIR must be set to a directory 12 | containing the Poly/ML library files (PolyLib.lib, PolyLib.dll, 13 | PolyMainLib.lib) and executable (PolyML.exe), and the clang compiler 14 | must be in the path, for example because we are running in a 15 | sufficiently recent Visual Studio command prompt with clang support. 16 | 17 | #> 18 | 19 | 20 | # NB just installing Poly/ML for Windows is not enough to get the 21 | # Poly/ML libraries, because the export libraries such as PolyLib.lib 22 | # are not included in the installation. 23 | # 24 | # To build them, check out Poly/ML from git or whatever, then go to 25 | # its repo in a VC command prompt and 26 | # 27 | # > msbuild polyml.sln /p:Configuration=Release '/t:PolyLib;PolyML;PolyMainLib' 28 | # 29 | # then set the x64\Release subdir of the Poly/ML dir as $env:POLY_DIR. 30 | # 31 | # You will also need to ensure PolyLib.dll is available at runtime 32 | # (e.g. in the same place as your executable). 33 | 34 | 35 | Set-StrictMode -Version 2.0 36 | $ErrorActionPreference = "Stop" 37 | 38 | if ($args.Count -lt 1) { 39 | "Usage: polybuild [-o output.exe] file.mlb" 40 | exit 1 41 | } 42 | 43 | if ($args[0] -eq "-o") { 44 | 45 | $output_file = $args[1] 46 | $mlb = $args[2] 47 | 48 | } else { 49 | 50 | $mlb = $args[0] 51 | 52 | $output_file = $mlb -replace ".mlb","" 53 | $output_file = "$output_file.exe" 54 | } 55 | 56 | if ($mlb -notmatch "[.]mlb$") { 57 | "Error: argument must be a .mlb file" 58 | exit 1 59 | } 60 | 61 | $poly_libdir = $env:POLY_DIR 62 | 63 | if (! $poly_libdir -or ! (Test-Path -PathType Container $poly_libdir)) { 64 | "Error: POLY_DIR environment variable must be set to a valid directory" 65 | exit 1 66 | } 67 | 68 | "Poly/ML libdir is $poly_libdir" 69 | 70 | $mydir = Split-Path -Parent $PSCommandPath 71 | 72 | . $mydir/smlbuild-include.ps1 73 | 74 | $lines = @(processMLB $mlb) 75 | 76 | if ($lines -match "^Error: ") { 77 | $lines -match "^Error: " 78 | exit 1 79 | } 80 | 81 | $tmpfile_in = ([System.IO.Path]::GetTempFileName()) -replace "[.]tmp",".sml" 82 | $tmpfile_out = ([System.IO.Path]::GetTempFileName()) -replace "[.]tmp",".obj" 83 | 84 | $outro = @" 85 | val _ = PolyML.export("$tmpfile_out", main); 86 | val _ = OS.Process.exit (OS.Process.success); 87 | "@ -split "[\r\n]+" 88 | 89 | $script = @() 90 | $script += $lines 91 | $script += $outro 92 | 93 | $script -replace "\\","\\" | Out-File -Encoding "ASCII" $tmpfile_in 94 | 95 | $polyml = "$poly_libdir\polyml" 96 | 97 | cat $tmpfile_in | & $polyml -q --error-exit | Out-Host 98 | 99 | if (-not $?) { 100 | del $tmpfile_in 101 | if (Test-Path $tmpfile_out) { 102 | del $tmpfile_out 103 | } 104 | exit $LastExitCode 105 | } 106 | 107 | del $tmpfile_in 108 | 109 | clang -O3 $tmpfile_out -o $output_file -Xlinker /subsystem:console -Xlinker /entry:WinMainCRTStartup -Xlinker /ltcg -L"$poly_libdir" -lPolyLib -lPolyMainLib 110 | 111 | if (-not $?) { 112 | del $tmpfile_out 113 | exit $LastExitCode 114 | } 115 | 116 | del $tmpfile_out 117 | -------------------------------------------------------------------------------- /polyrepl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # polyrepl - load a SML program defined in a MLB file into the Poly/ML 4 | # interactive environment 5 | # 6 | # Chris Cannam, 2015-2022. MIT licence 7 | 8 | set -e 9 | 10 | usage() { 11 | me=$(basename "$0") 12 | echo 1>&2 13 | echo "$me: Load a SML program defined in a MLB file into the Poly/ML repl" 1>&2 14 | echo 1>&2 15 | echo "Usage: $me [-d] file.sml" 1>&2 16 | echo " $me [-u] [-d] file.mlb" 1>&2 17 | echo "where" 1>&2 18 | echo " -u: Unique: \"use\" each file only once, regardless of how many times it" 1>&2 19 | echo " appears in the MLB file. See \"polybuild\" for discussion." 1>&2 20 | echo " -d: Enable Poly/ML compiler debug mode before reading SML source." 1>&2 21 | echo 1>&2 22 | exit 2 23 | } 24 | 25 | unique_arg="" 26 | if [ "$1" = "-u" ]; then 27 | unique_arg="-u" 28 | shift 29 | fi 30 | 31 | debug=no 32 | if [ "$1" = "-d" ]; then 33 | debug=yes 34 | shift 35 | fi 36 | 37 | arg="$1" 38 | 39 | if [ -z "$arg" ]; then 40 | usage 41 | fi 42 | 43 | shift 44 | set -u 45 | 46 | mydir=$(dirname "$0") 47 | . "$mydir/smlbuild-include.sh" 48 | 49 | out=$(get_outfile "$arg") # we don't use this, but it does some arg error checking 50 | 51 | if rlwrap -v >/dev/null 2>&1 ; then 52 | rlwrap=rlwrap 53 | else 54 | rlwrap= 55 | fi 56 | 57 | if [ "$debug" = "yes" ]; then 58 | $rlwrap poly --eval 'PolyML.Compiler.debug := true;' $(expand_arg $unique_arg "$arg" | sed 's/^\(.*\)$/--use \1/') --eval '"Entering trace mode; evaluate `PolyML.Debug.trace false` to leave";' --eval 'PolyML.Debug.trace true;' 59 | else 60 | $rlwrap poly $(expand_arg -u "$arg" | sed 's/^\(.*\)$/--use \1/') 61 | fi 62 | 63 | 64 | -------------------------------------------------------------------------------- /polyrun: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # polyrun - run a SML program defined in a SML or MLB file using Poly/ML 4 | # 5 | # Chris Cannam, 2015-2018. MIT licence 6 | 7 | set -e 8 | 9 | usage() { 10 | me=$(basename "$0") 11 | echo 1>&2 12 | echo "$me: Run a SML program defined in a MLB file using Poly/ML" 1>&2 13 | echo 1>&2 14 | echo "Usage: $me file.sml" 1>&2 15 | echo " $me [-u] file.mlb" 1>&2 16 | echo 1>&2 17 | echo "where" 1>&2 18 | echo " -u: Unique: \"use\" each file only once, regardless of how many times it" 1>&2 19 | echo " appears in the MLB file. See \"polybuild\" for discussion." 1>&2 20 | echo 1>&2 21 | exit 2 22 | } 23 | 24 | unique_arg="" 25 | if [ "$1" = "-u" ]; then 26 | unique_arg="-u" 27 | shift 28 | fi 29 | 30 | arg="$1" 31 | 32 | if [ -z "$arg" ]; then 33 | usage 34 | fi 35 | 36 | shift 37 | set -u 38 | 39 | mydir=$(dirname "$0") 40 | . "$mydir/smlbuild-include.sh" 41 | 42 | out=$(get_outfile "$arg") 43 | tmpobj=$(get_tmpobjfile "$arg") 44 | tmpout=$(get_tmpfile "$arg") 45 | trap "rm -f ${tmpobj} ${tmpout}" 0 46 | 47 | ( expand_arg $unique_arg "$arg" | \ 48 | sed 's|^\(.*\)$|use "\1";|' ; 49 | echo 'PolyML.export("'"$tmpobj"'", main);' ) | \ 50 | poly -q --error-exit && 51 | polyc -o "$tmpout" "$tmpobj" && 52 | "$tmpout" "$@" 53 | 54 | -------------------------------------------------------------------------------- /polyrun.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | 4 | .SYNOPSIS 5 | Use Poly/ML to run a Standard ML program defined in a .mlb file 6 | 7 | .EXAMPLE 8 | polyrun example.mlb datafile.txt 9 | Run the Standard ML program defined in example.mlb using Poly/ML, passing datafile.txt as an argument to the program 10 | 11 | #> 12 | 13 | Set-StrictMode -Version 2.0 14 | $ErrorActionPreference = "Stop" 15 | 16 | if ($args.Count -lt 1) { 17 | "Usage: polyrun file.mlb [args...]" 18 | exit 1 19 | } 20 | 21 | $mlb = $args[0] 22 | 23 | if ($mlb -notmatch "[.]mlb$") { 24 | "Error: argument must be a .mlb file" 25 | exit 1 26 | } 27 | 28 | $mydir = Split-Path -Parent $PSCommandPath 29 | 30 | . $mydir/smlbuild-include.ps1 31 | 32 | $lines = @(processMLB $mlb) 33 | 34 | if ($lines -match "^Error: ") { 35 | $lines -match "^Error: " 36 | exit 1 37 | } 38 | 39 | $outro = @" 40 | val _ = main (); 41 | val _ = OS.Process.exit (OS.Process.success); 42 | "@ -split "[\r\n]+" 43 | 44 | $script = @() 45 | $script += $lines 46 | $script += $outro 47 | 48 | $tmpfile = ([System.IO.Path]::GetTempFileName()) -replace "[.]tmp",".sml" 49 | 50 | $script | Out-File -Encoding "ASCII" $tmpfile 51 | 52 | cat $tmpfile | polyml --error-exit $args[1..$args.Length] | Out-Host 53 | 54 | if (-not $?) { 55 | del $tmpfile 56 | exit $LastExitCode 57 | } 58 | 59 | del $tmpfile 60 | 61 | -------------------------------------------------------------------------------- /smlbuild-include.ps1: -------------------------------------------------------------------------------- 1 | 2 | $libdir = "C:\mlton-20201002-1.amd64-mingw-gmp-dynamic\lib\mlton\sml" 3 | 4 | #$mlton = (Get-Command mlton -ErrorAction SilentlyContinue).Path 5 | #if ($mlton -ne "") { 6 | # $libdir = "$mlton\..\lib\mlton\sml" 7 | #} 8 | 9 | $libdir = $libdir -Replace "\\","/" 10 | 11 | "Using ""$libdir"" as SML_LIB path" 12 | 13 | function script:listMLB($m) { 14 | 15 | if (! (Test-Path $m)) { 16 | "Error: file not found: " + $m 17 | return 18 | } 19 | 20 | $lines = @(Get-Content $m) 21 | 22 | # remove incompatible Basis lib, MLton lib, and unneeded call to main 23 | $lines = $lines -notmatch "basis[.]mlb" -notmatch "mlton[.]mlb" -notmatch "main[.]sml" 24 | 25 | # remove ML-style comments 26 | $lines = $lines -replace "\(\*[^\*]*\*\)","" 27 | 28 | # expand library path 29 | $lines = $lines -replace "\$\(SML_LIB\)",$libdir 30 | 31 | # remove leading whitespace 32 | $lines = $lines -replace "^ *","" 33 | 34 | # remove trailing whitespace 35 | $lines = $lines -replace " *$","" 36 | 37 | # remove empty lines 38 | $lines = $lines -notmatch "^$" 39 | 40 | # remove lines with double-quotes in them, e.g. annotation 41 | $lines = $lines -notmatch """" 42 | 43 | $expanded = @() 44 | 45 | foreach ($line in $lines) { 46 | 47 | $path = $line 48 | 49 | if (!([System.IO.Path]::IsPathRooted($path))) { 50 | if (Split-Path -parent $m) { 51 | # resolve path relative to containing mlb file 52 | $path = (Join-Path (Split-Path -parent $m) $path) 53 | } 54 | } 55 | 56 | if ($path -match "[.]mlb$") { 57 | 58 | # recurse to expand included mlb 59 | $expanded += @(listMLB $path) 60 | 61 | } elseif ($path -match "[.](sml|sig)$") { 62 | 63 | # use forward slashes for path separators 64 | $path = $path -replace "\\","/" 65 | 66 | $expanded += $path 67 | 68 | } else { 69 | Write-Warning "*** Warning: unsupported syntax or file in ${m}: ${line}" 70 | } 71 | } 72 | 73 | $expanded 74 | } 75 | 76 | function script:processMLB($m) { 77 | 78 | $lines = @(listMLB $mlb) 79 | 80 | if ($lines -match "^Error: ") { 81 | $lines -match "^Error: " 82 | } else { 83 | 84 | $expanded = @() 85 | 86 | foreach ($line in $lines) { 87 | 88 | $path = $line 89 | 90 | # add use declaration 91 | $path = $path -replace "^(.*)$",'use "$1";' 92 | 93 | $expanded += $path 94 | } 95 | 96 | $expanded 97 | } 98 | } 99 | 100 | 101 | -------------------------------------------------------------------------------- /smlbuild-include.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Chris Cannam, 2015-2022. MIT licence 4 | 5 | # Disable shellcheck warnings for useless-use-of-cat. UUOC is good 6 | # practice, not bad: clearer, safer, less error-prone. 7 | # shellcheck disable=SC2002 8 | 9 | internal_debug=no 10 | 11 | if [ -z "${SML_LIB:-}" ]; then 12 | lib=/usr/lib/mlton/sml 13 | if [ ! -d "$lib" ]; then 14 | lib=/usr/local/lib/mlton/sml 15 | fi 16 | else 17 | lib="$SML_LIB" 18 | fi 19 | 20 | canonicalise() { 21 | local pre="$1" 22 | local post="" 23 | while [ "$pre" != "$post" ]; do 24 | if [ -z "$post" ]; then post="$pre"; else pre="$post"; fi 25 | post=$(echo "$post" | sed -e 's|[^/.][^/.]*/\.\./||g') 26 | done 27 | echo "$post" | sed -e 's|^./||' -e 's|//|/|g' 28 | } 29 | 30 | simplify() { 31 | local path="$1" 32 | simple=$(canonicalise "$path") 33 | if [ "$internal_debug" = "yes" ]; then 34 | echo "simplified \"$path\" to \"$simple\"" 1>&2 35 | fi 36 | if [ ! -f "$simple" ]; then 37 | echo "*** Error: input file \"$simple\" not found" 1>&2 38 | exit 1 39 | fi 40 | echo "$simple" 41 | } 42 | 43 | cat_mlb() { 44 | local mlb 45 | mlb=$(canonicalise "$1") 46 | if [ ! -f "$mlb" ]; then exit 1; fi 47 | local dir 48 | dir=$(dirname "$mlb") 49 | if [ "$internal_debug" = "yes" ]; then 50 | echo "reading MLB file \"$mlb\":" 1>&2 51 | fi 52 | cat "$mlb" | while read -r line; do 53 | if [ "$internal_debug" = "yes" ]; then 54 | echo "read line \"$line\":" 1>&2 55 | fi 56 | local trimmed 57 | # remove leading and trailing whitespace 58 | trimmed="${line#"${line%%[![:space:]]*}"}" 59 | trimmed="${trimmed%"${trimmed##*[![:space:]]}"}" 60 | case "$trimmed" in 61 | # check for ML-style comments or variable sigils; only 62 | # launch a further substitution if we see any 63 | *[\($]*) 64 | # Tell shellcheck that the $-variables in 65 | # single-quotes are not intended for bash to expand 66 | # shellcheck disable=SC2016 67 | trimmed=$( 68 | echo "$trimmed" | 69 | # remove ML-style comments; expand library path 70 | sed -e 's|(\*.*\*)||' -e 's#$(SML_LIB)#'"${lib}"'#g' | 71 | # expand other vars: 72 | perl -p -e 's|\$\(([A-Za-z_-]+)\)|$ENV{$1}|' 73 | ) 74 | ;; 75 | *) ;; 76 | esac 77 | local path="$trimmed" 78 | case "$path" in 79 | "") ;; # keep empty lines for ignoring later 80 | /*) ;; 81 | *) path="$dir/$trimmed" ;; 82 | esac 83 | case "$path" in 84 | "") ;; # ignore empty lines 85 | *basis.mlb) ;; # remove incompatible Basis lib 86 | *mlton.mlb) ;; # remove incompatible MLton lib 87 | *main.sml) ;; # remove redundant call to main 88 | *.mlb) cat_mlb "$path" ;; 89 | *.sml) simplify "$path" ;; 90 | *.sig) simplify "$path" ;; 91 | *) echo "*** Warning: unsupported syntax or file in $mlb: $trimmed" 1>&2 92 | esac 93 | done 94 | if [ "$internal_debug" = "yes" ]; then 95 | echo "finished reading MLB file \"$mlb\"" 1>&2 96 | fi 97 | } 98 | 99 | expand_arg() { 100 | local arg="$1" 101 | local unique="no" 102 | case "$arg" in 103 | "-u") unique=yes 104 | shift 105 | arg="$1" ;; 106 | *) ;; 107 | esac 108 | case "$arg" in 109 | *.sml) echo "$arg" ;; 110 | *.mlb) cat_mlb "$arg" ;; 111 | *) echo "*** Error: .sml or .mlb file must be provided" 1>&2 112 | exit 1 ;; 113 | esac | ( 114 | if [ "$unique" = "yes" ]; then 115 | cat -n | sort -k 2 -u | sort -n | awk '{ print $2; }' 116 | else 117 | cat 118 | fi 119 | ) 120 | } 121 | 122 | get_base() { 123 | local arg="$1" 124 | case "$arg" in 125 | *.sml) basename "$arg" .sml ;; 126 | *.mlb) basename "$arg" .mlb ;; 127 | *) echo "*** Error: .sml or .mlb file must be provided" 1>&2 128 | exit 1 ;; 129 | esac 130 | } 131 | 132 | get_outfile() { 133 | local arg="$1" 134 | canonicalise $(dirname "$arg")/$(get_base "$arg") 135 | } 136 | 137 | get_tmpfile() { 138 | local arg="$1" 139 | mktemp /tmp/smlbuild-$(get_base "$arg")-XXXXXXXX 140 | } 141 | 142 | get_tmpsmlfile() { 143 | local arg="$1" 144 | mktemp /tmp/smlbuild-$(get_base "$arg")-XXXXXXXX.sml 145 | } 146 | 147 | get_tmpobjfile() { 148 | local arg="$1" 149 | mktemp /tmp/smlbuild-$(get_base "$arg")-XXXXXXXX.o 150 | } 151 | 152 | 153 | -------------------------------------------------------------------------------- /smlrepl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # smlrepl - load a SML program defined in a MLB file into the SML/NJ 4 | # interactive environment 5 | # 6 | # Chris Cannam, 2015-2022. MIT licence 7 | 8 | set -e 9 | 10 | usage() { 11 | me=$(basename "$0") 12 | echo 1>&2 13 | echo "$me: Load a SML program defined in a MLB file into the SML/NJ repl" 1>&2 14 | echo 1>&2 15 | echo "Usage: $me file.sml" 1>&2 16 | echo " $me [-u] file.mlb" 1>&2 17 | echo "where" 1>&2 18 | echo " -u: Unique: \"use\" each file only once, regardless of how many times it" 1>&2 19 | echo " appears in the MLB file. See \"polybuild\" for discussion." 1>&2 20 | echo 1>&2 21 | exit 2 22 | } 23 | 24 | if echo | sml | grep -q Jersey ; then : 25 | else 26 | echo "*** Error: SML/NJ binary 'sml' not in path" 1>&2 27 | exit 1 28 | fi 29 | 30 | unique_arg="" 31 | if [ "$1" = "-u" ]; then 32 | unique_arg="-u" 33 | shift 34 | fi 35 | 36 | arg="$1" 37 | 38 | if [ -z "$arg" ]; then 39 | usage 40 | fi 41 | 42 | shift 43 | set -u 44 | 45 | mydir=$(dirname "$0") 46 | . "$mydir/smlbuild-include.sh" 47 | 48 | out=$(get_outfile "$arg") 49 | tmpout=$(get_tmpsmlfile "$arg") 50 | 51 | trap "rm -f ${tmpout}" 0 52 | 53 | expand_arg $unique_arg "$arg" | \ 54 | sed 's/^\(.*\)$/use "\1";/' > \ 55 | "$tmpout" 56 | 57 | rlwrap sml "$tmpout" "$@" 58 | 59 | -------------------------------------------------------------------------------- /smlrun: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # smlrun - run a SML program defined in a SML or MLB file using SML/NJ 4 | # 5 | # Chris Cannam, 2015-2022. MIT licence 6 | 7 | set -e 8 | 9 | usage() { 10 | me=$(basename "$0") 11 | echo 1>&2 12 | echo "$me: Run a SML program defined in a MLB file using SML/NJ" 1>&2 13 | echo 1>&2 14 | echo "Usage: $me [-v] file.sml" 1>&2 15 | echo " $me [-u] [-v] file.mlb" 1>&2 16 | echo "where" 1>&2 17 | echo " -u: Unique: \"use\" each file only once, regardless of how many times it" 1>&2 18 | echo " appears in the MLB file. See \"polybuild\" for discussion." 1>&2 19 | echo " -v: Verbose: Do not suppress output from interactive environment." 1>&2 20 | echo 1>&2 21 | exit 2 22 | } 23 | 24 | if echo | sml | grep -q Jersey ; then : 25 | else 26 | echo "*** Error: SML/NJ binary 'sml' not in path" 1>&2 27 | exit 1 28 | fi 29 | 30 | unique_arg="" 31 | if [ "$1" = "-u" ]; then 32 | unique_arg="-u" 33 | shift 34 | fi 35 | 36 | verbose=no 37 | if [ "$1" = "-v" ]; then 38 | verbose=yes 39 | shift 40 | fi 41 | 42 | arg="$1" 43 | 44 | if [ -z "$arg" ]; then 45 | usage 46 | fi 47 | 48 | shift 49 | set -u 50 | 51 | mydir=$(dirname "$0") 52 | . "$mydir/smlbuild-include.sh" 53 | 54 | out=$(get_outfile "$arg") 55 | tmpout=$(get_tmpsmlfile "$arg") 56 | 57 | trap "rm -f ${tmpout}" 0 58 | 59 | case "$verbose" in 60 | yes) 61 | expand_arg -u "$arg" | \ 62 | sed 's/^\(.*\)$/use "\1";/' | # wrap filenames in REPL use calls 63 | ( 64 | cat - 65 | cat < "$tmpout" 70 | 71 | sml "$tmpout" "$@" 72 | ;; 73 | 74 | no) 75 | expand_arg -u "$arg" | \ 76 | sed 's/^\(.*\)$/use "\1";/' | # wrap filenames in REPL use calls 77 | ( 78 | cat < (), flush = fn () => () }; 82 | x 83 | end; 84 | val smlrun__prev = ref ""; 85 | Control.Print.out := { 86 | say = fn s => 87 | (if String.isSubstring " Error" s orelse String.isSubstring "failed: " s 88 | then (Control.Print.out := smlrun__cp; 89 | (#say smlrun__cp) (!smlrun__prev); 90 | (#say smlrun__cp) s) 91 | else (smlrun__prev := s; ())), 92 | flush = fn s => () 93 | }; 94 | EOF 95 | cat - 96 | cat < "$tmpout" 102 | 103 | CM_VERBOSE=false sml "$tmpout" "$@" | tail -n +3 104 | ;; 105 | esac 106 | 107 | 108 | -------------------------------------------------------------------------------- /smlrun.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | 4 | .SYNOPSIS 5 | Use SML/NJ to run a Standard ML program defined in a .mlb file 6 | 7 | .EXAMPLE 8 | smlrun example.mlb datafile.txt 9 | Run the Standard ML program defined in example.mlb using SML/NJ, passing datafile.txt as an argument to the program 10 | 11 | #> 12 | 13 | Set-StrictMode -Version 2.0 14 | $ErrorActionPreference = "Stop" 15 | 16 | if ($args.Count -lt 1) { 17 | "Usage: smlrun file.mlb [args...]" 18 | exit 1 19 | } 20 | 21 | $mlb = $args[0] 22 | 23 | if ($mlb -notmatch "[.]mlb$") { 24 | "Error: argument must be a .mlb file" 25 | exit 1 26 | } 27 | 28 | $mydir = Split-Path -Parent $PSCommandPath 29 | 30 | . $mydir/smlbuild-include.ps1 31 | 32 | $lines = @(processMLB $mlb) 33 | 34 | if ($lines -match "^Error: ") { 35 | $lines -match "^Error: " 36 | exit 1 37 | } 38 | 39 | $intro = @" 40 | val smlrun__cp = 41 | let val x = !Control.Print.out in 42 | Control.Print.out := { say = fn _ => (), flush = fn () => () }; 43 | x 44 | end; 45 | val smlrun__prev = ref ""; 46 | Control.Print.out := { 47 | say = fn s => 48 | (if String.isSubstring " Error" s orelse String.isSubstring "failed: " s 49 | then (Control.Print.out := smlrun__cp; 50 | (#say smlrun__cp) (!smlrun__prev); 51 | (#say smlrun__cp) s) 52 | else (smlrun__prev := s; ())), 53 | flush = fn s => () 54 | }; 55 | "@ -split "[\r\n]+" 56 | 57 | $outro = @" 58 | val _ = main (); 59 | val _ = OS.Process.exit (OS.Process.success); 60 | "@ -split "[\r\n]+" 61 | 62 | $script = @() 63 | $script += $intro 64 | $script += $lines 65 | $script += $outro 66 | 67 | $tmpfile = ([System.IO.Path]::GetTempFileName()) -replace "[.]tmp",".sml" 68 | 69 | $script | Out-File -Encoding "ASCII" $tmpfile 70 | 71 | $env:CM_VERBOSE="false" 72 | 73 | $input | sml $tmpfile $args[1..$args.Length] 74 | 75 | if (-not $?) { 76 | del $tmpfile 77 | exit $LastExitCode 78 | } 79 | 80 | del $tmpfile 81 | 82 | -------------------------------------------------------------------------------- /test/main.sml: -------------------------------------------------------------------------------- 1 | val () = main () 2 | -------------------------------------------------------------------------------- /test/regression/annotate.txt: -------------------------------------------------------------------------------- 1 | 33 | INSTANCE of int option 2 | 34 3 | ### 35 fun locOf wher = 4 | ### 36 case wher 5 | ### 37 of PROLOG => LOC_PROLOG 6 | ### 38 | INSTANCE _ => LOC_PROLOG 7 | ### 39 | EPILOG => LOC_EPILOG 8 | 40 9 | 41 fun checkRoot dtd (a,q) (doc,stag as ((_,elem,_,_,_),_)) = 10 | 42 if !O_VALIDATE 11 | ### 43 then case doc 12 | ### 44 of NONE => a 13 | 45 | SOME doc => 14 | ### 46 if doc=elem then a 15 | ### 47 else let val err = ERR_ROOT_ELEM(Index2Element dtd doc, 16 | 48 Index2Element dtd elem) 17 | 49 in hookError(a,(getPos q,err)) 18 | -- 19 | 57 case c 20 | 58 of 0wx00 => (ws,(c,a,q)) 21 | ### 59 | 0wx26 (* #"&" *) => (ws,(c,a,q)) 22 | 60 | 0wx3C (* #"<" *) => (ws,(c,a,q)) 23 | ### 61 | 0wx09 (* #"t"*) => doit hadError (c::ws) (getChar(a,q)) 24 | 62 | 0wx0A (* #"n"*) => doit hadError (c::ws) (getChar(a,q)) 25 | ### 63 | 0wx20 (* #" " *) => doit hadError (c::ws) (getChar(a,q)) 26 | ### 64 | _ => let val a1 = if hadError then a 27 | ### 65 else hookError(a,(getPos q,ERR_FORBIDDEN_HERE 28 | 66 (IT_DATA nil,locOf wher))) 29 | 67 in doit true ws (getChar(a1,q)) 30 | -- 31 | 77 case c 32 | 78 of 0wx2D (* #"-" *) => 33 | ### 79 let val (c1,a1,q1) = getChar(a,q) 34 | ### 80 in if c1=0wx2D then (wher,parseComment (getPos q0) (a1,q1)) 35 | ### 81 else let val err = ERR_EXPECTED(expDash,[c1]) 36 | ### 82 val a2 = hookError(a1,(getPos q1,err)) 37 | ### 83 val caq2 = recoverDecl false (c1,a2,q1) 38 | 84 in (wher,caq2) 39 | 85 end 40 | 86 end 41 | 87 | 0wx5B (* #"[" *) => 42 | ### 88 let 43 | ### 89 val err = ERR_FORBIDDEN_HERE (IT_CDATA,locOf wher) 44 | ### 90 val a1 = hookError(a,(getPos q0,err)) 45 | ### 91 val caq2 = skipBadSection (getChar(a1,q)) 46 | 92 in (wher,caq2) 47 | 93 end 48 | -- 49 | 97 (let val (name,(c1,a1,q1)) = parseName (c,a,q) 50 | 98 handle NotFound (c,a,q) => 51 | ### 99 let val err = expectedOrEnded(expDashDocLbrk,LOC_DECL) c 52 | 100 in raise SyntaxError (c,hookError(a,(getPos q,err)),q) 53 | 101 end 54 | -- 55 | 103 val _ = if name=[0wx44,0wx4f,0wx43,0wx54,0wx59,0wx50,0wx45] 56 | 104 (* "DOCTYPE" *) then () 57 | ### 105 else let val err = ERR_EXPECTED(expDashDocLbrk,name) 58 | ### 106 val a2 = hookError(a1,(getPos q,err)) 59 | 107 in raise SyntaxError (c1,a2,q1) 60 | 108 end 61 | -- 62 | 111 in (INSTANCE doc,caq2) 63 | 112 end 64 | ### 113 handle SyntaxError caq => (PROLOG,recoverDecl true caq)) 65 | 114 66 | ### 115 | _ => let val loc = if wher=EPILOG then LOC_EPILOG else LOC_AFTER_DTD 67 | 116 val err = ERR_FORBIDDEN_HERE (IT_DECL,loc) 68 | ### 117 val a1 = hookError(a,(getPos q0,err)) 69 | ### 118 val caq2 = skipDecl true (c,a1,q) 70 | 119 in (wher,caq2) 71 | 120 end 72 | -- 73 | 123 case c 74 | 124 of 0wx00 => if isSpecial q then (wher,(a,q)) 75 | ### 125 else doit wher (getChar(a,q)) 76 | 126 (*--------------------------------------------------------------*) 77 | 127 (* References are forbidden outside the document element *) 78 | 128 (*--------------------------------------------------------------*) 79 | 129 | 0wx26 (* #"&" *) => 80 | ### 130 let 81 | ### 131 val (c1,a1,q1) = getChar(a,q) 82 | 132 val caq2 = 83 | ### 133 if c1=0wx23 (* #"#" *) 84 | ### 134 then let val err = ERR_FORBIDDEN_HERE(IT_CHAR_REF,locOf wher) 85 | ### 135 val a2 = hookError(a1,(getPos q,err)) 86 | 136 in skipCharRef (a2,q1) 87 | 137 end 88 | ### 138 else let val err = ERR_FORBIDDEN_HERE(IT_REF,locOf wher) 89 | ### 139 val a2 = hookError(a1,(getPos q,err)) 90 | 140 in skipReference (c1,a2,q1) 91 | 141 end 92 | -- 93 | 150 end 94 | 151 | 0wx2F (* #"/" *) => 95 | ### 152 let 96 | ### 153 val err = ERR_FORBIDDEN_HERE(IT_ETAG,locOf wher) 97 | ### 154 val a2 = hookError(a1,(getPos q,err)) 98 | ### 155 val caq3 = skipTag LOC_ETAG (a2,q1) 99 | 156 in doit wher caq3 100 | 157 end 101 | ### 158 | 0wx3F (* #"?" *) => doit wher (parseProcInstr (getPos q) (a1,q1)) 102 | 159 | _ => 103 | 160 if isName c1 then 104 | 161 let val wher1 = 105 | 162 case wher 106 | ### 163 of PROLOG => INSTANCE NONE 107 | 164 | _ => wher 108 | 165 in case wher1 109 | 166 of PROLOG => 110 | ### 167 raise InternalError(THIS_MODULE,"parseDoc.doit","") 111 | 168 | EPILOG => 112 | ### 169 let 113 | 170 val err = ERR_FORBIDDEN_HERE(IT_STAG,LOC_EPILOG) 114 | ### 171 val a2 = hookError(a1,(getPos q,err)) 115 | ### 172 val caq3 = skipTag LOC_STAG (a2,q1) 116 | 173 in doit EPILOG caq3 117 | 174 end 118 | -- 119 | 177 val a2 = 120 | 178 if not (!O_VALIDATE) orelse isSome doc then a1 121 | ### 179 else hookError(a1,(getPos q,ERR_NO_DTD)) 122 | 180 val (stag,(c3,a3,q3)) = parseSTag 123 | 181 dtd (getPos q) (c1,a2,q1) 124 | -- 125 | 187 of NONE => doit EPILOG (c5,a6,q5) 126 | 188 | SOME (_,_,startPos,_) => 127 | ### 189 let 128 | 190 val err = ERR_FORBIDDEN_HERE(IT_ETAG,LOC_EPILOG) 129 | ### 191 val a7 = hookError(a6,(startPos,err)) 130 | 192 in doit EPILOG (c5,a7,q5) 131 | 193 end 132 | 194 end 133 | ### 195 handle SyntaxError caq => doit wher1 caq) 134 | 196 end 135 | ### 197 else let val err = ERR_FORBIDDEN_HERE(IT_CHAR 0wx3C,locOf wher) 136 | ### 198 val a2 = hookError(a1,(getPos q,err)) 137 | 199 in doit wher (c1,a2,q1) 138 | 200 end 139 | -- 140 | 214 let 141 | 215 val dtd = case dtdOpt 142 | ### 216 of NONE => initDtdTables () 143 | 217 | SOME dtd => dtd 144 | 218 val (enc,xmlDecl,(c1,a1,q1)) = openDocument uriOpt a 145 | -- 146 | 220 val alone = case xmlDecl 147 | 221 of (SOME(_,_,SOME sa)) => sa 148 | ### 222 | _ => false 149 | 223 val _ = if alone then setStandAlone dtd true else () 150 | 224 val a2 = hookXml(a1,(uri,enc,xmlDecl)) 151 | -- 152 | 227 val version = case xmlDecl 153 | 228 of (SOME(SOME ver,_,_)) => ver 154 | ### 229 | _ => "1.0" 155 | 230 val getCharOld = !getCharRef 156 | 231 val isNmsOld = !isNmsRef 157 | -- 158 | 234 val _ = if version="1.0" then () 159 | 235 else 160 | ### 236 let 161 | ### 237 val _ = getCharRef := getChar11 162 | ### 238 val _ = isNmsRef := isNms11 163 | ### 239 val _ = isNameRef := isName11 164 | ### 240 val _ = isXmlRef := isXml11 165 | 241 in 166 | 242 () 167 | -- 168 | 253 val a4 = case wher 169 | 254 of EPILOG => a3 170 | ### 255 | _ => hookError(a3,(getPos q3,ERR_ENDED_IN_PROLOG)) 171 | 256 in hookFinish a4 172 | 257 end 173 | 258 handle CantOpenFile(fmsg,a) => 174 | ### 259 let val a1 = hookError(a,(nullPosition,ERR_NO_SUCH_FILE fmsg)) 175 | 260 in hookFinish a1 176 | 261 end 177 | -------------------------------------------------------------------------------- /test/regression/coverage.txt: -------------------------------------------------------------------------------- 1 | 19% sml (1060/5463) 2 | 57% src/Apps/Canon/canon.sml (22/38) 3 | 47% src/Apps/Canon/canonEncode.sml (10/21) 4 | 42% src/Apps/Canon/canonHooks.sml (24/57) 5 | 21% src/Apps/Canon/canonOptions.sml (12/56) 6 | 71% src/Apps/Canon/canonOutput.sml (27/38) 7 | --% src/Catalog/catData.sml (0/0) 8 | 100% src/Catalog/catDtd.sml (22/22) 9 | 0% src/Catalog/catError.sml (0/34) 10 | 0% src/Catalog/catFile.sml (0/24) 11 | 0% src/Catalog/catHooks.sml (0/46) 12 | 26% src/Catalog/catOptions.sml (21/78) 13 | --% src/Catalog/catParams.sml (0/0) 14 | 0% src/Catalog/catParse.sml (0/28) 15 | 0% src/Catalog/catResolve.sml (0/9) 16 | 1% src/Catalog/catalog.sml (1/76) 17 | 1% src/Catalog/socatParse.sml (3/165) 18 | --% src/Parser/Base/base.sml (0/0) 19 | 9% src/Parser/Base/baseData.sml (1/11) 20 | 0% src/Parser/Base/baseString.sml (0/73) 21 | 0% src/Parser/Dfa/dfa.sml (0/22) 22 | 50% src/Parser/Dfa/dfaData.sml (1/2) 23 | 0% src/Parser/Dfa/dfaError.sml (0/19) 24 | 32% src/Parser/Dfa/dfaOptions.sml (17/52) 25 | 0% src/Parser/Dfa/dfaPassOne.sml (0/21) 26 | 0% src/Parser/Dfa/dfaPassThree.sml (0/27) 27 | 0% src/Parser/Dfa/dfaPassTwo.sml (0/17) 28 | 0% src/Parser/Dfa/dfaString.sml (0/28) 29 | 0% src/Parser/Dfa/dfaUtil.sml (0/55) 30 | 13% src/Parser/Dtd/dtdAttributes.sml (24/180) 31 | 12% src/Parser/Dtd/dtdDeclare.sml (20/165) 32 | --% src/Parser/Dtd/dtdManager.sml (0/0) 33 | --% src/Parser/Error/errorData.sml (0/0) 34 | 0% src/Parser/Error/errorMessage.sml (0/75) 35 | 0% src/Parser/Error/errorString.sml (0/119) 36 | 0% src/Parser/Error/errorUtil.sml (0/65) 37 | --% src/Parser/Error/errors.sml (0/0) 38 | 95% src/Parser/Error/expected.sml (19/20) 39 | 56% src/Parser/Params/dtd.sml (56/100) 40 | 0% src/Parser/Params/hookData.sml (0/7) 41 | --% src/Parser/Params/hooks.sml (0/0) 42 | 0% src/Parser/Params/ignore.sml (0/20) 43 | 38% src/Parser/Params/parserOptions.sml (56/144) 44 | 0% src/Parser/Params/resolve.sml (0/4) 45 | 0% src/Parser/Parse/parseBase.sml (0/89) 46 | 13% src/Parser/Parse/parseContent.sml (40/299) 47 | 3% src/Parser/Parse/parseDecl.sml (12/316) 48 | 50% src/Parser/Parse/parseDocument.sml (64/128) 49 | 10% src/Parser/Parse/parseDtd.sml (19/177) 50 | 28% src/Parser/Parse/parseLiterals.sml (33/114) 51 | 25% src/Parser/Parse/parseMisc.sml (22/87) 52 | 28% src/Parser/Parse/parseNames.sml (7/25) 53 | 5% src/Parser/Parse/parseRefs.sml (12/232) 54 | 47% src/Parser/Parse/parseTags.sml (46/97) 55 | 43% src/Parser/Parse/parseXml.sml (75/171) 56 | 24% src/Parser/entities.sml (50/204) 57 | --% src/Parser/version.sml (0/0) 58 | 80% src/Unicode/Chars/charClasses.sml (36/45) 59 | --% src/Unicode/Chars/charVecDict.sml (0/0) 60 | --% src/Unicode/Chars/dataDict.sml (0/0) 61 | 0% src/Unicode/Chars/testClasses.sml (0/24) 62 | 27% src/Unicode/Chars/uniChar.sml (10/37) 63 | 54% src/Unicode/Chars/uniClasses.sml (43/79) 64 | 100% src/Unicode/Chars/uniRanges.sml (6/6) 65 | 33% src/Unicode/Decode/decode.sml (37/111) 66 | 0% src/Unicode/Decode/decodeError.sml (0/21) 67 | 58% src/Unicode/Decode/decodeFile.sml (25/43) 68 | 22% src/Unicode/Decode/decodeMisc.sml (2/9) 69 | 0% src/Unicode/Decode/decodeUcs2.sml (0/12) 70 | 0% src/Unicode/Decode/decodeUcs4.sml (0/48) 71 | 0% src/Unicode/Decode/decodeUtf16.sml (0/32) 72 | 17% src/Unicode/Decode/decodeUtf8.sml (17/98) 73 | 0% src/Unicode/Decode/decodeUtil.sml (0/4) 74 | 33% src/Unicode/Encode/encode.sml (12/36) 75 | 57% src/Unicode/Encode/encodeBasic.sml (4/7) 76 | 0% src/Unicode/Encode/encodeError.sml (0/3) 77 | 22% src/Unicode/Encode/encodeMisc.sml (18/79) 78 | 0% src/Unicode/Uri/uri.sml (0/102) 79 | 19% src/Unicode/Uri/uriDecode.sml (13/67) 80 | --% src/Unicode/Uri/uriDict.sml (0/0) 81 | 21% src/Unicode/Uri/uriEncode.sml (7/32) 82 | 21% src/Unicode/encoding.sml (9/41) 83 | 60% src/Util/SymDict/dict.sml (57/95) 84 | --% src/Util/SymDict/intDict.sml (0/0) 85 | 0% src/Util/SymDict/intListDict.sml (0/3) 86 | 0% src/Util/SymDict/intSetDict.sml (0/1) 87 | --% src/Util/SymDict/key.sml (0/0) 88 | 0% src/Util/SymDict/stringDict.sml (0/1) 89 | 0% src/Util/SymDict/symbolTable.sml (0/102) 90 | 0% src/Util/intLists.sml (0/12) 91 | 3% src/Util/intSets.sml (3/79) 92 | 31% src/Util/options.sml (14/45) 93 | 10% src/Util/utilCompare.sml (5/50) 94 | 0% src/Util/utilError.sml (0/17) 95 | 30% src/Util/utilHash.sml (12/39) 96 | 13% src/Util/utilInt.sml (4/29) 97 | 8% src/Util/utilList.sml (6/71) 98 | 3% src/Util/utilString.sml (3/96) 99 | 0% src/Util/utilTime.sml (0/5) 100 | --% src/config.sml (0/0) 101 | 0% src/genRandom.sml (0/24) 102 | -------------------------------------------------------------------------------- /test/regression/dependencies.txt: -------------------------------------------------------------------------------- 1 | src/Apps/Canon/canon: src/config.sml 2 | src/Apps/Canon/canon: src/Util/utilCompare.sml 3 | src/Apps/Canon/canon: src/Util/utilString.sml 4 | src/Apps/Canon/canon: src/Util/utilError.sml 5 | src/Apps/Canon/canon: src/Util/utilHash.sml 6 | src/Apps/Canon/canon: src/Util/utilInt.sml 7 | src/Apps/Canon/canon: src/Util/utilList.sml 8 | src/Apps/Canon/canon: src/Util/utilTime.sml 9 | src/Apps/Canon/canon: src/Util/intLists.sml 10 | src/Apps/Canon/canon: src/Util/intSets.sml 11 | src/Apps/Canon/canon: src/Util/options.sml 12 | src/Apps/Canon/canon: src/Util/SymDict/key.sml 13 | src/Apps/Canon/canon: src/Util/SymDict/dict.sml 14 | src/Apps/Canon/canon: src/Util/SymDict/symbolTable.sml 15 | src/Apps/Canon/canon: src/Util/SymDict/intSetDict.sml 16 | src/Apps/Canon/canon: src/Util/SymDict/intDict.sml 17 | src/Apps/Canon/canon: src/Util/SymDict/intListDict.sml 18 | src/Apps/Canon/canon: src/Util/SymDict/stringDict.sml 19 | src/Apps/Canon/canon: src/Unicode/Chars/uniChar.sml 20 | src/Apps/Canon/canon: src/Unicode/Chars/charClasses.sml 21 | src/Apps/Canon/canon: src/Unicode/Chars/charVecDict.sml 22 | src/Apps/Canon/canon: src/Unicode/Chars/dataDict.sml 23 | src/Apps/Canon/canon: src/Unicode/Chars/uniRanges.sml 24 | src/Apps/Canon/canon: src/Unicode/Chars/uniClasses.sml 25 | src/Apps/Canon/canon: src/Unicode/Chars/testClasses.sml 26 | src/Apps/Canon/canon: src/Unicode/Uri/uriDecode.sml 27 | src/Apps/Canon/canon: src/Unicode/Uri/uriEncode.sml 28 | src/Apps/Canon/canon: src/Unicode/Uri/uri.sml 29 | src/Apps/Canon/canon: src/Unicode/Uri/uriDict.sml 30 | src/Apps/Canon/canon: src/Unicode/encoding.sml 31 | src/Apps/Canon/canon: src/Unicode/Encode/encodeBasic.sml 32 | src/Apps/Canon/canon: src/Unicode/Encode/encodeError.sml 33 | src/Apps/Canon/canon: src/Unicode/Encode/encodeMisc.sml 34 | src/Apps/Canon/canon: src/Unicode/Encode/encode.sml 35 | src/Apps/Canon/canon: src/Unicode/Decode/decodeFile.sml 36 | src/Apps/Canon/canon: src/Unicode/Decode/decodeError.sml 37 | src/Apps/Canon/canon: src/Unicode/Decode/decodeMisc.sml 38 | src/Apps/Canon/canon: src/Unicode/Decode/decodeUtil.sml 39 | src/Apps/Canon/canon: src/Unicode/Decode/decodeUcs2.sml 40 | src/Apps/Canon/canon: src/Unicode/Decode/decodeUcs4.sml 41 | src/Apps/Canon/canon: src/Unicode/Decode/decodeUtf16.sml 42 | src/Apps/Canon/canon: src/Unicode/Decode/decodeUtf8.sml 43 | src/Apps/Canon/canon: src/Unicode/Decode/decode.sml 44 | src/Apps/Canon/canon: src/Parser/version.sml 45 | src/Apps/Canon/canon: src/Parser/Dfa/dfaData.sml 46 | src/Apps/Canon/canon: src/Parser/Dfa/dfaError.sml 47 | src/Apps/Canon/canon: src/Parser/Dfa/dfaOptions.sml 48 | src/Apps/Canon/canon: src/Parser/Dfa/dfaUtil.sml 49 | src/Apps/Canon/canon: src/Parser/Dfa/dfaPassOne.sml 50 | src/Apps/Canon/canon: src/Parser/Dfa/dfaPassTwo.sml 51 | src/Apps/Canon/canon: src/Parser/Dfa/dfaPassThree.sml 52 | src/Apps/Canon/canon: src/Parser/Dfa/dfaString.sml 53 | src/Apps/Canon/canon: src/Parser/Dfa/dfa.sml 54 | src/Apps/Canon/canon: src/Parser/Error/errorData.sml 55 | src/Apps/Canon/canon: src/Parser/Error/errorString.sml 56 | src/Apps/Canon/canon: src/Parser/Error/errorMessage.sml 57 | src/Apps/Canon/canon: src/Parser/Error/errorUtil.sml 58 | src/Apps/Canon/canon: src/Parser/Error/expected.sml 59 | src/Apps/Canon/canon: src/Parser/Error/errors.sml 60 | src/Apps/Canon/canon: src/Parser/Base/baseData.sml 61 | src/Apps/Canon/canon: src/Parser/Base/baseString.sml 62 | src/Apps/Canon/canon: src/Parser/Base/base.sml 63 | src/Apps/Canon/canon: src/Parser/Params/dtd.sml 64 | src/Apps/Canon/canon: src/Parser/Params/hookData.sml 65 | src/Apps/Canon/canon: src/Parser/Params/hooks.sml 66 | src/Apps/Canon/canon: src/Parser/Params/ignore.sml 67 | src/Apps/Canon/canon: src/Parser/Params/parserOptions.sml 68 | src/Apps/Canon/canon: src/Parser/Params/resolve.sml 69 | src/Apps/Canon/canon: src/Parser/entities.sml 70 | src/Apps/Canon/canon: src/Parser/Dtd/dtdDeclare.sml 71 | src/Apps/Canon/canon: src/Parser/Dtd/dtdAttributes.sml 72 | src/Apps/Canon/canon: src/Parser/Dtd/dtdManager.sml 73 | src/Apps/Canon/canon: src/Parser/Parse/parseBase.sml 74 | src/Apps/Canon/canon: src/Parser/Parse/parseNames.sml 75 | src/Apps/Canon/canon: src/Parser/Parse/parseMisc.sml 76 | src/Apps/Canon/canon: src/Parser/Parse/parseXml.sml 77 | src/Apps/Canon/canon: src/Parser/Parse/parseRefs.sml 78 | src/Apps/Canon/canon: src/Parser/Parse/parseLiterals.sml 79 | src/Apps/Canon/canon: src/Parser/Parse/parseTags.sml 80 | src/Apps/Canon/canon: src/Parser/Parse/parseDecl.sml 81 | src/Apps/Canon/canon: src/Parser/Parse/parseDtd.sml 82 | src/Apps/Canon/canon: src/Parser/Parse/parseContent.sml 83 | src/Apps/Canon/canon: src/Parser/Parse/parseDocument.sml 84 | src/Apps/Canon/canon: src/Catalog/catData.sml 85 | src/Apps/Canon/canon: src/Catalog/catDtd.sml 86 | src/Apps/Canon/canon: src/Catalog/catError.sml 87 | src/Apps/Canon/canon: src/Catalog/catParams.sml 88 | src/Apps/Canon/canon: src/Catalog/catFile.sml 89 | src/Apps/Canon/canon: src/Catalog/catHooks.sml 90 | src/Apps/Canon/canon: src/Catalog/catOptions.sml 91 | src/Apps/Canon/canon: src/Catalog/socatParse.sml 92 | src/Apps/Canon/canon: src/Catalog/catParse.sml 93 | src/Apps/Canon/canon: src/Catalog/catalog.sml 94 | src/Apps/Canon/canon: src/Catalog/catResolve.sml 95 | src/Apps/Canon/canon: src/genRandom.sml 96 | src/Apps/Canon/canon: src/Apps/Canon/canonOptions.sml 97 | src/Apps/Canon/canon: src/Apps/Canon/canonEncode.sml 98 | src/Apps/Canon/canon: src/Apps/Canon/canonOutput.sml 99 | src/Apps/Canon/canon: src/Apps/Canon/canonHooks.sml 100 | src/Apps/Canon/canon: src/Apps/Canon/canon.sml 101 | -------------------------------------------------------------------------------- /test/regression/expand.txt: -------------------------------------------------------------------------------- 1 | src/config.sml 2 | src/Util/utilCompare.sml 3 | src/Util/utilString.sml 4 | src/Util/utilError.sml 5 | src/Util/utilHash.sml 6 | src/Util/utilInt.sml 7 | src/Util/utilList.sml 8 | src/Util/utilTime.sml 9 | src/Util/intLists.sml 10 | src/Util/intSets.sml 11 | src/Util/options.sml 12 | src/Util/SymDict/key.sml 13 | src/Util/SymDict/dict.sml 14 | src/Util/SymDict/symbolTable.sml 15 | src/Util/SymDict/intSetDict.sml 16 | src/Util/SymDict/intDict.sml 17 | src/Util/SymDict/intListDict.sml 18 | src/Util/SymDict/stringDict.sml 19 | src/Unicode/Chars/uniChar.sml 20 | src/Unicode/Chars/charClasses.sml 21 | src/Unicode/Chars/charVecDict.sml 22 | src/Unicode/Chars/dataDict.sml 23 | src/Unicode/Chars/uniRanges.sml 24 | src/Unicode/Chars/uniClasses.sml 25 | src/Unicode/Chars/testClasses.sml 26 | src/Unicode/Uri/uriDecode.sml 27 | src/Unicode/Uri/uriEncode.sml 28 | src/Unicode/Uri/uri.sml 29 | src/Unicode/Uri/uriDict.sml 30 | src/Unicode/encoding.sml 31 | src/Unicode/Encode/encodeBasic.sml 32 | src/Unicode/Encode/encodeError.sml 33 | src/Unicode/Encode/encodeMisc.sml 34 | src/Unicode/Encode/encode.sml 35 | src/Unicode/Decode/decodeFile.sml 36 | src/Unicode/Decode/decodeError.sml 37 | src/Unicode/Decode/decodeMisc.sml 38 | src/Unicode/Decode/decodeUtil.sml 39 | src/Unicode/Decode/decodeUcs2.sml 40 | src/Unicode/Decode/decodeUcs4.sml 41 | src/Unicode/Decode/decodeUtf16.sml 42 | src/Unicode/Decode/decodeUtf8.sml 43 | src/Unicode/Decode/decode.sml 44 | src/Parser/version.sml 45 | src/Parser/Dfa/dfaData.sml 46 | src/Parser/Dfa/dfaError.sml 47 | src/Parser/Dfa/dfaOptions.sml 48 | src/Parser/Dfa/dfaUtil.sml 49 | src/Parser/Dfa/dfaPassOne.sml 50 | src/Parser/Dfa/dfaPassTwo.sml 51 | src/Parser/Dfa/dfaPassThree.sml 52 | src/Parser/Dfa/dfaString.sml 53 | src/Parser/Dfa/dfa.sml 54 | src/Parser/Error/errorData.sml 55 | src/Parser/Error/errorString.sml 56 | src/Parser/Error/errorMessage.sml 57 | src/Parser/Error/errorUtil.sml 58 | src/Parser/Error/expected.sml 59 | src/Parser/Error/errors.sml 60 | src/Parser/Base/baseData.sml 61 | src/Parser/Base/baseString.sml 62 | src/Parser/Base/base.sml 63 | src/Parser/Params/dtd.sml 64 | src/Parser/Params/hookData.sml 65 | src/Parser/Params/hooks.sml 66 | src/Parser/Params/ignore.sml 67 | src/Parser/Params/parserOptions.sml 68 | src/Parser/Params/resolve.sml 69 | src/Parser/entities.sml 70 | src/Parser/Dtd/dtdDeclare.sml 71 | src/Parser/Dtd/dtdAttributes.sml 72 | src/Parser/Dtd/dtdManager.sml 73 | src/Parser/Parse/parseBase.sml 74 | src/Parser/Parse/parseNames.sml 75 | src/Parser/Parse/parseMisc.sml 76 | src/Parser/Parse/parseXml.sml 77 | src/Parser/Parse/parseRefs.sml 78 | src/Parser/Parse/parseLiterals.sml 79 | src/Parser/Parse/parseTags.sml 80 | src/Parser/Parse/parseDecl.sml 81 | src/Parser/Parse/parseDtd.sml 82 | src/Parser/Parse/parseContent.sml 83 | src/Parser/Parse/parseDocument.sml 84 | src/Catalog/catData.sml 85 | src/Catalog/catDtd.sml 86 | src/Catalog/catError.sml 87 | src/Catalog/catParams.sml 88 | src/Catalog/catFile.sml 89 | src/Catalog/catHooks.sml 90 | src/Catalog/catOptions.sml 91 | src/Catalog/socatParse.sml 92 | src/Catalog/catParse.sml 93 | src/Catalog/catalog.sml 94 | src/Catalog/catResolve.sml 95 | src/genRandom.sml 96 | src/Apps/Canon/canonOptions.sml 97 | src/Apps/Canon/canonEncode.sml 98 | src/Apps/Canon/canonOutput.sml 99 | src/Apps/Canon/canonHooks.sml 100 | src/Apps/Canon/canon.sml 101 | -------------------------------------------------------------------------------- /test/simple.mlb: -------------------------------------------------------------------------------- 1 | simple.sml 2 | main.sml 3 | -------------------------------------------------------------------------------- /test/simple.sml: -------------------------------------------------------------------------------- 1 | fun main () = print "Hello, world!\n" 2 | -------------------------------------------------------------------------------- /test/test.ps1: -------------------------------------------------------------------------------- 1 | 2 | Set-StrictMode -Version 2.0 3 | $ErrorActionPreference = "Stop" 4 | 5 | $mydir = Split-Path $MyInvocation.MyCommand.Path -Parent 6 | 7 | cd $mydir 8 | 9 | "" 10 | "==> Running simple example directly in SML/NJ (smlrun)" 11 | "" 12 | 13 | ..\smlrun.ps1 .\simple.mlb 14 | 15 | "" 16 | "==> Done" 17 | "" 18 | 19 | if (-not (Test-Path "fxp")) { 20 | "==> Checking out more complex test repo" 21 | "" 22 | cmd /c "git clone https://github.com/cannam/fxp 2>&1" 23 | } 24 | 25 | "" 26 | "==> Running complex example directly in SML/NJ (smlrun)" 27 | "" 28 | 29 | Get-Content -Path .\fxp\doc\fxp-xsa.xml | ..\smlrun.ps1 .\fxp\src\Apps\Canon\canon.mlb --validate=no 30 | 31 | "" 32 | "==> Done" 33 | "" 34 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # A straightforward test using a real repo (a mirror of the FXP XML 4 | # parser) with real MLB files, albeit tuned to match our expectations 5 | # about the nature of the main function. 6 | 7 | set -eu 8 | 9 | mydir=$(dirname "$0") 10 | cd "$mydir" 11 | 12 | check_regression() { 13 | local expected="$1" 14 | local actual="$2" 15 | if ! cmp -s "$expected" "$actual" ; then 16 | echo "*** ERROR: Output does not match expected: diff follows, expected first" 17 | diff -u "$expected" "$actual" 18 | exit 2 19 | fi 20 | } 21 | 22 | 23 | echo 24 | echo "==> Running simplest example directly in Poly/ML" 25 | echo 26 | 27 | ../polyrun ./simple.mlb 28 | 29 | 30 | if [ ! -d fxp ]; then 31 | echo 32 | echo "==> Checking out more complex test repo" 33 | echo 34 | git clone https://github.com/cannam/fxp 35 | ( cd fxp ; git checkout 534f24d26695ef810d1b3c9e6d9f05a86c977217 ) 36 | fi 37 | 38 | 39 | cd fxp 40 | 41 | echo 42 | echo "==> Running mlb-expand regression test" 43 | echo 44 | 45 | ../../mlb-expand src/Apps/Canon/canon.mlb > output.txt 46 | check_regression ../regression/expand.txt output.txt 47 | 48 | echo 49 | echo "==> Running mlb-dependencies regression test" 50 | echo 51 | 52 | ../../mlb-dependencies src/Apps/Canon/canon.mlb > output.txt 53 | check_regression ../regression/dependencies.txt output.txt 54 | 55 | echo 56 | echo "==> First testing MLB with MLton (for reference)" 57 | echo 58 | 59 | mlton src/Apps/Canon/canon.mlb 60 | 61 | echo 62 | echo "==> Running build with Poly/ML (polybuild)" 63 | echo 64 | 65 | ../../polybuild src/Apps/Canon/canon.mlb 66 | 67 | echo 68 | echo "==> Testing output" 69 | echo 70 | 71 | cat doc/fxp-xsa.xml | src/Apps/Canon/canon --validate=no && echo 72 | 73 | echo 74 | echo "==> Running directly in Poly/ML (polyrun)" 75 | echo 76 | 77 | cat doc/fxp-xsa.xml | ../../polyrun src/Apps/Canon/canon.mlb --validate=no && echo 78 | 79 | echo 80 | echo "==> Loading in Poly/ML REPL (polyrepl)" 81 | echo 82 | 83 | echo main | ../../polyrepl src/Apps/Canon/canon.mlb | grep '^val it = fn' 84 | 85 | echo 86 | echo "==> Running directly in SML/NJ (smlrun)" 87 | echo 88 | 89 | cat doc/fxp-xsa.xml | ../../smlrun src/Apps/Canon/canon.mlb --validate=no && echo 90 | 91 | echo 92 | echo "==> Running mlb-coverage all-files regression test" 93 | echo 94 | 95 | cat doc/fxp-xsa.xml | ../../mlb-coverage src/Apps/Canon/canon.mlb --validate=no > output.txt 96 | check_regression ../regression/coverage.txt output.txt 97 | 98 | echo 99 | echo "==> Running mlb-coverage single-file regression test" 100 | echo 101 | 102 | # annoyingly, different greps seem to differ in how they handle 103 | # overlapping context so the results come out a bit different across 104 | # platforms. I can't easily see how to work around that one in the 105 | # coverage script, so let's do it here - hence the sort/uniq shuffle 106 | cat doc/fxp-xsa.xml | ../../mlb-coverage -f src/Parser/Parse/parseDocument.sml ./src/Apps/Canon/canon.mlb --validate=no | sort -n | uniq > output.txt 107 | cat ../regression/annotate.txt | sort -n | uniq > expected.txt 108 | check_regression expected.txt output.txt 109 | 110 | echo 111 | echo "==> Done" 112 | echo 113 | 114 | -------------------------------------------------------------------------------- /with-mlb-dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # with-mlb-dependencies - run a (presumed) compiler command, while also 4 | # dumping out a dependency file. Intended for Meson build integration. 5 | # 6 | # Chris Cannam, 2020. MIT licence 7 | 8 | set -e 9 | 10 | if [ -z "$1" ]; then 11 | myname=$(basename "$0") 12 | echo 1>&2 13 | echo "Usage: $myname " 1>&2 14 | echo 1>&2 15 | echo "First runs the supplied build command with the supplied build arguments;" 1>&2 16 | echo "then scans the build arguments, locating the first argument that names an .mlb" 1>&2 17 | echo "or .sml file, and writes out the dependency list for that file to a" 1>&2 18 | echo "similarly-named .deps file in the same location." 1>&2 19 | echo 1>&2 20 | echo "Example: $myname mlton program.mlb" 1>&2 21 | echo 1>&2 22 | echo "The above example runs mlton with the argument program.mlb; if that was" 1>&2 23 | echo "successful, it then writes out a dependency file called program.deps," 1>&2 24 | echo "containing a list of the input files which the target program depends on," 1>&2 25 | echo "in Makefile dependency syntax." 1>&2 26 | echo 1>&2 27 | echo "This program also looks for the -o, -output, and -mlb-path-var options in the" 1>&2 28 | echo "build arguments and interprets them appropriately." 1>&2 29 | exit 2 30 | fi 31 | 32 | set -u 33 | 34 | mydir=$(dirname "$0") 35 | . "$mydir/smlbuild-include.sh" 36 | 37 | arg="" 38 | output="" 39 | env_args= 40 | expecting_pathvar=false 41 | expecting_output=false 42 | for x in "$@" ; do 43 | if [ "$expecting_pathvar" = "true" ]; then 44 | env_args="$env_args $(echo $x |sed 's/ /=/')" 45 | expecting_pathvar=false 46 | elif [ "$expecting_output" = "true" ]; then 47 | output="$x" 48 | expecting_output=false 49 | else 50 | case "$x" in 51 | *.mlb) arg="$x";; 52 | *.sml) arg="$x";; 53 | -mlb-path-var) expecting_pathvar=true;; 54 | -o) expecting_output=true;; 55 | -output) expecting_output=true;; 56 | *) ;; 57 | esac 58 | if [ -n "$arg" ]; then 59 | break 60 | fi 61 | fi 62 | done 63 | 64 | "$@" || exit 1 65 | 66 | if [ -z "$output" ]; then 67 | output=$(get_outfile "$arg") 68 | fi 69 | 70 | deps="$output".deps 71 | 72 | shift 73 | 74 | env $env_args \ 75 | "$mydir/mlb-dependencies" "$arg" | \ 76 | sed 's|^[^:]*: |'"$output: "'|' > "$deps" 77 | 78 | -------------------------------------------------------------------------------- /with-mlb-dependencies.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set args=%* 3 | if defined args set args=%args:-=_DASH_% 4 | if defined args set args=%args:"=\"% 5 | PowerShell -NoProfile -ExecutionPolicy Bypass -Command "& %~dpn0.ps1 %args%" 6 | if %errorlevel% neq 0 exit /b %errorlevel% 7 | -------------------------------------------------------------------------------- /with-mlb-dependencies.ps1: -------------------------------------------------------------------------------- 1 | 2 | Set-StrictMode -Version 2.0 3 | $ErrorActionPreference = "Stop" 4 | 5 | if ($args.Count -lt 1) { 6 | "Usage: with-mlb-dependencies " 7 | exit 1 8 | } 9 | 10 | $mydir = Split-Path -Parent $PSCommandPath 11 | 12 | . $mydir/smlbuild-include.ps1 13 | 14 | $mlb = "" 15 | $sml = "" 16 | $output = "" 17 | $expecting_output = $false 18 | 19 | $args = $args -Replace "_DASH_","-" 20 | 21 | foreach ($arg in $args) { 22 | 23 | if ($expecting_output) { 24 | $output = $arg 25 | $expecting_output = $false 26 | } else { 27 | if ($arg -match "[.]mlb$") { 28 | $mlb = $arg 29 | } elseif ($arg -match "[.]sml") { 30 | $sml = $arg 31 | } elseif ($arg -match "-o") { 32 | $expecting_output = $true 33 | } elseif ($arg -match "-output") { 34 | $expecting_output = $true 35 | } 36 | if ($mlb) { 37 | break 38 | } 39 | } 40 | } 41 | 42 | "mlb = $mlb" | Out-Host 43 | "sml = $sml" | Out-Host 44 | "output = $output" | Out-Host 45 | 46 | $compiler=$args[0] 47 | $compiler_args=$args[1..$args.length] 48 | 49 | "$compiler $compiler_args" | Out-File ".mlb-dependencies-command" 50 | 51 | &$compiler $compiler_args | Tee-Object -FilePath ".mlb-dependencies-output" | Out-Host 52 | 53 | "Completed" | Out-Host 54 | 55 | if ($mlb) { 56 | 57 | if (!$output) { 58 | $output = $mlb -replace "[.]mlb$",".exe" 59 | } 60 | $base = $output -replace "[.]exe$","" 61 | $deps = "$base.deps" 62 | 63 | "Writing dependencies to $deps" 64 | 65 | $lines = @(listMLB $mlb) 66 | 67 | if ($lines -match "^Error: ") { 68 | $lines -match "^Error: " 69 | exit 1 70 | } 71 | 72 | $lines = $lines -replace "^","${output}: " 73 | 74 | $lines | Out-File -Encoding "ASCII" $deps 75 | 76 | } elseif ($sml) { 77 | 78 | if (!$output) { 79 | $output = $sml -replace "[.]mlb$",".exe" 80 | } 81 | $base = $output -replace "[.]exe$","" 82 | $deps = "$base.deps" 83 | 84 | "Writing dependencies to $deps" 85 | 86 | "${target}: $sml" | Out-File -Encoding "ASCII" $deps 87 | } 88 | 89 | Get-Content ".mlb-dependencies-output" | Out-Host 90 | 91 | 92 | --------------------------------------------------------------------------------