Skip to content

Instantly share code, notes, and snippets.

@cwfoo
Created May 21, 2022 06:45
Show Gist options
  • Save cwfoo/c8f3d43b2177e866fa3458ae57332a00 to your computer and use it in GitHub Desktop.
Save cwfoo/c8f3d43b2177e866fa3458ae57332a00 to your computer and use it in GitHub Desktop.
Check syntax of Standard ML program using Poly/ML without executing the program
(* Check for syntax errors and type errors in a Standard ML file without
* executing the program. Tested in Poly/ML 5.9 on Ubuntu 20.04.
*
* To check for the existence of errors in a Standard ML file using Poly/ML, it
* is sufficient to use `PolyML.compiler (TextIO.input1 inStream, [])`. However,
* that will not show line and column numbers when there are errors or warnings.
* This program adds line and column numbers to the error and warning messages.
*
* Usage:
* poly --script this-file.sml file-to-check.sml
*
* Behavior:
* * Prints warnings and errors to standard output.
* * Exits with exit code 1 if there are errors, exits with exit code 0
* otherwise.
*
* To print to standard error instead of standard output, add this to the
* compiler parameter list in the call to PolyML.compiler:
* PolyML.Compiler.CPOutStream (fn s => (TextIO.output (TextIO.stdErr, s);
* TextIO.flushOut TextIO.stdErr))
* *)
fun getLineChars inStream =
(* Limitation: TextIO.inputLine will raise the "Size" exception if the line is
* longer than String.maxSize. *)
case TextIO.inputLine inStream of
NONE => NONE
| SOME s => SOME (explode s)
fun checkFile filePath =
let
val lineNum = ref 0
val colNum = ref 0
val curLine = ref []
val ins = TextIO.openIn filePath
fun getChar () =
case !curLine of
[] =>
(case getLineChars ins of
NONE => NONE
| SOME (c::cs) =>
(curLine := cs;
lineNum := !lineNum + 1;
colNum := 1;
SOME c)
| SOME [] =>
(lineNum := !lineNum + 1;
getChar ()))
| (c::cs) =>
(curLine := cs;
colNum := !colNum + 1;
SOME c)
in
(ignore o PolyML.compiler)
(getChar, [PolyML.Compiler.CPFileName filePath,
PolyML.Compiler.CPLineNo (fn () => !lineNum),
PolyML.Compiler.CPLineOffset (fn () => !colNum)])
end
val () = case CommandLine.arguments () of
["--script", _, fileToCheck] => checkFile fileToCheck
| _ => raise (Fail "Invalid command line arguments")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment