From 843929c241c7916483377a65f1602e953d2cf735 Mon Sep 17 00:00:00 2001 From: Martin Elsman Date: Sat, 20 Mar 2021 17:59:10 +0100 Subject: [PATCH 1/2] tests, github actions, etc --- .github/workflows/main.yml | 68 ++++++++++++++++++++++ Makefile | 12 ++++ README.md | 43 +++++++++++++- lib/github.com/kfl/wpp/.gitignore | 5 ++ lib/github.com/kfl/wpp/Makefile | 14 +++++ lib/github.com/kfl/wpp/Wpp.sig | 2 +- lib/github.com/kfl/wpp/Wpp.sml | 18 +++--- lib/github.com/kfl/wpp/test/.gitignore | 5 ++ lib/github.com/kfl/wpp/test/Makefile | 31 ++++++++++ lib/github.com/kfl/wpp/test/example.mlb | 6 ++ lib/github.com/kfl/wpp/test/example.out.ok | 44 ++++++++++++++ lib/github.com/kfl/wpp/test/example.sml | 62 ++++++++++++++++++++ lib/github.com/kfl/wpp/wpp.mlb | 7 +++ 13 files changed, 303 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/main.yml create mode 100644 Makefile create mode 100644 lib/github.com/kfl/wpp/.gitignore create mode 100644 lib/github.com/kfl/wpp/Makefile create mode 100644 lib/github.com/kfl/wpp/test/.gitignore create mode 100644 lib/github.com/kfl/wpp/test/Makefile create mode 100644 lib/github.com/kfl/wpp/test/example.mlb create mode 100644 lib/github.com/kfl/wpp/test/example.out.ok create mode 100644 lib/github.com/kfl/wpp/test/example.sml create mode 100644 lib/github.com/kfl/wpp/wpp.mlb diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..58d57fd --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,68 @@ +name: CI + +on: + + push: + branches: [ master ] + + pull_request: + branches: [ master ] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + + build-test: + + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + mlcomp: [mlkit, mlton] + + runs-on: ${{ matrix.os }} + + steps: + + - uses: actions/checkout@v2 + + - name: Setup environment + run: | + echo "OS=$(uname -s | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV + echo "RUNHOME=$(echo $HOME)" >> $GITHUB_ENV + + - name: Install MLKit and smlpkg + working-directory: ${{ env.RUNHOME }} + run: | + echo "[OS: $OS, HOME: $RUNHOME]" + wget https://github.com/diku-dk/smlpkg/releases/download/v0.1.4/smlpkg-bin-dist-${{env.OS}}.tgz + tar xzf smlpkg-bin-dist-${{env.OS}}.tgz + echo "$HOME/smlpkg-bin-dist-${{env.OS}}/bin" >> $GITHUB_PATH + wget https://github.com/melsman/mlkit/releases/download/v4.5.4/mlkit-bin-dist-${{env.OS}}.tgz + tar xzf mlkit-bin-dist-${{env.OS}}.tgz + echo "$HOME/mlkit-bin-dist-${{env.OS}}/bin" >> $GITHUB_PATH + mkdir -p .mlkit + echo "SML_LIB $HOME/mlkit-bin-dist-${{env.OS}}/lib/mlkit" > .mlkit/mlb-path-map + + - name: Check + run: | + mlkit --version + smlpkg --version + + - name: Install MLton (linux) + if: ${{ env.OS == 'linux' && matrix.mlcomp == 'mlton' }} + run: | + sudo apt-get install -y mlton + mlton + + - name: Install MLton (macos) + if: ${{ env.OS == 'darwin' && matrix.mlcomp == 'mlton' }} + run: | + brew install mlton + mlton + + - name: Build + run: MLCOMP=${{ matrix.mlcomp }} make clean all + + - name: Run tests + run: MLCOMP=${{ matrix.mlcomp }} make test diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..89264e1 --- /dev/null +++ b/Makefile @@ -0,0 +1,12 @@ +.PHONY: all +all: + $(MAKE) -C lib/github.com/kfl/wpp all + +.PHONY: test +test: + $(MAKE) -C lib/github.com/kfl/wpp test + +.PHONY: clean +clean: + $(MAKE) -C lib/github.com/kfl/wpp clean + rm -rf MLB *~ .*~ diff --git a/README.md b/README.md index 5bef874..b7be9de 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,41 @@ -wpp -=== +# sml-regexp [![CI](https://github.com/kfl/wpl/workflows/CI/badge.svg)](https://github.com/kfl/wpp/actions) - A Pretty Printer, based on Philip Wadler's "A prettier printer". But heavily modified to be efficient in a strict language. +A Pretty Printer for Standard ML, based on Philip Wadler's "A prettier +printer". But heavily modified to be efficient in a strict language. + +## Overview of MLB files + +- `lib/github.com/kfl/wpp/wpp.mlb`: + + - **signature** [`Wpp`](lib/github.com/kfl/wpp/Wpp.sig) + - **structure** `Wpp` + - **structure** `Utility` + +## Use of the package + +This library is set up to work well with the SML package manager +[smlpkg](https://github.com/diku-dk/smlpkg). To use the package, in +the root of your project directory, execute the command: + +``` +$ smlpkg add github.com/kfl/wpp +``` + +This command will add a _requirement_ (a line) to the `sml.pkg` file in your +project directory (and create the file, if there is no file `sml.pkg` +already). + +To download the library into the directory +`lib/github.com/kfl/wpp`, execute the command: + +``` +$ smlpkg sync +``` + +You can now reference the `mlb`-file using relative paths from within +your project's `mlb`-files. + +Notice that you can choose either to treat the downloaded package as +part of your own project sources (vendoring) or you can add the +`sml.pkg` file to your project sources and make the `smlpkg sync` +command part of your build process. diff --git a/lib/github.com/kfl/wpp/.gitignore b/lib/github.com/kfl/wpp/.gitignore new file mode 100644 index 0000000..b0ba8f6 --- /dev/null +++ b/lib/github.com/kfl/wpp/.gitignore @@ -0,0 +1,5 @@ +*.res +*.exe +*~ +*.out +MLB \ No newline at end of file diff --git a/lib/github.com/kfl/wpp/Makefile b/lib/github.com/kfl/wpp/Makefile new file mode 100644 index 0000000..00e4db4 --- /dev/null +++ b/lib/github.com/kfl/wpp/Makefile @@ -0,0 +1,14 @@ +MLCOMP ?= mlkit + +.PHONY: all +all: + $(MLCOMP) -output wpp.exe wpp.mlb + +.PHONY: test +test: + $(MAKE) -C test test + +.PHONY: clean +clean: + $(MAKE) -C test clean + rm -rf MLB *~ wpp.exe diff --git a/lib/github.com/kfl/wpp/Wpp.sig b/lib/github.com/kfl/wpp/Wpp.sig index a94b636..837b835 100644 --- a/lib/github.com/kfl/wpp/Wpp.sig +++ b/lib/github.com/kfl/wpp/Wpp.sig @@ -8,6 +8,7 @@ your choice, the licence can be obtained at http://www.gnu.org/copyleft/lgpl.html *) + signature Wpp = sig type doc @@ -34,7 +35,6 @@ signature Wpp = val real : real -> doc (* an ML real constant *) val bool : bool -> doc (* a boolean *) - val toString : int -> doc -> string val toOutStream : int -> TextIO.outstream -> doc -> unit val toFile : int -> string -> doc -> unit diff --git a/lib/github.com/kfl/wpp/Wpp.sml b/lib/github.com/kfl/wpp/Wpp.sml index 72819f9..09de6a3 100644 --- a/lib/github.com/kfl/wpp/Wpp.sml +++ b/lib/github.com/kfl/wpp/Wpp.sml @@ -13,7 +13,7 @@ struct infixr 6 ^^ datatype doc = - NIL + NIL | APPEND of doc * doc | NEST of int * doc | TEXT of string @@ -21,11 +21,11 @@ struct | NEWLINE | GROUP of doc - fun op^^ p = case p of - (NIL,NIL) => NIL - | (NIL, y) => y - | (x, NIL) => x - | _ => APPEND p + fun op^^ p = case p of + (NIL,NIL) => NIL + | (NIL, y) => y + | (x, NIL) => x + | _ => APPEND p val empty = NIL fun nest i x = NEST(i,x) @@ -33,7 +33,7 @@ struct fun break sp off = BREAK(sp, off) val line = BREAK (1,0) val newline = NEWLINE - fun group x = GROUP x + fun group x = GROUP x (*** Derived functions ***) val concat = List.foldr op^^ empty @@ -52,8 +52,6 @@ struct val real = fromConv Real.toString fun bool b = if b then text "true" else text "false" - - (*** Formating of docs ***) val nlsize = String.size "\n" @@ -61,7 +59,7 @@ struct fun nlspace outs s i = outs s (StringCvt.padRight #" " (i+nlsize) "\n") local - datatype mode = Flat | Break + datatype mode = Flat | Break fun fitting [] left = true | fitting ((i, mode, doc) :: rest) left = diff --git a/lib/github.com/kfl/wpp/test/.gitignore b/lib/github.com/kfl/wpp/test/.gitignore new file mode 100644 index 0000000..b0ba8f6 --- /dev/null +++ b/lib/github.com/kfl/wpp/test/.gitignore @@ -0,0 +1,5 @@ +*.res +*.exe +*~ +*.out +MLB \ No newline at end of file diff --git a/lib/github.com/kfl/wpp/test/Makefile b/lib/github.com/kfl/wpp/test/Makefile new file mode 100644 index 0000000..fe28b35 --- /dev/null +++ b/lib/github.com/kfl/wpp/test/Makefile @@ -0,0 +1,31 @@ + +MLCOMP ?= mlkit + +.PHONY: test +test: example.res + cat $^ + +%.res: %.out + @(diff -aq $< $<.ok > /dev/null 2>&1; \ + if [ $$? -eq 0 ]; then \ + echo "OK: $*" > $@ \ + ; else \ + if [ -e $<.ok ]; then \ + echo "ERR: $* - file $< differs from $<.ok"; \ + echo "ERR: $* - file $< differs from $<.ok" > $@ \ + ; else \ + echo "ERR: $* - file $<.ok does not exist"; \ + echo "ERR: $* - file $<.ok does not exist" > $@ \ + ; fi \ + ; exit 1 \ + ;fi) + +%.out: %.exe + ./$< > $@ + +%.exe: %.mlb %.sml + $(MLCOMP) -output $@ $< + +.PHONY: clean +clean: + rm -rf MLB *.out *~ *.exe *.res run diff --git a/lib/github.com/kfl/wpp/test/example.mlb b/lib/github.com/kfl/wpp/test/example.mlb new file mode 100644 index 0000000..8dc9b1c --- /dev/null +++ b/lib/github.com/kfl/wpp/test/example.mlb @@ -0,0 +1,6 @@ +local + $(SML_LIB)/basis/basis.mlb + ../wpp.mlb +in + example.sml +end diff --git a/lib/github.com/kfl/wpp/test/example.out.ok b/lib/github.com/kfl/wpp/test/example.out.ok new file mode 100644 index 0000000..454b1c2 --- /dev/null +++ b/lib/github.com/kfl/wpp/test/example.out.ok @@ -0,0 +1,44 @@ +maxS50: +if (x > y) then (x + 1) else (y * z) + +maxS30: +if (x > y) +then (x + 1) +else (y * z) + +maxS10: +if (x > y) +then + (x + 1) +else + (y * z) + +nestS50: +if (x > y) +then (x + 1) +else if (x > y) then (x + 1) else (y * z) + +nestS30: +if (x > y) +then (x + 1) +else + if (x > y) + then (x + 1) + else (y * z) + +nestS10: +if (x > y) +then + (x + 1) +else + if + (x + > + y) + then + (x + + + 1) + else + (y * z) + diff --git a/lib/github.com/kfl/wpp/test/example.sml b/lib/github.com/kfl/wpp/test/example.sml new file mode 100644 index 0000000..f870f10 --- /dev/null +++ b/lib/github.com/kfl/wpp/test/example.sml @@ -0,0 +1,62 @@ +structure Example = +struct + +(* +Small demonstration of how to use Wpp and the utilities. + +An often occurring challenge is to format if-then-else nicely, so that +is mainly what we'll demonstrate, +*) + +local + structure U = Utility + val $ = U.$ + val ^+^ = U.^+^ + infix ^+^ +in + +datatype Ast = Var of string + | Lit of int + | Opr of Ast * string * Ast + | Cond of Ast * Ast * Ast + +fun toDoc ast = + case ast of + Var v => $v + | Lit n => Wpp.int n + | Opr(x, opr, y) => U.bin toDoc ($opr) (x, y) + | Cond(test, pos, neg) => + Wpp.group (U.spread [ U.block 2 ($"if" ^+^ toDoc test) + , U.block 2 ($"then" ^+^ toDoc pos) + , U.block 2 ($"else" ^+^ toDoc neg)]) + +(* AST for `if (x > y) then x+1 else y*z` *) +val maxEx = Cond(Opr(Var"x", ">", Var"y"), + Opr(Var"x", "+", Lit 1), + Opr(Var"y", "*", Var"z")) +val maxDoc = toDoc maxEx +val maxS50 = Wpp.toString 50 maxDoc (* equals "if (x > y) then (x + 1) else (y * z)\n" *) +val maxS30 = Wpp.toString 30 maxDoc (* equals "if (x > y)\nthen (x + 1)\nelse (y * z)\n" *) +val maxS10 = Wpp.toString 10 maxDoc (* equals "if (x > y)\nthen\n (x + 1)\nelse\n (y * z)\n" *) + + +val nested = Cond(Opr(Var"x", ">", Var"y"), + Opr(Var"x", "+", Lit 1), + maxEx) +val nestDoc = toDoc nested +val nestS50 = Wpp.toString 50 nestDoc +val nestS30 = Wpp.toString 30 nestDoc +val nestS10 = Wpp.toString 10 nestDoc + +fun pr_test t s = print (t ^ ":\n" ^ s ^ "\n") + +val () = pr_test "maxS50" maxS50 +val () = pr_test "maxS30" maxS30 +val () = pr_test "maxS10" maxS10 + +val () = pr_test "nestS50" nestS50 +val () = pr_test "nestS30" nestS30 +val () = pr_test "nestS10" nestS10 + +end +end diff --git a/lib/github.com/kfl/wpp/wpp.mlb b/lib/github.com/kfl/wpp/wpp.mlb new file mode 100644 index 0000000..ef3ab63 --- /dev/null +++ b/lib/github.com/kfl/wpp/wpp.mlb @@ -0,0 +1,7 @@ +local + $(SML_LIB)/basis/basis.mlb +in + Wpp.sig + Wpp.sml + Utility.sml +end From 1b5e5a6d863c82d46ee9dfa9c9a8366ef34da905 Mon Sep 17 00:00:00 2001 From: Martin Elsman Date: Sat, 20 Mar 2021 18:24:33 +0100 Subject: [PATCH 2/2] fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7be9de..f838a3d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# sml-regexp [![CI](https://github.com/kfl/wpl/workflows/CI/badge.svg)](https://github.com/kfl/wpp/actions) +# wpp [![CI](https://github.com/kfl/wpl/workflows/CI/badge.svg)](https://github.com/kfl/wpp/actions) A Pretty Printer for Standard ML, based on Philip Wadler's "A prettier printer". But heavily modified to be efficient in a strict language.