build: Separate Mes and Guile modules.
authorJan Nieuwenhuizen <janneke@gnu.org>
Sat, 21 Jul 2018 05:15:52 +0000 (07:15 +0200)
committerJan Nieuwenhuizen <janneke@gnu.org>
Sat, 21 Jul 2018 05:15:52 +0000 (07:15 +0200)
* scaffold/gc.scm: Move from guile/gc.scm.
* guile/: Remove.
* module/language/paren.mes: Remove.
* mes/module/mes/base.mes: Move from module/mes/.
* mes/module/mes/boot-0.scm: Likewise.
* mes/module/mes/boot-00.scm: Likewise.
* mes/module/mes/boot-01.scm: Likewise.
* mes/module/mes/boot-02.scm: Likewise.
* mes/module/mes/catch.mes: Likewise.
* mes/module/mes/display.mes: Likewise.
* mes/module/mes/fluids.mes: Likewise.
* mes/module/mes/getopt-long.mes: Likewise.
* mes/module/mes/guile.mes: Likewise.
* mes/module/mes/lalr.mes: Likewise.
* mes/module/mes/lalr.scm: Likewise.
* mes/module/mes/let.mes: Likewise.
* mes/module/mes/match.mes: Likewise.
* mes/module/mes/match.scm: Likewise.
* mes/module/mes/mescc.mes: Likewise.
* mes/module/mes/misc.mes: Likewise.
* mes/module/mes/module.mes: Likewise.
* mes/module/mes/optargs.mes: Likewise.
* mes/module/mes/optargs.scm: Likewise.
* mes/module/mes/peg.mes: Likewise.
* mes/module/mes/peg/cache.scm: Likewise.
* mes/module/mes/peg/codegen.scm: Likewise.
* mes/module/mes/peg/simplify-tree.scm: Likewise.
* mes/module/mes/peg/string-peg.scm: Likewise.
* mes/module/mes/peg/using-parsers.scm: Likewise.
* mes/module/mes/pmatch.mes: Likewise.
* mes/module/mes/pmatch.scm: Likewise.
* mes/module/mes/posix.mes: Likewise.
* mes/module/mes/pretty-print.mes: Likewise.
* mes/module/mes/pretty-print.scm: Likewise.
* mes/module/mes/psyntax-0.mes: Likewise.
* mes/module/mes/psyntax-1.mes: Likewise.
* mes/module/mes/psyntax.mes: Likewise.
* mes/module/mes/psyntax.pp: Likewise.
* mes/module/mes/psyntax.ss: Likewise.
* mes/module/mes/quasiquote.mes: Likewise.
* mes/module/mes/quasisyntax.mes: Likewise.
* mes/module/mes/quasisyntax.scm: Likewise.
* mes/module/mes/repl.mes: Likewise.
* mes/module/mes/scm.mes: Likewise.
* mes/module/mes/syntax.mes: Likewise.
* mes/module/mes/syntax.scm: Likewise.
* mes/module/mes/test.mes: Likewise.
* mes/module/mes/tiny-0.mes: Likewise.
* mes/module/mes/type-0.mes: Likewise.
* mes/module/mescc/M1.mes: Likewise.
* mes/module/mescc/as.mes: Likewise.
* mes/module/mescc/bytevectors.mes: Likewise.
* mes/module/mescc/compile.mes: Likewise.
* mes/module/mescc/i386/as.mes: Likewise.
* mes/module/mescc/info.mes: Likewise.
* mes/module/mescc/mescc.mes: Likewise.
* mes/module/mescc/preprocess.mes: Likewise.
* mes/module/nyacc/lalr.mes: Likewise.
* mes/module/nyacc/lang/c99/cpp.mes: Likewise.
* mes/module/nyacc/lang/c99/parser.mes: Likewise.
* mes/module/nyacc/lang/c99/pprint.mes: Likewise.
* mes/module/nyacc/lang/calc/parser.mes: Likewise.
* mes/module/nyacc/lang/util.mes: Likewise.
* mes/module/nyacc/lex.mes: Likewise.
* mes/module/nyacc/parse.mes: Likewise.
* mes/module/nyacc/util.mes: Likewise.
* mes/module/rnrs/arithmetic/bitwise.mes: Likewise.
* mes/module/srfi/srfi-0.mes: Likewise.
* mes/module/srfi/srfi-1.mes: Likewise.
* mes/module/srfi/srfi-1.scm: Likewise.
* mes/module/srfi/srfi-13.mes: Likewise.
* mes/module/srfi/srfi-14.mes: Likewise.
* mes/module/srfi/srfi-16.mes: Likewise.
* mes/module/srfi/srfi-16.scm: Likewise.
* mes/module/srfi/srfi-26.mes: Likewise.
* mes/module/srfi/srfi-26.scm: Likewise.
* mes/module/srfi/srfi-43.mes: Likewise.
* mes/module/srfi/srfi-8.mes: Likewise.
* mes/module/srfi/srfi-9.mes: Likewise.
* mes/module/srfi/srfi-9/gnu.mes: Likewise.
* mes/module/sxml/xpath.mes: Likewise.
* mes/module/sxml/xpath.scm: Likewise.
* module/mes/mes-0.scm: Likewise.
* build-aux/build-guile.sh: Update for new layout.
* build-aux/build-mes.sh: Likewise.
* build-aux/check-boot.sh: Likewise.
* build-aux/check-mescc.sh: Likewise.
* install.sh: Likewise.
* scaffold/boot/51-module.scm: Likewise.
* scaffold/boot/52-define-module.scm: Likewise.
* scripts/mescc: Likewise.
* src/mes.c: Likewise.
* tests/base.test-guile: Likewise.
* tests/boot.test: Likewise.
* tests/srfi-9.test: Likewise.
* mes/include: New symlink.
* mes/lib: New symlink.
* AUTHORS: Update file names.

189 files changed:
AUTHORS
GNUmakefile
build-aux/build-guile.sh
build-aux/build-mes.sh
build-aux/check-boot.sh
build-aux/check-mescc.sh
build-aux/mes-snarf.scm
build-aux/test.sh
guile/gc.scm [deleted file]
guile/language [deleted symlink]
guile/mes [deleted symlink]
guile/mes-0.scm [deleted file]
guile/mes.mes [deleted file]
guile/mes.scm [deleted file]
guile/mescc [deleted symlink]
guile/reader.mes [deleted file]
install.sh
mes/include [new symlink]
mes/lib [new symlink]
mes/module/mes/base.mes [new file with mode: 0644]
mes/module/mes/boot-0.scm [new file with mode: 0644]
mes/module/mes/boot-00.scm [new file with mode: 0644]
mes/module/mes/boot-01.scm [new file with mode: 0644]
mes/module/mes/boot-02.scm [new file with mode: 0644]
mes/module/mes/catch.mes [new file with mode: 0644]
mes/module/mes/display.mes [new file with mode: 0644]
mes/module/mes/fluids.mes [new file with mode: 0644]
mes/module/mes/getopt-long.mes [new file with mode: 0644]
mes/module/mes/guile.mes [new file with mode: 0644]
mes/module/mes/lalr.mes [new file with mode: 0644]
mes/module/mes/lalr.scm [new file with mode: 0644]
mes/module/mes/let.mes [new file with mode: 0644]
mes/module/mes/match.mes [new file with mode: 0644]
mes/module/mes/match.scm [new file with mode: 0644]
mes/module/mes/mescc.mes [new file with mode: 0644]
mes/module/mes/misc.mes [new file with mode: 0644]
mes/module/mes/module.mes [new file with mode: 0644]
mes/module/mes/optargs.mes [new file with mode: 0644]
mes/module/mes/optargs.scm [new file with mode: 0644]
mes/module/mes/peg.mes [new file with mode: 0644]
mes/module/mes/peg/cache.scm [new file with mode: 0644]
mes/module/mes/peg/codegen.scm [new file with mode: 0644]
mes/module/mes/peg/simplify-tree.scm [new file with mode: 0644]
mes/module/mes/peg/string-peg.scm [new file with mode: 0644]
mes/module/mes/peg/using-parsers.scm [new file with mode: 0644]
mes/module/mes/pmatch.mes [new file with mode: 0644]
mes/module/mes/pmatch.scm [new file with mode: 0644]
mes/module/mes/posix.mes [new file with mode: 0644]
mes/module/mes/pretty-print.mes [new file with mode: 0644]
mes/module/mes/pretty-print.scm [new file with mode: 0644]
mes/module/mes/psyntax-0.mes [new file with mode: 0644]
mes/module/mes/psyntax-1.mes [new file with mode: 0644]
mes/module/mes/psyntax.mes [new file with mode: 0644]
mes/module/mes/psyntax.pp [new file with mode: 0644]
mes/module/mes/psyntax.ss [new file with mode: 0644]
mes/module/mes/quasiquote.mes [new file with mode: 0644]
mes/module/mes/quasisyntax.mes [new file with mode: 0644]
mes/module/mes/quasisyntax.scm [new file with mode: 0644]
mes/module/mes/repl.mes [new file with mode: 0644]
mes/module/mes/scm.mes [new file with mode: 0644]
mes/module/mes/syntax.mes [new file with mode: 0644]
mes/module/mes/syntax.scm [new file with mode: 0644]
mes/module/mes/test.mes [new file with mode: 0644]
mes/module/mes/tiny-0.mes [new file with mode: 0644]
mes/module/mes/type-0.mes [new file with mode: 0644]
mes/module/mescc/M1.mes [new file with mode: 0644]
mes/module/mescc/as.mes [new file with mode: 0644]
mes/module/mescc/bytevectors.mes [new file with mode: 0644]
mes/module/mescc/compile.mes [new file with mode: 0644]
mes/module/mescc/i386/as.mes [new file with mode: 0644]
mes/module/mescc/info.mes [new file with mode: 0644]
mes/module/mescc/mescc.mes [new file with mode: 0644]
mes/module/mescc/preprocess.mes [new file with mode: 0644]
mes/module/nyacc/lalr.mes [new file with mode: 0644]
mes/module/nyacc/lang/c99/cpp.mes [new file with mode: 0644]
mes/module/nyacc/lang/c99/parser.mes [new file with mode: 0644]
mes/module/nyacc/lang/c99/pprint.mes [new file with mode: 0644]
mes/module/nyacc/lang/calc/parser.mes [new file with mode: 0644]
mes/module/nyacc/lang/util.mes [new file with mode: 0644]
mes/module/nyacc/lex.mes [new file with mode: 0644]
mes/module/nyacc/parse.mes [new file with mode: 0644]
mes/module/nyacc/util.mes [new file with mode: 0644]
mes/module/rnrs/arithmetic/bitwise.mes [new file with mode: 0644]
mes/module/srfi/srfi-0.mes [new file with mode: 0644]
mes/module/srfi/srfi-1.mes [new file with mode: 0644]
mes/module/srfi/srfi-1.scm [new file with mode: 0644]
mes/module/srfi/srfi-13.mes [new file with mode: 0644]
mes/module/srfi/srfi-14.mes [new file with mode: 0644]
mes/module/srfi/srfi-16.mes [new file with mode: 0644]
mes/module/srfi/srfi-16.scm [new file with mode: 0644]
mes/module/srfi/srfi-26.mes [new file with mode: 0644]
mes/module/srfi/srfi-26.scm [new file with mode: 0644]
mes/module/srfi/srfi-43.mes [new file with mode: 0644]
mes/module/srfi/srfi-8.mes [new file with mode: 0644]
mes/module/srfi/srfi-9.mes [new file with mode: 0644]
mes/module/srfi/srfi-9/gnu.mes [new file with mode: 0644]
mes/module/sxml/xpath.mes [new file with mode: 0644]
mes/module/sxml/xpath.scm [new file with mode: 0644]
module/language/paren.mes [deleted file]
module/mes/base.mes [deleted file]
module/mes/boot-0.scm [deleted file]
module/mes/boot-00.scm [deleted file]
module/mes/boot-01.scm [deleted file]
module/mes/boot-02.scm [deleted file]
module/mes/catch.mes [deleted file]
module/mes/display.mes [deleted file]
module/mes/fluids.mes [deleted file]
module/mes/getopt-long.mes [deleted file]
module/mes/guile.mes [deleted file]
module/mes/lalr.mes [deleted file]
module/mes/lalr.scm [deleted file]
module/mes/let.mes [deleted file]
module/mes/match.mes [deleted file]
module/mes/match.scm [deleted file]
module/mes/mes-0.scm [new file with mode: 0644]
module/mes/mescc.mes [deleted file]
module/mes/misc.mes [deleted file]
module/mes/module.mes [deleted file]
module/mes/optargs.mes [deleted file]
module/mes/optargs.scm [deleted file]
module/mes/peg.mes [deleted file]
module/mes/peg/cache.scm [deleted file]
module/mes/peg/codegen.scm [deleted file]
module/mes/peg/simplify-tree.scm [deleted file]
module/mes/peg/string-peg.scm [deleted file]
module/mes/peg/using-parsers.scm [deleted file]
module/mes/pmatch.mes [deleted file]
module/mes/pmatch.scm [deleted file]
module/mes/posix.mes [deleted file]
module/mes/pretty-print.mes [deleted file]
module/mes/pretty-print.scm [deleted file]
module/mes/psyntax-0.mes [deleted file]
module/mes/psyntax-1.mes [deleted file]
module/mes/psyntax.mes [deleted file]
module/mes/psyntax.pp [deleted file]
module/mes/psyntax.ss [deleted file]
module/mes/quasiquote.mes [deleted file]
module/mes/quasisyntax.mes [deleted file]
module/mes/quasisyntax.scm [deleted file]
module/mes/repl.mes [deleted file]
module/mes/scm.mes [deleted file]
module/mes/syntax.mes [deleted file]
module/mes/syntax.scm [deleted file]
module/mes/test.mes [deleted file]
module/mes/test.scm
module/mes/tiny-0.mes [deleted file]
module/mes/type-0.mes [deleted file]
module/mescc/M1.mes [deleted file]
module/mescc/as.mes [deleted file]
module/mescc/bytevectors.mes [deleted file]
module/mescc/compile.mes [deleted file]
module/mescc/i386/as.mes [deleted file]
module/mescc/info.mes [deleted file]
module/mescc/mescc.mes [deleted file]
module/mescc/preprocess.mes [deleted file]
module/nyacc/lalr.mes [deleted file]
module/nyacc/lang/c99/cpp.mes [deleted file]
module/nyacc/lang/c99/parser.mes [deleted file]
module/nyacc/lang/c99/pprint.mes [deleted file]
module/nyacc/lang/calc/parser.mes [deleted file]
module/nyacc/lang/util.mes [deleted file]
module/nyacc/lex.mes [deleted file]
module/nyacc/parse.mes [deleted file]
module/nyacc/util.mes [deleted file]
module/rnrs/arithmetic/bitwise.mes [deleted file]
module/srfi/srfi-0.mes [deleted file]
module/srfi/srfi-1.mes [deleted file]
module/srfi/srfi-1.scm [deleted file]
module/srfi/srfi-13.mes [deleted file]
module/srfi/srfi-14.mes [deleted file]
module/srfi/srfi-16.mes [deleted file]
module/srfi/srfi-16.scm [deleted file]
module/srfi/srfi-26.mes [deleted file]
module/srfi/srfi-26.scm [deleted file]
module/srfi/srfi-43.mes [deleted file]
module/srfi/srfi-8.mes [deleted file]
module/srfi/srfi-9.mes [deleted file]
module/srfi/srfi-9/gnu.mes [deleted file]
module/sxml/xpath.mes [deleted file]
module/sxml/xpath.scm [deleted file]
scaffold/boot/51-module.scm
scaffold/boot/52-define-module.scm
scaffold/gc.scm [new file with mode: 0644]
scripts/mescc
src/mes.c
tests/base.test-guile
tests/boot.test
tests/srfi-13.test
tests/srfi-9.test

diff --git a/AUTHORS b/AUTHORS
index d2e9281dc49da9acbb527d2fe92edb01ee6ce36f..fdad0bd24a8ee82a5693166ddbc1514b8c7e2fbc 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -15,48 +15,45 @@ List of imported files
 D A Gwyn
 lib/alloca.c
 
-Based on Guile ECMAScript
-module/language/c/lexer.mes
-
 Included verbatim from gnulib
 build-aux/gitlog-to-changelog
 
 Portable hygienic pattern matcher
-module/mes/match.scm
+mes/module/mes/match.scm
 
 Portable LALR(1) parser generator
-module/mes/lalr.scm
+mes/module/mes/lalr.scm
 
 Portable syntax-case from Chez Scheme; patches from Guile
-module/mes/psyntax.ss
-module/mes/psyntax.pp [generated]
+mes/module/mes/psyntax.ss
+mes/module/mes/psyntax.pp [generated]
 
 Getopt-long from Guile
 module/mes/getopt-long.scm
 
 Optargs from Guile
-module/mes/optargs.scm
+mes/module/mes/optargs.scm
 
 PEG from Guile
-module/mes/peg/
+mes/module/mes/peg/
 
 Pmatch from Guile
-module/mes/pmatch.scm
+mes/module/mes/pmatch.scm
 
 Pretty-print from Guile
-module/mes/pretty-print.scm
+mes/module/mes/pretty-print.scm
 
 Srfi-1 bits from Guile
-module/srfi/srfi-1.scm
+mes/module/srfi/srfi-1.scm
 
 Srfi-16 from Guile
-module/srfi/srfi-16.scm
+mes/module/srfi/srfi-16.scm
 
 Srfi-26 from Guile
-module/srfi/srfi-26.scm
+mes/module/srfi/srfi-26.scm
 
 Sxml bits from Guile
-module/sxml/xpath.scm
+mes/module/sxml/xpath.scm
 
 GNU FDL in texinfo from GNU
 doc/fdl-1.3.texi
index 3fd2911049e92ce02f16759537fc110c1f041823..2587d960d93dd47e69fbcc5c2a8c24eb222a738c 100644 (file)
@@ -16,7 +16,7 @@
 # You should have received a copy of the GNU General Public License
 # along with Mes.  If not, see <http://www.gnu.org/licenses/>.
 
-GUILE_FLAGS:=--no-auto-compile -L . -L guile -C . -C guile
+GUILE_FLAGS:=--no-auto-compile -L . -L module -C . -C module
 
 include .config.make
 
@@ -24,7 +24,7 @@ include .config.make
        ./configure --prefix=$(prefix)
 
 PHONY_TARGETS:= all all-go build check clean clean-go default doc help install install-info man\
-cc mes mes-gcc mes-tcc
+gcc mes src/mes mes-gcc mes-tcc
 
 .PHONY: $(PHONY_TARGETS)
 
@@ -116,14 +116,13 @@ install-info: info
 
 man: doc/mes.1 doc/mescc.1
 
-doc/mes.1: src/mes.gcc-out
-       MES_ARENA=10000000 $(HELP2MAN) $< > $@
+src/mes: build
 
-src/mes.gcc-out:
-       $(MAKE) cc
+doc/mes.1: src/mes
+       MES_ARENA=10000000 ./pre-inst-env $(HELP2MAN) $< > $@
 
-doc/mescc.1: src/mes.gcc-out scripts/mescc
-       MES_ARENA=10000000 $(HELP2MAN) $< > $@
+doc/mescc.1: src/mes scripts/mescc
+       MES_ARENA=10000000 ./pre-inst-env $(HELP2MAN) $< > $@
 
 html: mes/index.html
 
index f4e9547df55ec20357b5206933b85e3358c5d528..0ba899b3cceddd984b48b4006db756e57714f361 100755 (executable)
@@ -31,17 +31,18 @@ GUILE_AUTO_COMPILE=0
 set -e
 
 SCM_FILES="
-guile/mes/guile.scm
-guile/mes/misc.scm
-guile/mes/test.scm
-guile/mescc/M1.scm
-guile/mescc/as.scm
-guile/mescc/bytevectors.scm
-guile/mescc/compile.scm
-guile/mescc/i386/as.scm
-guile/mescc/info.scm
-guile/mescc/mescc.scm
-guile/mescc/preprocess.scm
+module/mes/getopt-long.scm
+module/mes/guile.scm
+module/mes/misc.scm
+module/mes/test.scm
+module/mescc/M1.scm
+module/mescc/as.scm
+module/mescc/bytevectors.scm
+module/mescc/compile.scm
+module/mescc/i386/as.scm
+module/mescc/info.scm
+module/mescc/mescc.scm
+module/mescc/preprocess.scm
 "
 
 export srcdir=.
@@ -57,7 +58,7 @@ for i in $SCM_FILES; do
     go=${i%%.scm}.go
     if [ $i -nt $go ]; then
         echo "  GUILEC $i"
-        $GUILE_TOOLS compile -L ${abs}guile -L ${abs}scripts -o $go $i
+        $GUILE_TOOLS compile -L ${abs}module -L ${abs}scripts -o $go $i
     fi
 done
 
@@ -69,6 +70,6 @@ for i in $SCRIPTS; do
     go=${i%%.scm}.go
     if [ $i -nt $go ]; then
         echo "  GUILEC $i"
-        $GUILE_TOOLS compile -L ${abs}guile -L ${abs}scripts -o $go $i
+        $GUILE_TOOLS compile -L ${abs}module -L ${abs}scripts -o $go $i
     fi
 done
index d7395fa6d3315e799a55a27d7ffc5ecffd2fd1cd..cca170da5d534ea133f85929b32076a74d7db9f7 100755 (executable)
@@ -104,6 +104,7 @@ if [ ! -d "$MES_SEED" ] \
     MES_ARENA=100000000
 fi
 
+MES_ARENA=100000000
 ARCHDIR=1 NOLINK=1 bash build-aux/cc-mes.sh lib/crt0
 ARCHDIR=1 NOLINK=1 bash build-aux/cc-mes.sh lib/crt1
 ARCHDIR=1 NOLINK=1 bash build-aux/cc-mes.sh lib/crti
index 34844314d357a956824bc264fc46071b402b692c..8d29f43c680a93074ef801ca0556ec8aa221a68a 100755 (executable)
@@ -116,7 +116,7 @@ for i in $tests; do
         echo ' [SKIP]'
         continue;
     fi
-    $GUILE -L guile -L . <(echo '(use-modules (mes guile))'; cat scaffold/boot/$i) >& /dev/null
+    $GUILE -L module -C module -L . <(echo '(use-modules (mes guile))'; cat scaffold/boot/$i) >& /dev/null
     x=$(
         if [ -z "${i/5[0-9]-*/}" ]; then
             cat scaffold/boot/$i | MES_BOOT=boot-00.scm $MES 2>&1;
index 2d5940854959b5d54482c2da0fd9d66a66828253..0f9d294a13cc0cc45ddf6fb8d21f35987d49c230 100755 (executable)
@@ -31,7 +31,7 @@ export LIBC CC32LIBS MES_LIBS
 MES=${MES-src/mes}
 MESCC=${MESCC-scripts/mescc}
 GUILE=${GUILE-guile}
-MES_PREFIX=${MES_PREFIX-.}
+MES_PREFIX=${MES_PREFIX-mes}
 
 HEX2=${HEX2-hex2}
 M1=${M1-M1}
index ed57bc67af5de79bac1992d7595df272fa230d9c..7379e16c203dc4f447240a8bdb8c6b45ba0f62b1 100755 (executable)
@@ -1,6 +1,6 @@
 #! /bin/sh
 # -*-scheme-*-
-exec ${GUILE-guile} -L $(dirname 0) -e '(mes-snarf)' -s "$0" "$@"
+exec ${GUILE-guile} --no-auto-compile -L $(dirname $0) -C $(dirname $0) -e '(mes-snarf)' -s "$0" "$@"
 !#
 
 ;;; Mes --- Maxwell Equations of Software
@@ -218,7 +218,7 @@ exec ${GUILE-guile} -L $(dirname 0) -e '(mes-snarf)' -s "$0" "$@"
                   (string-join (map function->header functions (iota (length functions) (+ %start (length symbols)))) "")))
          (source (make-file
                   (string-append base-name ".i")
-                  (string-join (map function->source (filter (negate no-environment?) functions) (iota (length functions) (+ (length symbols) %start))) ""))) 
+                  (string-join (map function->source (filter (negate no-environment?) functions) (iota (length functions) (+ (length symbols) %start))) "")))
          (environment (make-file
                        (string-append base-name ".environment.i")
                        (string-join (map function->environment (filter (negate no-environment?) functions) (iota (length functions) (+ (length symbols) %start))) "")))
index 4cfc09893caf94d217ecb26da686a747df30a56b..7845fcc0dd004fed03f44adc68dadd0cd4482795 100755 (executable)
@@ -22,6 +22,8 @@ if [ -n "$BUILD_DEBUG" ]; then
     set -x
 fi
 
+MES_ARENA=100000000
+
 export LIBC MES_LIBS
 
 GUILE=${GUILE-$MES}
diff --git a/guile/gc.scm b/guile/gc.scm
deleted file mode 100644 (file)
index 2f680b7..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-;;; -*-scheme-*-
-
-;;; Mes --- Maxwell Equations of Software
-;;; Copyright © 2016 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; mes.mes: This file is part of Mes.
-;;;
-;;; Mes is free software; you can redistribute it and/or modify it
-;;; under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; This is an early SICP stop-and-copy garbage collector playground,
-;;; currently not used.
-
-;;; Code:
-
-(define-module (guile gc))
-
-(define (R) (reload-module (current-module)))
-
-(define gc-size 10)
-(define the-cars (make-vector gc-size '(* . *)))
-(define the-cdrs (make-vector gc-size '(* . *)))
-(define gc-free 0)
-(define (gc-show)
-  (display "\nfree:") (display gc-free) (newline)
-  (display "       0       1       2       3       4       5       6       7       8       9\n")
-  (display "cars:") (display the-cars) (newline)
-  (display "cdrs:") (display the-cdrs) (newline))
-
-(define (gc-show-new)
-  (display "\nfree:") (display gc-free) (newline)
-  (display "       0       1       2       3       4       5       6       7       8       9\n")
-  (display "ncar:") (display new-cars) (newline)
-  (display "ncdr:") (display new-cdrs) (newline))
-(gc-show)
-
-(define (gc-car c)
-  (vector-ref the-cars (cell-index c)))
-
-(define (gc-cdr c)
-  (vector-ref the-cdrs (cell-index c)))
-
-(define (gc-set-car! c x)
-  (if (gc-pair? c) (vector-set! the-cars (cell-index c) x)))
-
-(define (gc-set-cdr! c x)
-  (if (gc-pair? c) (vector-set! the-cdrs (cell-index c) x)))
-
-(define (gc-null? x) (eq? (car x) 'e))
-
-(define (gc-pair? c)
-  (and (pair? c) (eq? (car c) 'p)))
-
-(define (cell-index c)
-  (if (eq? (car c) 'p)
-      (cdr c)))
-
-(define (cell-value c)
-  (if (member (car c) '(n s))
-   (cdr c)))
-
-(define (make-cell type . x)
-  (cons type (if (pair? x) (car x) '*)))
-
-(define (gc-alloc)
-  (if (= gc-free gc-size) (gc))
-  ((lambda (index)
-     (set! gc-free (+ gc-free 1))
-     (make-cell 'p index))
-   gc-free))
-
-(define (make-number x)
-  ((lambda (cell)
-     (vector-set! the-cars (cell-index cell) (make-cell 'n x))
-     (gc-car cell))
-   (gc-alloc)))
-
-(define (make-symbol x)
-  ((lambda (cell)
-     (vector-set! the-cars (cell-index cell) (make-cell 's x))
-     (gc-car cell))
-   (gc-alloc)))
-
-(define (gc-cons x y)
-  ((lambda (cell)
-     (vector-set! the-cars (cell-index cell) x)
-     (vector-set! the-cdrs (cell-index cell) y)
-     cell)
-   (gc-alloc)))
-
-(define gc-nil (make-cell 'e 0))
-(define (gc-list . rest)
-  (if (null? rest) gc-nil
-      (gc-cons (car rest) (apply gc-list (cdr rest)))))
-
-(define (gc-display x . cont?)
-  (if (gc-pair? x) (begin (if (null? cont?) (display "("))
-                          (gc-display (gc-car x))
-                          (if (gc-pair? (gc-cdr x)) (display " "))
-                          (if (not (gc-null? (gc-cdr x)))
-                              (gc-display (gc-cdr x) #t))
-                          (if (null? cont?) (display ")")))
-      (if (gc-null? x) (if (not cont?) (display "()"))
-          (display (cell-value x)))))
-
-(define (gc-root)
-  (filter gc-pair? (module-map (lambda (x y) (variable-ref y)) (current-module)))
-  list1234)
-
-(define new-cars (make-vector gc-size '(* . *)))
-(define new-cdrs (make-vector gc-size '(* . *)))
-
-#!
-     begin-garbage-collection
-       (assign free (const 0))
-       (assign scan (const 0))
-       (assign old (reg root))
-       (assign relocate-continue
-               (label reassign-root))
-       (goto (label relocate-old-result-in-new))
-     reassign-root
-       (assign root (reg new))
-       (goto (label gc-loop))
-
-     gc-loop
-       (test (op =) (reg scan) (reg free))
-       (branch (label gc-flip))
-       (assign old
-               (op vector-ref)
-               (reg new-cars)
-               (reg scan))
-       (assign relocate-continue
-               (label update-car))
-       (goto (label relocate-old-result-in-new))
-
-
-     update-car
-       (perform (op vector-set!)
-                (reg new-cars)
-                (reg scan)
-                (reg new))
-       (assign  old
-                (op vector-ref)
-                (reg new-cdrs)
-                (reg scan))
-       (assign  relocate-continue
-                (label update-cdr))
-       (goto (label relocate-old-result-in-new))
-     update-cdr
-       (perform (op vector-set!)
-                (reg new-cdrs)
-                (reg scan)
-                (reg new))
-       (assign  scan (op +) (reg scan) (const 1))
-       (goto (label gc-loop))
-
-
-     relocate-old-result-in-new
-       (test (op pointer-to-pair?) (reg old))
-       (branch (label pair))
-       (assign new (reg old))
-       (goto (reg relocate-continue))
-     pair
-       (assign  oldcr
-                (op vector-ref)
-                (reg the-cars)
-                (reg old))
-       (test (op broken-heart?) (reg oldcr))
-       (branch  (label already-moved))
-       (assign  new (reg free)) ; new location for pair
-       ;; Update ‘free’ pointer.
-       (assign free (op +) (reg free) (const 1))
-       ;; Copy the ‘car’ and ‘cdr’ to new memory.
-       (perform (op vector-set!)
-                (reg new-cars)
-                (reg new)
-                (reg oldcr))
-       (assign  oldcr
-                (op vector-ref)
-                (reg the-cdrs)
-                (reg old))
-       (perform (op vector-set!)
-                (reg new-cdrs)
-                (reg new)
-                (reg oldcr))
-       ;; Construct the broken heart.
-       (perform (op vector-set!)
-                (reg the-cars)
-                (reg old)
-                (const broken-heart))
-       (perform (op vector-set!)
-                (reg the-cdrs)
-                (reg old)
-                (reg new))
-       (goto (reg relocate-continue))
-     already-moved
-       (assign  new
-                (op vector-ref)
-                (reg the-cdrs)
-                (reg old))
-       (goto (reg relocate-continue))
-
-     gc-flip
-       (assign temp (reg the-cdrs))
-       (assign the-cdrs (reg new-cdrs))
-       (assign new-cdrs (reg temp))
-       (assign temp (reg the-cars))
-       (assign the-cars (reg new-cars))
-       (assign new-cars (reg temp))
-
-!#
-
-(define (gc)
-  (let ((root (gc-root)))
-    (display "gc root=") (display root) (newline)
-    (set! gc-free 0)
-    (gc-relocate root)
-    (gc-loop 0)))
-
-(define (gc-loop scan)
-  (gc-show)
-  (gc-show-new)
-  (display "gc-loop scan=") (display scan) (newline)
-  (display "gc-loop free=") (display gc-free) (newline)
-
-  (if (eq? scan gc-free) (gc-flip)
-      (let ((old (vector-ref new-cars scan)))
-        (let ((new (gc-relocate old)))
-          (let ((old (gc-update-car scan new)))
-            (let ((new (gc-relocate old)))
-              (let ((scan (gc-update-cdr scan new)))
-                (gc-loop scan))))))))
-
-(define (gc-update-car scan new) ; -> old
-  (vector-set! new-cars scan new)
-  (vector-ref new-cdrs scan))
-
-(define (gc-update-cdr scan new)
-  (vector-set! new-cdrs scan new)
-  (+ 1 scan))
-
-(define (broken-heart? c) (eq? (car c) '<))
-(define gc-broken-heart '(< . 3))
-(define (gc-relocate old) ; old -> new
-  (display "gc-relocate old=") (display old) (newline)
-  (display "gc-relocate old is pair?=") (display (gc-pair? old)) (newline)
-
-  (if (not (gc-pair? old)) old
-      (let ((oldcr (vector-ref the-cars (cell-index old))))
-        (display "gc-relocate oldcr=") (display oldcr) (newline)
-        (if (broken-heart? oldcr) old
-            (let ((new (cons 'p gc-free)))
-              (set! gc-free (+ 1 gc-free))
-              (vector-set! new-cars (cell-index new) oldcr)
-              (let ((oldcr (vector-ref the-cdrs (cell-index old))))
-                (display "gc-relocate oldcr=") (display oldcr) (newline)
-                (vector-set! new-cdrs (cell-index new) oldcr)
-                (vector-set! the-cars (cell-index old) gc-broken-heart)
-                (vector-set! the-cdrs (cell-index old) new))
-              new)))))
-
-(define (gc-flip)
-  (let ((cars the-cars)
-        (cdrs the-cdrs))
-    (set! the-cars new-cars)
-    (set! the-cdrs new-cdrs)
-    (set! new-cars cars)
-    (set! new-cdrs cdrs))
-  (gc-show))
-
-(define first (make-symbol 'F)) (newline)
-
-(define one (make-number 1))
-(display "\n one=") (display one) (newline)
-(define two (make-number 2))
-(define pair2-nil (gc-cons two gc-nil))
-(display "\npair2-nil=") (display pair2-nil) (newline)
-(gc-show)
-
-(define list1-2 (gc-cons one pair2-nil))
-(display "\nlist1-2=") (display list1-2) (newline)
-(gc-show)
-
-(define three (make-number 3))
-(define four (make-number 4))
-(define pair4-nil (gc-cons four gc-nil))
-(define list3-4 (gc-cons three pair4-nil))
-(define list1234 (gc-cons list1-2 list3-4))
-(gc-show)
-
-(display "\nlist1-2=") (display list1-2) (newline)
-(display "\nlist3-4=") (display list3-4) (newline)
-(display "lst=") (display list1234) (newline)
-(gc-show)
-
-(display "sicp-lst:") (gc-display list1234) (newline)
-(gc-show)
-
-(display "\n**** trigger gc ****\n")
-(define next (gc-list (make-symbol 'N) (make-symbol 'X)))
-(set! list1234 '(p . 0))
-(display "sicp-lst:") (gc-display list1234) (newline)
-(gc-show)
-(display "next=") (display next) (newline)
-(display "gc-next=") (gc-display next) (newline)
-(gc-show)
diff --git a/guile/language b/guile/language
deleted file mode 120000 (symlink)
index 4f52fd3..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../module/language
\ No newline at end of file
diff --git a/guile/mes b/guile/mes
deleted file mode 120000 (symlink)
index cd5c453..0000000
--- a/guile/mes
+++ /dev/null
@@ -1 +0,0 @@
-../module/mes
\ No newline at end of file
diff --git a/guile/mes-0.scm b/guile/mes-0.scm
deleted file mode 100644 (file)
index e671457..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-;;; -*-scheme-*-
-
-;;; Mes --- Maxwell Equations of Software
-;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; mes-0.scm: This file is part of Mes.
-;;;
-;;; Mes is free software; you can redistribute it and/or modify it
-;;; under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; mes-0.scm is the first file being loaded into Guile.  It provides
-;;; non-standard definitions that Mes modules and tests depend on.
-
-;;; Code:
-
-(define-macro (mes-use-module . rest) #t)
-(define builtin? procedure?) ; not strictly true, but ok for tests/*.test
-(cond-expand
- (mes)
- (guile-2)
- (guile
-  (use-modules (ice-9 syncase))))
-(define EOF (if #f #f))
-(define append2 append)
diff --git a/guile/mes.mes b/guile/mes.mes
deleted file mode 100644 (file)
index 87ac308..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-;;; -*-scheme-*-
-
-;;; Mes --- Maxwell Equations of Software
-;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; mes.mes: This file is part of Mes.
-;;;
-;;; Mes is free software; you can redistribute it and/or modify it
-;;; under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-;; The Maxwell Equations of Software -- John McCarthy page 13
-;; http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf
-
-(define (caar x) (car (car x)))
-(define (cadr x) (car (cdr x)))
-(define (cdar x) (cdr (car x)))
-(define (cddr x) (cdr (cdr x)))
-(define (caadr x) (car (car (cdr x))))
-(define (caddr x) (car (cdr (cdr x))))
-(define (cddar x) (cdr (cdr (car x))))
-(define (cdadr x) (cdr (car (cdr x))))
-(define (cadar x) (car (cdr (car x))))
-(define (cdddr x) (cdr (cdr (cdr x))))
-
-;; Page 12
-(define (pairlis x y a)
-  (cond
-   ((null? x) a)
-   ((atom? x) (cons (cons x y) a))
-   (#t (cons (cons (car x) (car y))
-             (pairlis (cdr x) (cdr y) a)))))
-
-(define (assq x a)
-  (cond
-   ((null? a) #f)
-   ((eq? (caar a) x) (car a))
-   (#t (assq x (cdr a)))))
-
-(define (assq-ref-env x a)
-  (let ((e (assq x a)))
-    (if (eq? e #f) '*undefined* (cdr e))))
-
-;; Page 13
-(define (evcon c a)
-  (cond
-   ((null? c) *unspecified*)
-   ;; single-statement cond
-   ;; ((eval (caar c) a) (eval (cadar c) a))
-   ((eval (caar c) a)
-    (cond ((null? (cddar c)) (eval (cadar c) a))
-          (#t (eval (cadar c) a)
-              (evcon
-               (cons (cons #t (cddar c)) '())
-               a))))
-   (#t (evcon (cdr c) a))))
-
-(define (evlis-env m a)
-  (cond
-   ((null? m) '())
-   ((not (pair? m)) (eval-env m a))
-   (#t (cons (eval-env (car m) a) (evlis-env (cdr m) a)))))
-
-(define (apply-env fn x a) 
-  (cond
-   ((atom? fn)
-    (cond
-     ((builtin? fn) (call fn x))
-     ((eq? fn 'call-with-values) (call call-with-values-env (append x (cons a '()))))
-     ((eq? fn 'current-module) a)))
-   ((eq? (car fn) 'lambda)
-    (let ((p (pairlis (cadr fn) x a)))
-      (eval-begin-env (cddr fn) (cons (cons '*closure* p) p))))
-   ((eq? (car fn) '*closure*)
-    (let ((args (caddr fn))
-          (body (cdddr fn))
-          (a (cddr (cadr fn))))
-      (let ((p (pairlis args x a)))
-        (eval-begin-env body (cons (cons '*closure* p) p)))))
-   ;;((eq? (car fn) 'label) (apply-env (caddr fn) x (cons (cons (cadr fn) (caddr fn)) a)))
-   (#t (apply-env (eval-env fn a) x a))))
-
-;;return make_cell_ (tmp_num_ (TCLOSURE), cell_f, cons (cons (cell_circular, a), cons (formals, body)));
-(define (make-closure formals body a)
-  (cons (cons '*closure* #f) (cons (cons '*circ* a) (cons formals body))))
-
-(define (eval-expand e a)
-  (cond
-   ((eq? e '*undefined*) e)
-   ((symbol? e) (assq-ref-env e a))
-   ((atom? e) e)
-   ((atom? (car e))
-    (cond
-     ((eq? (car e) 'quote) (cadr e))
-     ((eq? (car e) 'syntax) (cadr e))
-     ((eq? (car e) 'begin) (eval-begin-env e a))
-     ((eq? (car e) 'lambda) e)
-     ((eq? (car e) 'lambda) (make-closure (cadr e) (cddr e) (assq '*closure* a)))
-     ((eq? (car e) '*closure*) e)
-     ((eq? (car e) 'if) (eval-if-env (cdr e) a))
-     ((eq? (car e) 'define) (env:define (cons (sexp:define e a) '()) a))
-     ((eq? (car e) 'define-macro) (env:define (env:macro (sexp:define e a)) a))
-     ((eq? (car e) 'set!) (set-env! (cadr e) (eval-env (caddr e) a) a))
-     ((eq? (car e) 'apply-env) (apply-env (eval-env (cadr e) a) (evlis-env (caddr e) a) a))
-     ((eq? (car e) 'unquote) (eval-env (cadr e) a))
-     ((eq? (car e) 'quasiquote) (eval-quasiquote (cadr e) (add-unquoters a)))
-     (#t (apply-env (eval-env (car e) a) (evlis-env (cdr e) a) a))))
-   (#t (apply-env (eval-env (car e) a) (evlis-env (cdr e) a) a))))
-
-(define (unquote x) (cons 'unquote x))
-(define (unquote-splicing x) (cons 'quasiquote x))
-
-(define %the-unquoters
-  (cons
-   (cons 'unquote unquote)
-   (cons (cons 'unquote-splicing unquote-splicing) '())))
-
-(define (add-unquoters a)
-  (cons %the-unquoters a))
-
-(define (eval-env e a)
-  (eval-expand (macro-expand-env e a) a))
-
-(define (macro-expand-env e a)
-  (if (pair? e) ((lambda (macro)
-                   (if macro (macro-expand-env (apply-env macro (cdr e) a) a)
-                       e))
-                 (lookup-macro (car e) a))
-      e))
-
-(define (eval-begin-env e a)
-  (if (null? e) *unspecified*
-      (if (null? (cdr e)) (eval-env (car e) a)
-          (begin
-            (eval-env (car e) a)
-            (eval-begin-env (cdr e) a)))))
-
-(define (eval-if-env e a)
-  (if (eval-env (car e) a) (eval-env (cadr e) a)
-      (if (pair? (cddr e)) (eval-env (caddr e) a))))
-
-;; (define (eval-quasiquote e a)
-;;   (cond ((null? e) e)
-;;         ((atom? e) e)
-;;         ((eq? (car e) 'unquote) (eval-env (cadr e) a))
-;;         ((and (pair? (car e))
-;;               (eq? (caar e) 'unquote-splicing))
-;;          (append2 (eval-env (cadar e) a) (eval-quasiquote (cdr e) a)))
-;;         (#t (cons (eval-quasiquote (car e) a) (eval-quasiquote (cdr e) a)))))
-
-(define (sexp:define e a)
-  (if (atom? (cadr e)) (cons (cadr e) (eval-env (caddr e) a))
-      (cons (caadr e) (eval-env (cons 'lambda (cons (cdadr e) (cddr e))) a))))
-
-(define (env:define a+ a)
-  (set-cdr! a+ (cdr a))
-  (set-cdr! a a+)
-  (set-cdr! (assq '*closure* a) a))
-
-(define (env:macro name+entry)
-  (cons
-   (cons (car name+entry)
-         (make-macro (car name+entry)
-                     (cdr name+entry)))
-   '()))
diff --git a/guile/mes.scm b/guile/mes.scm
deleted file mode 100755 (executable)
index b903265..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-#! /bin/sh
-# -*-scheme-*-
-exec guile -L $(pwd) -e '(mes)' -s "$0" "$@"
-!#
-
-;;; Mes --- The Maxwell Equations of Software
-;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; This file is part of GNU Guix.
-;;;
-;;; Mes is free software; you can redistribute it and/or modify it
-;;; under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-;; The Maxwell Equations of Software -- John McCarthy page 13
-;; http://www.softwarepreservation.org/projects/LISP/book/LISP%201.5%20Programmers%20Manual.pdf
-
-(define-module (mes)
-  #:export (main))
-
-(let ((guile (resolve-interface
-              '(guile)
-              #:select `(
-                         ;; Debugging
-                         apply
-                         cons*
-                         current-module
-                         display
-                         eof-object?
-                         eval
-                         exit
-                         force-output
-                         format
-                         list
-                         map
-                         newline
-                         read
-                         
-                         ;; Guile admin
-                         module-define!
-                         resolve-interface
-                         
-                         ;; PRIMITIVE BUILTINS
-                         car
-                         cdr
-                         cons
-                         eq?
-                         null?
-                         pair?
-                         *unspecified*
-                         
-                         ;; READER
-                         char->integer
-                         integer->char
-                         
-                         ;; non-primitive BUILTINS
-                         char?
-                         number?
-                         procedure?
-                         string?
-                         <
-                         -
-                         )
-              #:renamer (symbol-prefix-proc 'guile:)))
-      (guile-2.0 (resolve-interface '(guile) #:select '(define)))
-      (guile-2.2 (resolve-interface '(guile) #:select '(quasiquote unquote)))
-      (ports (resolve-interface
-              (if (equal? (effective-version) "2.0")'(guile) '(ice-9 ports))
-                  #:select '(
-                             ;; Debugging
-                             current-error-port
-                             current-output-port
-                             
-                             ;; READER
-                             ;;peek-char
-                             read-char
-                             unread-char)
-                  #:renamer (symbol-prefix-proc 'guile:))))
-  (set-current-module
-   (make-module 10 `(,guile ,guile-2.0 ,guile-2.2 ,ports))))
-
-(define (logf port string . rest)
-  (guile:apply guile:format (guile:cons* port string rest))
-  (guile:force-output port)
-  #t)
-
-(define (stderr string . rest)
-  (guile:apply logf (guile:cons* (guile:current-error-port) string rest)))
-
-(define (stdout string . rest)
-  (guile:apply logf (guile:cons* (guile:current-output-port) string rest)))
-
-(define (debug . x) #t)
-(define debug stderr)
-
-;; TODO
-(define (atom? x)
-  (cond
-   ((guile:pair? x) #f)
-   ((guile:null? x) #f)
-   (#t #t)))
-
-;; PRIMITIVES
-(define car guile:car)
-(define cdr guile:cdr)
-(define cons guile:cons)
-(define eq? guile:eq?)
-(define null? guile:null?)
-(define pair? guile:pair?)
-(define builtin? guile:procedure?)
-(define char? guile:char?)
-(define number? guile:number?)
-(define string? guile:number?)
-(define call guile:apply)
-(define (peek-byte)
-  (unread-byte (read-byte)))
-;;(define peek-byte guile:peek-char)
-(define (read-byte)
-  (char->integer (guile:read-char)))
-(define (unread-byte x)
-  (guile:unread-char (guile:integer->char x))
-  x)
-(define (lookup x a)
-  ;; TODO
-  (stderr "lookup x=~a\n" x)
-  x)
-
-(define (char->integer c)
-  (if (guile:eof-object? c) -1 (guile:char->integer c)))
-
-(include "mes.mes")
-;; guile-2.2 only, guile-2.0 has no include?
-(include "reader.mes")
-
-(define (append2 x y)
-  (cond ((null? x) y)
-        (#t (cons (car x) (append2 (cdr x) y)))))
-
-;; READER: TODO lookup
-(define (read)
-  (let ((x (guile:read)))
-    (if (guile:eof-object? x) '()
-        x)))
-
-(define (lookup-macro e a)
-  #f)
-
-(define guile:dot '#{.}#)
-
-(define environment
-  (guile:map
-   (lambda (x) (cons (car x) (guile:eval (cdr x) (guile:current-module))))
-   '(
-     (*closure* . #t)
-     ((guile:list) . (guile:list))
-     (#t . #t)
-     (#f . #f)
-    
-     (*unspecified* . guile:*unspecified*)
-
-     (atom? . atom?)
-     (car . car)
-     (cdr . cdr)
-     (cons . cons)
-     ;; (cond . evcon)
-     (eq? . eq?)
-
-     (null? . null?)
-     (pair? . guile:pair?)
-     ;; (quote . quote)
-
-     (evlis-env . evlis-env)
-     (evcon . evcon)
-     (pairlis . pairlis)
-     (assq . assq)
-     (assq-ref-env . assq-ref-env)
-
-     (eval-env . eval-env)
-     (apply-env . apply-env)
-
-     (read . read)
-     (display . guile:display)
-     (newline . guile:newline)
-
-     (builtin? . builtin?)
-     (number? . number?)
-     (call . call)
-
-     (< . guile:<)
-     (- . guile:-)
-
-     ;; DERIVED
-     (caar . caar)
-     (cadr . cadr)
-     (cdar . cdar)
-     (cddr . cddr)
-     (caadr . caadr)
-     (caddr . caddr)
-     (cdadr . cdadr)
-     (cadar . cadar)
-     (cddar . cddar)
-     (cdddr . cdddr)
-
-     (append2 . append2)
-     (exit . guile:exit)
-
-     (*macro* . (guile:list))
-     (*dot* . guile:dot)
-
-     ;;
-     (stderr . stderr))))
-
-(define (main arguments)
-  (let ((program (cons 'begin (read-input-file))))
-    (stderr "program:~a\n" program)
-    (stderr "=> ~s\n" (eval-env program environment)))
-  (guile:newline))
-
-(guile:module-define! (guile:resolve-interface '(mes)) 'main main)
diff --git a/guile/mescc b/guile/mescc
deleted file mode 120000 (symlink)
index 540fb2d..0000000
+++ /dev/null
@@ -1 +0,0 @@
-../module/mescc
\ No newline at end of file
diff --git a/guile/reader.mes b/guile/reader.mes
deleted file mode 100644 (file)
index c00582b..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-;;; -*-scheme-*-
-
-;;; Mes --- Maxwell Equations of Software
-;;; Copyright © 2016 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
-;;;
-;;; This file is part of Mes.
-;;;
-;;; Mes is free software; you can redistribute it and/or modify it
-;;; under the terms of the GNU General Public License as published by
-;;; the Free Software Foundation; either version 3 of the License, or (at
-;;; your option) any later version.
-;;;
-;;; Mes is distributed in the hope that it will be useful, but
-;;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;;; GNU General Public License for more details.
-;;;
-;;; You should have received a copy of the GNU General Public License
-;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; copy of mes/read-0.mes, comment-out read-input-file
-
-;;; Code:
-
-(begin
-
-  ;; (define car (make-function 'car 0))
-  ;; (define cdr (make-function 'cdr 1))
-  ;; (define cons (make-function 'cons 1))
-
-  ;; TODO:
-  ;; * use case/cond, expand
-  ;; * etc int/char?
-  ;; * lookup in Scheme
-  ;; * read characters, quote, strings
-
-  (define (read)
-    (read-word (read-byte) (list) (current-module)))
-
-  (define (read-input-file)
-    (define (helper x)
-      (if (null? x) x
-          (cons x (helper (read)))))
-    (helper (read)))
-
-  (define-macro (cond . clauses)
-    (list (quote if) (null? clauses) *unspecified*
-          (if (null? (cdr clauses))
-              (list (quote if) (car (car clauses))
-                    (list (cons (quote lambda) (cons (list) (cons (car (car clauses)) (cdr (car clauses))))))
-                    *unspecified*)
-              (if (eq? (car (cadr clauses)) (quote else))
-                  (list (quote if) (car (car clauses))
-                        (list (cons (quote lambda) (cons (list) (car clauses))))
-                        (list (cons (quote lambda) (cons (list) (cons *unspecified* (cdr (cadr clauses)))))))
-                  (list (quote if) (car (car clauses))
-                        (list (cons (quote lambda) (cons (list) (car clauses))))
-                        (cons (quote cond) (cdr clauses)))))))
-
-  (define (eat-whitespace)
-    (cond
-     ((eq? (peek-byte) 9) (read-byte) (eat-whitespace))
-     ((eq? (peek-byte) 10) (read-byte) (eat-whitespace))
-     ((eq? (peek-byte) 13) (read-byte) (eat-whitespace))
-     ((eq? (peek-byte) 32) (read-byte) (eat-whitespace))
-     ((eq? (peek-byte) 59) (begin (read-line-comment (read-byte))
-                                  (eat-whitespace)))
-     ((eq? (peek-byte) 35) (begin (read-byte)
-                                  (if (eq? (peek-byte) 33) (begin (read-byte)
-                                                                  (read-block-comment (read-byte))
-                                                                  (eat-whitespace))
-                                      (unread-byte 35))))))
-
-  (define (read-block-comment c)
-    (if (eq? c 33) (if (eq? (peek-byte) 35) (read-byte)
-                       (read-block-comment (read-byte)))
-        (read-block-comment (read-byte))))
-
-  ;; (define (read-hex c)
-  ;;   (if (eq? c 10) c
-  ;;       (read-line-comment (read-byte))))
-
-  (define (read-line-comment c)
-    (if (eq? c 10) c
-        (read-line-comment (read-byte))))
-
-  (define (read-list a)
-    (eat-whitespace)
-    (if (eq? (peek-byte) 41) (begin (read-byte) (list))
-        ((lambda (w)
-           (if (eq? w *dot*) (car (read-list a))
-               (cons w (read-list a))))
-         (read-word (read-byte) (list) a))))
-
-  ;;(define (read-string))
-
-  (define (lookup-char c a)
-    (lookup (cons (integer->char c) (list)) a))
-
-  (define (read-word c w a)
-    (cond
-      ((eq? c -1) (list))
-      ((eq? c 10) (if (null? w) (read-word (read-byte) (list) a)
-                      (lookup w a)))
-      ((eq? c 32) (read-word 10 w a))
-      ((eq? c 34) (if (null? w) (read-string)
-                      (begin (unread-byte c) (lookup w a))))
-      ((eq? c 35) (cond
-                   ((eq? (peek-byte) 33) (begin (read-byte)
-                                                (read-block-comment (read-byte))
-                                                (read-word (read-byte) w a)))
-                   ((eq? (peek-byte) 40) (read-byte) (list->vector (read-list a)))
-                   ((eq? (peek-byte) 92) (read-byte) (read-character))
-                   ((eq? (peek-byte) 120) (read-byte) (read-hex))
-                   (else (read-word (read-byte) (append2 w (cons (integer->char c) (list))) a))))
-      ((eq? c 39) (if (null? w) (cons (lookup (cons (integer->char c) (list)) a)
-                                      (cons (read-word (read-byte) w a) (list)))
-                      (begin (unread-byte c) (lookup w a))))
-      ((eq? c 40) (if (null? w) (read-list a)
-                      (begin (unread-byte c) (lookup w a))))
-      ((eq? c 41) (if (null? w) (cons (lookup (cons (integer->char c) (list)) a)
-                                      (cons (read-word (read-byte) w a) (list)))
-                      (begin (unread-byte c) (lookup w a))))
-      ((eq? c 44) (cond
-                   ((eq? (peek-byte) 64) (begin (read-byte)
-                                                (cons
-                                                 (lookup (symbol->list (quote unquote-splicing)) a)
-                                                 (cons (read-word (read-byte) w a) (list)))))
-                   (else  (cons (lookup-char c a) (cons (read-word (read-byte) w a)
-                                                        (list))))))
-      ((eq? c 96) (cons (lookup-char c a) (cons (read-word (read-byte) w a) (list))))
-      ((eq? c 59) (read-line-comment c) (read-word 10 w a))
-      (else (read-word (read-byte) (append2 w (cons (integer->char c) (list))) a))))
-
-  ;; ((lambda (p)
-  ;;    ;;(display (quote program=)) (display p) (newline)
-  ;;    (begin-env p (current-module)))
-  ;;  (read-input-file))
-  )
index 9ff242e1ef7ed3b5e0413d51b6beda38deccafe8..88bb2db8a50c92752cb6692cd51ab3369f077ab5 100755 (executable)
@@ -15,6 +15,15 @@ MES_PREFIX=${MES_PREFIX-$prefix/share/mes}
 MES_SEED=${MES_SEED-../MES-SEED}
 TINYCC_SEED=${TINYCC_SEED-../TINYCC-SEED}
 
+GUILE_EFFECTIVE_VERSION=${GUILE_EFFECTIVE_VERSION-2.2}
+datadir=${moduledir-$prefix/share/mes}
+docdir=${moduledir-$prefix/share/doc/mes}
+mandir=${mandir-$prefix/share/man}
+moduledir=${moduledir-$datadir/module}
+guile_site_dir=${guile_site_dir-$prefix/share/guile/site/$GUILE_EFFECTIVE_VERSION}
+guile_site_ccache_dir=${guile_site_ccache_dir-$prefix/lib/guile/$GUILE_EFFECTIVE_VERSION/site-ccache}
+docdir=${moduledir-$prefix/share/doc/mes}
+
 mkdir -p $DESTDIR$prefix/bin
 cp src/mes $DESTDIR$prefix/bin/mes
 
@@ -23,21 +32,18 @@ mkdir -p $DESTDIR$MES_PREFIX/lib
 cp scripts/mescc $DESTDIR$prefix/bin/mescc
 
 mkdir -p $DESTDIR$MES_PREFIX
-tar -cf- doc guile include lib module scaffold | tar -xf- -C $DESTDIR$MES_PREFIX
+tar -cf- doc include lib scaffold | tar -xf- -C $DESTDIR$MES_PREFIX
+tar -cf- --exclude='*.go' module | tar -xf- -C $DESTDIR$MES_PREFIX
+tar -cf- -C mes module | tar -xf- -C $DESTDIR$MES_PREFIX
 
-GUILE_EFFECTIVE_VERSION=${GUILE_EFFECTIVE_VERSION-2.2}
-datadir=${moduledir-$prefix/share/mes}
-docdir=${moduledir-$prefix/share/doc/mes}
-mandir=${mandir-$prefix/share/man}
-moduledir=${moduledir-$datadir/module}
-guile_site_dir=${moduledir-$prefix/share/guile/site/$GUILE_EFFECTIVE_VERSION}
-guile_site_ccache_dir=${guile_site_ccache_dir-$prefix/lib/guile/$GUILE_EFFECTIVE_VERSION/site-ccache}
-docdir=${moduledir-$prefix/share/doc/mes}
+mkdir -p $DESTDIR$guile_site_dir
+mkdir -p $DESTDIR$guile_site_ccache_dir
+tar -cf- -C module --exclude='*.go' . | tar -xf- -C $DESTDIR$guile_site_dir
+tar -cf- -C module --exclude='*.scm' . | tar -xf- -C $DESTDIR$guile_site_ccache_dir
 
 chmod +w $DESTDIR$prefix/bin/mescc
 sed \
     -e "s,^#! /bin/sh,#! $SHELL," \
-    -e "s,module/,$moduledir/," \
     -e "s,@datadir@,$datadir,g" \
     -e "s,@docdir@,$docdir,g" \
     -e "s,@guile_site_ccache_dir@,$guile_site_ccache_dir,g" \
@@ -49,7 +55,7 @@ sed \
 chmod +w $DESTDIR$moduledir/mes/boot-0.scm
 sed \
     -e "s,^#! /bin/sh,#! $SHELL," \
-    -e "s,module/,$moduledir/," \
+    -e "s,mes/module/,$moduledir/," \
     -e "s,@datadir@,$datadir,g" \
     -e "s,@docdir@,$docdir,g" \
     -e "s,@guile_site_ccache_dir@,$guile_site_ccache_dir,g" \
@@ -57,7 +63,7 @@ sed \
     -e "s,@moduledir@,$moduledir,g" \
     -e "s,@prefix@,$prefix,g" \
     -e "s,@VERSION@,$VERSION,g" \
-    module/mes/boot-0.scm > $DESTDIR$moduledir/mes/boot-0.scm
+    mes/module/mes/boot-0.scm > $DESTDIR$moduledir/mes/boot-0.scm
 
 sed \
     -e "s,^#! /bin/sh,#! $SHELL," \
diff --git a/mes/include b/mes/include
new file mode 120000 (symlink)
index 0000000..f5030fe
--- /dev/null
@@ -0,0 +1 @@
+../include
\ No newline at end of file
diff --git a/mes/lib b/mes/lib
new file mode 120000 (symlink)
index 0000000..dc598c5
--- /dev/null
+++ b/mes/lib
@@ -0,0 +1 @@
+../lib
\ No newline at end of file
diff --git a/mes/module/mes/base.mes b/mes/module/mes/base.mes
new file mode 100644 (file)
index 0000000..51d0f48
--- /dev/null
@@ -0,0 +1,119 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+
+;;; Commentary:
+
+;;; base.mes is being loaded after base-0.mes.  It provides the minimal
+;;; set of scheme primitives to run lib/test.mes.  It is safe to be
+;;; run by Guile.
+
+;;; Code:
+
+(define (caar x) (car (car x)))
+(define (cadr x) (car (cdr x)))
+(define (cdar x) (cdr (car x)))
+(define (cddr x) (cdr (cdr x)))
+
+
+(define (caaar x) (car (car (car x))))
+(define (caadr x) (car (car (cdr x))))
+(define (cadar x) (car (cdr (car x))))
+(define (caddr x) (car (cdr (cdr x))))
+
+(define (cdaar x) (cdr (car (car x))))
+(define (cdadr x) (cdr (car (cdr x))))
+(define (cddar x) (cdr (cdr (car x))))
+(define (cdddr x) (cdr (cdr (cdr x))))
+
+
+
+(define (caaaar x) (car (car (car (car x)))))
+(define (caaadr x) (car (car (car (cdr x)))))
+(define (caadar x) (car (car (cdr (car x)))))
+(define (caaddr x) (car (car (cdr (cdr x)))))
+
+(define (cadaar x) (car (cdr (car (car x)))))
+(define (cadadr x) (car (cdr (car (cdr x)))))
+(define (caddar x) (car (cdr (cdr (car x)))))
+(define (cadddr x) (car (cdr (cdr (cdr x)))))
+
+
+(define (cdaaar x) (cdr (car (car (car x)))))
+(define (cdaadr x) (cdr (car (car (cdr x)))))
+(define (cdadar x) (cdr (car (cdr (car x)))))
+(define (cdaddr x) (cdr (car (cdr (cdr x)))))
+
+(define (cddaar x) (cdr (cdr (car (car x)))))
+(define (cddadr x) (cdr (cdr (car (cdr x)))))
+(define (cdddar x) (cdr (cdr (cdr (car x)))))
+(define (cddddr x) (cdr (cdr (cdr (cdr x)))))
+
+
+
+(define (identity x) x)
+(define call/cc call-with-current-continuation)
+
+(define (command-line) %argv)
+(define (read) (read-env (current-module)))
+
+(define-macro (and . x)
+  (if (null? x) #t
+      (if (null? (cdr x)) (car x)
+          (list 'if (car x) (cons 'and (cdr x))
+                #f))))
+
+(define-macro (or . x)
+  (if (null? x) #f
+      (if (null? (cdr x)) (car x)
+          (list (list 'lambda (list 'r)
+                      (list 'if 'r 'r
+                            (cons 'or (cdr x))))
+                (car x)))))
+
+(define (and=> value procedure) (and value (procedure value)))
+(define eqv? eq?)
+
+(define (equal? . x)
+  (if (or (null? x) (null? (cdr x))) #t
+      (if (null? (cddr x)) (equal2? (car x) (cadr x))
+          (and (equal2? (car x) (cadr x))
+               (apply equal? (cdr x))))))
+
+(define (list? x)
+  (or (null? x)
+      (and (pair? x) (list? (cdr x)))))
+
+(define (procedure? p)
+  (cond ((builtin? p) #t)
+        ((and (pair? p) (eq? (car p) 'lambda)))
+        ((closure? p) #t)
+        (#t #f)))
+
+(define (map f h . t)
+  (if (null? h) '()
+      (if (null? t) (cons (f (car h)) (map f (cdr h)))
+          (if (null? (cdr t))
+              (cons (f (car h) (caar t)) (map f (cdr h) (cdar t)))
+              (if (null? (cddr t))
+                  (cons (f (car h) (caar t) (caadr t)) (map f (cdr h) (cdar t) (cdadr t)))
+                  (if (null? (cdddr t))
+                      (cons (f (car h) (caar t) (caadr t) (car (caddr t))) (map f (cdr h) (cdar t) (cdadr t) (cdr (caddr t))))
+                      (error 'unsupported (cons* "map 5:" f h t))) )))))
diff --git a/mes/module/mes/boot-0.scm b/mes/module/mes/boot-0.scm
new file mode 100644 (file)
index 0000000..bac5b6a
--- /dev/null
@@ -0,0 +1,310 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; read-0.mes - bootstrap reader.  This file is read by a minimal
+;;; core reader.  It only supports s-exps and line-comments; quotes,
+;;; character literals, string literals cannot be used here.
+
+;;; Code:
+
+;; boot-00.scm
+(define mes %version)
+
+(define (defined? x)
+  (assq x (current-module)))
+
+(define (cond-expand-expander clauses)
+  (if (defined? (car (car clauses)))
+      (cdr (car clauses))
+      (cond-expand-expander (cdr clauses))))
+
+(define-macro (cond-expand . clauses)
+  (cons 'begin (cond-expand-expander clauses)))
+;; end boot-00.scm
+
+;; boot-01.scm
+(define (pair? x) (eq? (core:type x) <cell:pair>))
+(define (not x) (if x #f #t))
+
+(define (display x . rest)
+  (if (null? rest) (core:display x)
+      (core:display-port x (car rest))))
+
+(define (write x . rest)
+  (if (null? rest) (core:write x)
+      (core:write-port x (car rest))))
+
+(define (list->string lst)
+  (core:make-cell <cell:string> lst 0))
+
+(define (integer->char x)
+  (core:make-cell <cell:char> 0 x))
+
+(define (newline . rest)
+  (core:display (list->string (list (integer->char 10)))))
+
+(define (string->list s)
+  (core:car s))
+
+(define (cadr x) (car (cdr x)))
+
+(define (map1 f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map1 f (cdr lst)))))
+
+(define (map f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map f (cdr lst)))))
+
+(define (cons* . rest)
+  (if (null? (cdr rest)) (car rest)
+      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
+
+(define (apply f h . t)
+  (if (null? t) (core:apply f h (current-module))
+      (apply f (apply cons* (cons h t)))))
+
+(define (append . rest)
+  (if (null? rest) '()
+      (if (null? (cdr rest)) (car rest)
+          (append2 (car rest) (apply append (cdr rest))))))
+;; end boot-01.scm
+
+;; boot-02.scm
+(define-macro (and . x)
+  (if (null? x) #t
+      (if (null? (cdr x)) (car x)
+          (list (quote if) (car x) (cons (quote and) (cdr x))
+                #f))))
+
+(define-macro (or . x)
+  (if (null? x) #f
+      (if (null? (cdr x)) (car x)
+          (list (list (quote lambda) (list (quote r))
+                      (list (quote if) (quote r) (quote r)
+                            (cons (quote or) (cdr x))))
+                (car x)))))
+
+(define-macro (module-define! module name value)
+  ;;(list 'define name value)
+  #t)
+
+(define-macro (mes-use-module module)
+  #t)
+;; end boot-02.scm
+
+;; boot-0.scm
+(define (primitive-eval e) (core:eval e (current-module)))
+(define eval core:eval)
+
+(define (current-output-port) 1)
+(define (current-error-port) 2)
+(define (port-filename port) "<stdin>")
+(define (port-line port) 0)
+(define (port-column port) 0)
+(define (ftell port) 0)
+(define (false-if-exception x) x)
+
+(define (cons* . rest)
+  (if (null? (cdr rest)) (car rest)
+      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
+
+(define (apply f h . t)
+  (if (null? t) (core:apply f h (current-module))
+      (apply f (apply cons* (cons h t)))))
+
+(define-macro (cond . clauses)
+  (list 'if (pair? clauses)
+        (list (cons
+               'lambda
+               (cons
+                '(test)
+                (list (list 'if 'test
+                            (if (pair? (cdr (car clauses)))
+                                (if (eq? (car (cdr (car clauses))) '=>)
+                                    (append2 (cdr (cdr (car clauses))) '(test))
+                                    (list (cons 'lambda (cons '() (cons 'test (cdr (car clauses)))))))
+                                (list (cons 'lambda (cons '() (cons 'test (cdr (car clauses)))))))
+                            (if (pair? (cdr clauses))
+                                (cons 'cond (cdr clauses)))))))
+              (car (car clauses)))))
+
+(define else #t)
+
+(define-macro (load file)
+  (list 'begin
+        (list 'if (list 'and (list getenv "MES_DEBUG")
+                        (list not (list equal2? (list getenv "MES_DEBUG") "0"))
+                        (list not (list equal2? (list getenv "MES_DEBUG") "1")))
+              (list 'begin
+                    (list core:display-error ";;; read ")
+                    (list core:display-error file)
+                    (list core:display-error "\n")))
+     (list 'primitive-load file)))
+
+(define-macro (include file) (list 'load file))
+
+(define (append . rest)
+  (if (null? rest) '()
+      (if (null? (cdr rest)) (car rest)
+          (append2 (car rest) (apply append (cdr rest))))))
+
+(define (string->list s)
+  (core:car s))
+
+(define %prefix (getenv "MES_PREFIX"))
+(define %moduledir
+  (if (not %prefix) "mes/module/"
+      (list->string
+       (append (string->list %prefix) (string->list "/module/" )))))
+
+(include (list->string
+          (append2 (string->list %moduledir) (string->list "mes/type-0.mes"))))
+
+(define (symbol->string s)
+  (apply string (symbol->list s)))
+
+(define (string-append . rest)
+  (apply string (apply append (map1 string->list rest))))
+
+(define %version (if (eq? (car (string->list "@VERSION@")) #\@) "git"
+                     "@VERSION@"))
+(define (effective-version) %version)
+
+(if (list 'and (list getenv "MES_DEBUG")
+          (list not (list equal2? (list getenv "MES_DEBUG") "0"))
+          (list not (list equal2? (list getenv "MES_DEBUG") "1")))
+    (begin
+      (core:display-error ";;; %moduledir=")
+      (core:display-error %moduledir)
+      (core:display-error "\n")))
+
+(define-macro (include-from-path file)
+  (list 'load (list string-append %moduledir file)))
+
+(define (string-join lst infix)
+  (if (null? lst) ""
+      (if (null? (cdr lst)) (car lst)
+          (string-append (car lst) infix (string-join (cdr lst) infix)))))
+
+(include-from-path "mes/module.mes")
+
+(mes-use-module (mes base))
+(mes-use-module (mes quasiquote))
+(mes-use-module (mes let))
+(mes-use-module (mes scm))
+(mes-use-module (srfi srfi-1))
+(mes-use-module (srfi srfi-13))
+(mes-use-module (mes fluids))
+(mes-use-module (mes catch))
+(mes-use-module (mes posix))
+
+(define-macro (include-from-path file)
+  (let loop ((path (cons* %moduledir "module" (string-split (or (getenv "GUILE_LOAD_PATH")) #\:))))
+    (cond ((and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 2)) string->number))
+           (core:display-error (string-append "include-from-path: " file " [PATH:" (string-join path ":") "]\n")))
+          ((and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 1)) string->number))
+           (core:display-error (string-append "include-from-path: " file "\n"))))
+    (if (null? path) (error "include-from-path: not found: " file)
+        (let ((file (string-append (car path) "/" file)))
+          (if (access? file R_OK) `(load ,file)
+              (loop (cdr path)))))))
+
+(define-macro (define-module module . rest)
+  `(if ,(and (pair? module)
+             (= 1 (length module))
+             (symbol? (car module)))
+       (define (,(car module) . arguments) (main (command-line)))))
+
+(define-macro (use-modules . rest) #t)
+
+(mes-use-module (mes getopt-long))
+
+(define %main #f)
+(primitive-load 0)
+(let ((tty? (isatty? 0)))
+  (define (parse-opts args)
+    (let* ((option-spec
+            '((compiled-path (single-char #\C) (value #t))
+              (dump)
+              (help (single-char #\h))
+              (load)
+              (load-path (single-char #\L) (value #t))
+              (main (single-char #\e) (value #t))
+              (source (single-char #\s) (value #t))
+              (version (single-char #\V)))))
+      (getopt-long args option-spec #:stop-at-first-non-option #t)))
+  (define (source-arg? o)
+    (equal? "-s" o))
+  (let* ((s-index (list-index source-arg? %argv))
+         (args (if s-index (list-head %argv (+ s-index 2)) %argv))
+         (options (parse-opts args))
+         (main (option-ref options 'main #f))
+         (source (option-ref options 'source #f))
+         (files (if s-index (list-tail %argv (+ s-index 1))
+                    (option-ref options '() '())))
+         (help? (option-ref options 'help #f))
+         (usage? (and (not help?) (null? files) (not tty?) (not main)))
+         (version? (option-ref options 'version #f)))
+    (or
+     (and version?
+          (display (string-append "mes (Mes) " %version "\n"))
+          (exit 0))
+     (and (or help? usage?)
+          (display "Usage: mes [OPTION]... [FILE]...
+Evaluate code with Mes, interactively or from a script.
+
+  [-s] FILE           load source code from FILE, and exit
+  --                  stop scanning arguments; run interactively
+
+The above switches stop argument processing, and pass all
+remaining arguments as the value of (command-line).
+
+  -C,--compiled-path=DIR
+                      ignored for Guile compatibility
+  --dump              dump binary program to stdout
+  -e,--main=MAIN      after reading script, apply MAIN to command-line arguments
+  -h, --help          display this help and exit
+  --load              load binary program [module/mes/boot-0.32-mo]
+  -L,--load-path=DIR  add DIR to the front of the module load path
+  -v, --version       display version information and exit
+" (or (and usage? (current-error-port)) (current-output-port)))
+          (exit (or (and usage? 2) 0)))
+     options)
+    (if main (set! %main main))
+    (and=> (option-ref options 'load-path #f)
+           (lambda (dir)
+             (setenv "GUILE_LOAD_PATH" (string-append dir ":" (getenv "GUILE_LOAD_PATH")))))
+    (cond ((pair? files)
+           (let* ((file (car files))
+                  (port (if (equal? file "-") 0
+                            (open-input-file file))))
+             (set! %argv files)
+             (set-current-input-port port)))
+          ((and (null? files) tty?)
+
+           (mes-use-module (mes repl))
+           (set-current-input-port 0)
+           (repl))
+          (else #t))))
+(primitive-load 0)
+(primitive-load (open-input-string %main))
diff --git a/mes/module/mes/boot-00.scm b/mes/module/mes/boot-00.scm
new file mode 100644 (file)
index 0000000..977a9ed
--- /dev/null
@@ -0,0 +1,34 @@
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;; boot-00.scm
+(define mes %version)
+
+(define (defined? x)
+  (assq x (current-module)))
+
+(define (cond-expand-expander clauses)
+  (if (defined? (car (car clauses)))
+      (cdr (car clauses))
+      (cond-expand-expander (cdr clauses))))
+
+(define-macro (cond-expand . clauses)
+  (cons 'begin (cond-expand-expander clauses)))
+;; end boot-00.scm
+
+(primitive-load 0)
diff --git a/mes/module/mes/boot-01.scm b/mes/module/mes/boot-01.scm
new file mode 100644 (file)
index 0000000..d8d9a62
--- /dev/null
@@ -0,0 +1,80 @@
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;; boot-00.scm
+(define mes %version)
+
+(define (defined? x)
+  (assq x (current-module)))
+
+(define (cond-expand-expander clauses)
+  (if (defined? (car (car clauses)))
+      (cdr (car clauses))
+      (cond-expand-expander (cdr clauses))))
+
+(define-macro (cond-expand . clauses)
+  (cons 'begin (cond-expand-expander clauses)))
+;; end boot-00.scm
+
+;; boot-01.scm
+(define (pair? x) (eq? (core:type x) <cell:pair>))
+(define (not x) (if x #f #t))
+
+(define (display x . rest)
+  (if (null? rest) (core:display x)
+      (core:display-port x (car rest))))
+
+(define (write x . rest)
+  (if (null? rest) (core:write x)
+      (core:write-port x (car rest))))
+
+(define (list->string lst)
+  (core:make-cell <cell:string> lst 0))
+
+(define (integer->char x)
+  (core:make-cell <cell:char> 0 x))
+
+(define (newline . rest)
+  (core:display (list->string (list (integer->char 10)))))
+
+(define (string->list s)
+  (core:car s))
+
+(define (cadr x) (car (cdr x)))
+
+(define (map1 f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map1 f (cdr lst)))))
+
+(define map map1)
+
+(define (cons* . rest)
+  (if (null? (cdr rest)) (car rest)
+      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
+
+(define (apply f h . t)
+  (if (null? t) (core:apply f h (current-module))
+      (apply f (apply cons* (cons h t)))))
+
+(define (append . rest)
+  (if (null? rest) '()
+      (if (null? (cdr rest)) (car rest)
+          (append2 (car rest) (apply append (cdr rest))))))
+;; end boot-01.scm
+
+(primitive-load 0)
diff --git a/mes/module/mes/boot-02.scm b/mes/module/mes/boot-02.scm
new file mode 100644 (file)
index 0000000..1783744
--- /dev/null
@@ -0,0 +1,119 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; read-0.mes - bootstrap reader.  This file is read by a minimal
+;;; core reader.  It only supports s-exps and line-comments; quotes,
+;;; character literals, string literals cannot be used here.
+
+;;; Code:
+
+;; boot-00.scm
+(define mes %version)
+
+(define (defined? x)
+  (assq x (current-module)))
+
+(define (cond-expand-expander clauses)
+  (if (defined? (car (car clauses)))
+      (cdr (car clauses))
+      (cond-expand-expander (cdr clauses))))
+
+(define-macro (cond-expand . clauses)
+  (cons 'begin (cond-expand-expander clauses)))
+;; end boot-00.scm
+
+;; boot-01.scm
+(define (pair? x) (eq? (core:type x) <cell:pair>))
+(define (not x) (if x #f #t))
+
+(define (display x . rest)
+  (if (null? rest) (core:display x)
+      (core:display-port x (car rest))))
+
+(define (write x . rest)
+  (if (null? rest) (core:write x)
+      (core:write-port x (car rest))))
+
+(define (list->string lst)
+  (core:make-cell <cell:string> lst 0))
+
+(define (integer->char x)
+  (core:make-cell <cell:char> 0 x))
+
+(define (newline . rest)
+  (core:display (list->string (list (integer->char 10)))))
+
+(define (string->list s)
+  (core:car s))
+
+(define (cadr x) (car (cdr x)))
+
+(define (map1 f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map1 f (cdr lst)))))
+
+(define (map f lst)
+  (if (null? lst) (list)
+      (cons (f (car lst)) (map f (cdr lst)))))
+
+(define (cons* . rest)
+  (if (null? (cdr rest)) (car rest)
+      (cons (car rest) (core:apply cons* (cdr rest) (current-module)))))
+
+(define (apply f h . t)
+  (if (null? t) (core:apply f h (current-module))
+      (apply f (apply cons* (cons h t)))))
+
+(define (append . rest)
+  (if (null? rest) '()
+      (if (null? (cdr rest)) (car rest)
+          (append2 (car rest) (apply append (cdr rest))))))
+;; end boot-01.scm
+
+;; boot-02.scm
+(define-macro (and . x)
+  (if (null? x) #t
+      (if (null? (cdr x)) (car x)
+          (list (quote if) (car x) (cons (quote and) (cdr x))
+                #f))))
+
+(define-macro (or . x)
+  (if (null? x) #f
+      (if (null? (cdr x)) (car x)
+          (list (list (quote lambda) (list (quote r))
+                      (list (quote if) (quote r) (quote r)
+                            (cons (quote or) (cdr x))))
+                (car x)))))
+
+(define-macro (module-define! module name value)
+  ;;(list 'define name value)
+  #t)
+
+(define-macro (mes-use-module module)
+  #t)
+
+(define-macro (define-module module . rest)
+  #t)
+
+;; end boot-02.scm
+
+(primitive-load 0)
diff --git a/mes/module/mes/catch.mes b/mes/module/mes/catch.mes
new file mode 100644 (file)
index 0000000..9ea0dec
--- /dev/null
@@ -0,0 +1,56 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+(mes-use-module (mes let))
+(mes-use-module (mes fluids))
+
+(define %eh (make-fluid
+             (lambda (key . args)
+               (if #f ;;(defined? 'simple-format)
+                   (simple-format (current-error-port) "unhandled exception:~a:~a\n" key args)
+                   (begin
+                     (core:display-error "unhandled exception:")
+                     (core:display-error key)
+                     (core:display-error ":")
+                     (core:write-error args)
+                     (core:display-error "\n")))
+               (exit 1))))
+
+(define (catch key thunk handler)
+  (let ((previous-eh (fluid-ref %eh)))
+    (with-fluid*
+        %eh #f
+        (lambda ()
+          (call/cc
+           (lambda (cc)
+             (fluid-set! %eh
+                         (lambda (k . args)
+                           (let ((handler (if (or (eq? key #t) (eq? key k)) handler
+                                              previous-eh)))
+                             (cc
+                              (lambda (x)
+                                (apply handler (cons k args)))))))
+             (thunk)))))))
+
+(define (throw key . args)
+  (let ((handler (fluid-ref %eh)))
+    (apply handler (cons key args))))
+
+(define with-throw-handler catch) ; FIXME: hack for Nyacc 0.75
diff --git a/mes/module/mes/display.mes b/mes/module/mes/display.mes
new file mode 100644 (file)
index 0000000..110a947
--- /dev/null
@@ -0,0 +1,222 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(mes-use-module (mes scm))
+
+(define (srfi-1:member x lst eq)
+  (if (null? lst) #f
+      (if (eq x (car lst)) lst
+          (srfi-1:member x (cdr lst) eq))))
+
+(define (next-xassq x a)
+  (and=> (srfi-1:member x a (lambda (x e) (eq? x (cdr e))))
+         (lambda (a) (xassq x (cdr a)))))
+
+(define (next-xassq2 x a)
+  (and=> (srfi-1:member x a (lambda (x e) (eq? x (cdr e))))
+         (lambda (a)
+           (and=> (srfi-1:member x (cdr a) (lambda (x e) (eq? x (cdr e))))
+                  (lambda (a) (xassq x (cdr a)))))))
+
+(define-macro (display-cut f slot n1)
+  `(lambda (slot) (,f slot ,n1)))
+
+(define-macro (display-cut2 f slot n1 n2)
+  `(lambda (slot) (,f slot ,n1 ,n2)))
+
+(define (display x . rest)
+  (let* ((port (if (null? rest) (current-output-port) (car rest)))
+         (write? (and (pair? rest) (pair? (cdr rest)) (cadr rest))))
+
+    (define (display-char x port write?)
+      (cond ((and write? (or (eq? x #\") (eq? x #\\)))
+             (write-char #\\ port)
+             (write-char x port))
+            ((and write? (eq? x #\nul))
+             (write-char #\\ port)
+             (write-char #\0 port))
+            ((and write? (eq? x #\alarm))
+             (write-char #\\ port)
+             (write-char #\a port))
+            ((and write? (eq? x #\backspace))
+             (write-char #\\ port)
+             (write-char #\b port))
+            ((and write? (eq? x #\tab))
+             (write-char #\\ port)
+             (write-char #\t port))
+            ((and write? (eq? x #\newline))
+             (write-char #\\ port)
+             (write-char #\n port))
+            ((and write? (eq? x #\vtab))
+             (write-char #\\ port)
+             (write-char #\v port))
+            ((and write? (eq? x #\page))
+             (write-char #\\ port)
+             (write-char #\f port))
+            (#t (write-char x port))))
+
+    (define (d x cont? sep)
+      (for-each (display-cut write-char <> port) (string->list sep))
+      (cond
+       ((eof-object? x)
+        (display "#<eof>" port))
+       ((char? x)
+        (if (not write?) (write-char x port)
+            (let ((name (and=> (assq x '((#\nul . nul)
+                                         (#\alarm . alarm)
+                                         (#\backspace . backspace)
+                                         (#\tab . tab)
+                                         (#\newline . newline)
+                                         (#\vtab . vtab)
+                                         (#\page . page)
+                                         (#\return . return)
+                                         (#\space . space)))
+                               cdr)))
+              (write-char #\# port)
+              (write-char #\\ port)
+              (if name (display name port)
+                  (write-char x port)))))
+       ((closure? x)
+        (display "#<procedure " port)
+        (let ((name (and=> (next-xassq2 x (current-module)) car)))
+          (display name port))
+        (display " " port)
+        (display (cadr (core:cdr x)) port)
+        (display ">" port))
+       ((continuation? x)
+        (display "#<continuation " port)
+        (display (core:car x) port)
+        (display ">" port))
+       ((macro? x)
+        (display "#<macro " port)
+        (display (core:cdr x) port)
+        (display ">" port))
+       ((port? x)
+        (display "#<port " port)
+        (display (core:cdr x) port)
+        (display (core:car x) port)
+        (display ">" port))
+       ((variable? x)
+        (display "#<variable " port)
+        (write (list->string (car (core:car x))) port)
+        (display ">" port))
+       ((number? x)
+        (display (number->string x) port))
+       ((pair? x)
+        (if (not cont?) (write-char #\( port))
+        (cond ((eq? (car x) '*circular*)
+               (display "*circ* . #-1#)" port))
+              ((eq? (car x) '*closure*)
+               (display "*closure* . #-1#)" port))
+              (#t
+               (display (car x) port write?)
+               (if (pair? (cdr x)) (d (cdr x) #t " ")
+                   (if (and (cdr x) (not (null? (cdr x))))
+                       (begin
+                         (display " . " port)
+                         (display (cdr x) port write?))))))
+        (if (not cont?) (write-char #\) port)))
+       ((or (keyword? x) (special? x) (string? x) (symbol? x))
+        (if (and (string? x) write?) (write-char #\" port))
+        (if (keyword? x) (display "#:" port))
+        (for-each (display-cut2 display-char <> port write?) (string->list x))
+        (if (and (string? x) write?) (write-char #\" port)))
+       ((vector? x)
+        (display "#(" port)
+        (for-each (lambda (i)
+                    (let ((x (vector-ref x i)))
+                      (if (vector? x)
+                          (begin
+                            (display (if (= i 0) "" " ") port)
+                            (display "#(...)" port))
+                          (d x #f (if (= i 0) "" " ")))))
+                  (iota (vector-length x)))
+        (display ")" port))
+       ((function? x)
+        (display "#<procedure " port)
+        (display (core:car x) port)
+        (display " " port)
+        (display
+         (case (core:arity x)
+           ((-1) "_")
+           ((0) "()")
+           ((1) "(_)")
+           ((2) "(_ _)")
+           ((3) "(_ _ _)"))
+         port)
+        (display ">" port))
+       ((broken-heart? x)
+        (display "<3" port))
+       (#t
+        (display "TODO type=") (display (cell:type-name x)) (newline)))
+      *unspecified*)
+    (d x #f "")))
+
+(define (write-char x . rest)
+  (apply write-byte (cons (char->integer x) rest)))
+
+(define (write x . rest)
+  (let ((port (if (null? rest) (current-output-port) (car rest))))
+    (display x port #t)))
+
+(define (newline . rest)
+  (apply display (cons "\n" rest)))
+
+(define (with-output-to-string thunk)
+  (define save-write-byte write-byte)
+  (let ((stdout '()))
+    (set! write-byte
+          (lambda (x . rest)
+            (let ((out? (or (null? rest) (eq? (car rest) (current-output-port)))))
+              (if (not out?) (apply save-write-byte (cons x rest))
+                  (begin
+                    (set! stdout (append stdout (list (integer->char x))))
+                    x)))))
+    (thunk)
+    (let ((r (apply string stdout)))
+      (set! write-byte save-write-byte)
+      r)))
+
+(define (simple-format destination format . rest)
+  (let ((port (if (boolean? destination) (current-output-port) destination))
+        (lst (string->list format)))
+    (define (simple-format lst args)
+      (if (pair? lst)
+          (let ((c (car lst)))
+            (if (not (eq? c #\~)) (begin (write-char (car lst) port)
+                                         (simple-format (cdr lst) args))
+                (let ((c (cadr lst)))
+                  (case c
+                    ((#\A) (display (car args) port))
+                    ((#\a) (display (car args) port))
+                    ((#\S) (write (car args) port))
+                    ((#\s) (write (car args) port))
+                    (else (display (car args) port)))
+                  (simple-format (cddr lst) (cdr args)))))))
+    
+    (if destination (simple-format lst rest)
+        (with-output-to-string
+          (lambda () (simple-format lst rest))))))
+
+(define format simple-format)
diff --git a/mes/module/mes/fluids.mes b/mes/module/mes/fluids.mes
new file mode 100644 (file)
index 0000000..9761b8f
--- /dev/null
@@ -0,0 +1,102 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(mes-use-module (mes scm))
+
+
+(define (sexp:define e a)
+  (if (atom? (car (cdr e))) (cons (car (cdr e))
+                                  (core:eval (car (cdr (cdr e))) a))
+      (cons (car (car (cdr e)))
+            (core:eval (cons (quote lambda)
+                             (cons (cdr (car (cdr e))) (cdr (cdr e)))) a))))
+
+(define (f:env:define a+ a)
+  (set-cdr! a+ (cdr a))
+  (set-cdr! a a+)
+  ;;(set-cdr! (assq '*closure* a) a+)
+  )
+
+(define (env:escape-closure a n)
+  (if (eq? (caar a) '*closure*) (if (= 0 n) a
+                                    (env:escape-closure (cdr a) (- n 1)))
+      (env:escape-closure (cdr a) n)))
+
+(define-macro (module-define! name value a)
+  `(f:env:define (cons (sexp:define (cons 'define (cons ',name (cons ,value '()))) ,a) '()) (env:escape-closure ,a 1)))
+
+(define-macro (make-fluid . default)
+  `(begin
+     ,(let ((fluid (symbol-append 'fluid: (gensym)))
+            (module (current-module)))
+        `(begin
+           (module-define! ,fluid
+                           (let ((v ,(and (pair? default) (car default))))
+                             (lambda ( . rest)
+                               (if (null? rest) v
+                                   (set! v (car rest))))) ',module)
+           ',fluid))))
+
+(define (fluid-ref fluid)
+  (fluid))
+
+(define (fluid-set! fluid value)
+  (fluid value))
+
+(define-macro (fluid? fluid)
+  `(begin
+     (and (symbol? ,fluid)
+          (symbol-prefix? 'fluid: ,fluid))))
+
+(define (with-fluid* fluid value thunk)
+  (let ((v (fluid)))
+    (fluid-set! fluid value)
+    (let ((r (thunk)))
+      (fluid-set! fluid v)
+      r)))
+
+;; (define-macro (with-fluids*-macro fluids values thunk)
+;;   `(begin
+;;      ,@(map (lambda (f v) (list 'set! f v)) fluids values)
+;;      (,thunk)))
+
+;; (define (with-fluids*-next fluids values thunk)
+;;   `(with-fluids*-macro ,fluids ,values ,thunk))
+
+;; (define (with-fluids* fluids values thunk)
+;;   (primitive-eval (with-fluids*-next fluids values thunk)))
+
+(define-macro (with-fluids bindings . bodies)
+  (let ((syms (map gensym bindings)))
+    `(let ,(map (lambda (b s) `(,s (,b))) (map car bindings) syms)
+       ,@(map (lambda (o) `(fluid-set! ,(car o) ,(cadr o))) bindings)
+       (let ((r (begin ,@bodies)))
+         `,@(map (lambda (b s) `(fluid-set! ,b ,s)) (map car bindings) syms)
+         r))))
+
+(define (dynamic-wind in-guard thunk out-guard)
+  (in-guard)
+  (let ((r (thunk)))
+    (out-guard)
+    r))
diff --git a/mes/module/mes/getopt-long.mes b/mes/module/mes/getopt-long.mes
new file mode 100644 (file)
index 0000000..b2c66fd
--- /dev/null
@@ -0,0 +1,29 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(mes-use-module (srfi srfi-1))
+(mes-use-module (srfi srfi-9))
+(mes-use-module (srfi srfi-13))
+(mes-use-module (mes optargs))
+(include-from-path "mes/getopt-long.scm")
diff --git a/mes/module/mes/guile.mes b/mes/module/mes/guile.mes
new file mode 100644 (file)
index 0000000..b59135b
--- /dev/null
@@ -0,0 +1,140 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(mes-use-module (srfi srfi-13))
+
+(define-macro (cond-expand-provide . rest) #t)
+
+(mes-use-module (mes catch))
+(mes-use-module (mes posix))
+(mes-use-module (srfi srfi-16))
+(mes-use-module (mes display))
+
+(if #t ;;(not (defined? 'read-string))
+    (define (read-string)
+      (define (read-string c)
+        (if (eq? c #\*eof*) '()
+            (cons c (read-string (read-char)))))
+      (let ((string (list->string (read-string (read-char)))))
+        (if (and=> (getenv "MES_DEBUG") (compose (lambda (o) (> o 3)) string->number))
+            (core:display-error (string-append "drained: `" string "'\n")))
+        string)))
+
+(define (drain-input port) (read-string))
+
+(define (make-string n . fill)
+  (list->string (apply make-list n fill)))
+
+(define (object->string x . rest)
+  (with-output-to-string
+    (lambda () ((if (pair? rest) (car rest) write) x))))
+
+(define (port-filename p) "<stdin>")
+(define (port-line p) 0)
+
+(define (with-input-from-string string thunk)
+  (let ((prev (set-current-input-port (open-input-string string)))
+        (r (thunk)))
+    (set-current-input-port prev)
+    r))
+
+(define (with-input-from-file file thunk)
+  (let ((port (open-input-file file)))
+    (if (= port -1)
+        (error 'no-such-file file)
+        (let* ((save (current-input-port))
+               (foo (set-current-input-port port))
+               (r (thunk)))
+          (set-current-input-port save)
+          r))))
+
+(define (with-output-to-file file thunk)
+  (let ((port (open-output-file file)))
+    (if (= port -1)
+        (error 'cannot-open file)
+        (let* ((save (current-output-port))
+               (foo (set-current-output-port port))
+               (r (thunk)))
+          (set-current-output-port save)
+          r))))
+
+(define (with-output-to-port port thunk)
+  (let* ((save (current-output-port))
+         (foo (set-current-output-port port))
+         (r (thunk)))
+    (set-current-output-port save)
+    r))
+
+(define core:open-input-file open-input-file)
+(define (open-input-file file)
+  (let ((port (core:open-input-file file))
+        (debug (and=> (getenv "MES_DEBUG") string->number)))
+    (when (and debug (> debug 1))
+      (core:display-error (string-append "open-input-file: `" file "'"))
+      (when (> debug 3)
+        (core:display-error " port=")
+        (core:display-error port)))
+    (core:display-error "\n")
+    port))
+
+(define (dirname file-name)
+  (let ((lst (filter (negate string-null?) (string-split file-name #\/))))
+    (if (<= (length lst) 1) "."
+        (string-join (list-head lst (1- (length lst))) "/"))))
+
+;; FIXME: c&p from display
+(define (with-output-to-string thunk)
+  (define save-write-byte write-byte)
+  (let ((stdout '()))
+    (set! write-byte
+          (lambda (x . rest)
+            (let ((out? (or (null? rest) (eq? (car rest) (current-output-port)))))
+              (if (not out?) (apply save-write-byte (cons x rest))
+                  (begin
+                    (set! stdout (append stdout (list (integer->char x))))
+                    x)))))
+    (thunk)
+    (let ((r (apply string stdout)))
+      (set! write-byte save-write-byte)
+      r)))
+
+;; FIXME: c&p from display
+(define (simple-format destination format . rest)
+  (let ((port (if (boolean? destination) (current-output-port) destination))
+        (lst (string->list format)))
+    (define (simple-format lst args)
+      (if (pair? lst)
+          (let ((c (car lst)))
+            (if (not (eq? c #\~)) (begin (write-char (car lst) port)
+                                         (simple-format (cdr lst) args))
+                (let ((c (cadr lst)))
+                  (case c
+                    ((#\a) (display (car args) port))
+                    ((#\s) (write (car args) port)))
+                  (simple-format (cddr lst) (cdr args)))))))
+
+    (if destination (simple-format lst rest)
+        (with-output-to-string
+          (lambda () (simple-format lst rest))))))
+(define format simple-format)
diff --git a/mes/module/mes/lalr.mes b/mes/module/mes/lalr.mes
new file mode 100644 (file)
index 0000000..dadc40e
--- /dev/null
@@ -0,0 +1,28 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; lalr
+
+(mes-use-module (mes scm))
+(mes-use-module (mes syntax))
+(mes-use-module (srfi srfi-9))
+(include-from-path "mes/lalr.scm")
diff --git a/mes/module/mes/lalr.scm b/mes/module/mes/lalr.scm
new file mode 100644 (file)
index 0000000..87b63c5
--- /dev/null
@@ -0,0 +1,2120 @@
+;;;
+;;;; An Efficient and Portable LALR(1) Parser Generator for Scheme
+;;;
+;; Copyright 2014  Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;; Copyright 1993, 2010 Dominique Boucher
+;;
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public License
+;; as published by the Free Software Foundation, either version 3 of
+;; the License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU Lesser General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+
+(define *lalr-scm-version* "2.5.0")
+
+(cond-expand 
+
+ ;; -- Gambit-C
+ (gambit
+
+   (display "Gambit-C!")
+   (newline)
+   
+  (define-macro (def-macro form . body)
+    `(define-macro ,form (let () ,@body)))
+
+  (def-macro (BITS-PER-WORD) 28)
+  (def-macro (logical-or x . y) `(bitwise-ior ,x ,@y))
+  (def-macro (lalr-error msg obj) `(error ,msg ,obj))
+
+  (define pprint pretty-print)
+  (define lalr-keyword? keyword?)
+  (define (note-source-location lvalue tok) lvalue))
+ ;; -- 
+ (bigloo
+  (define-macro (def-macro form . body)
+    `(define-macro ,form (let () ,@body)))
+
+  (define pprint (lambda (obj) (write obj) (newline)))
+  (define lalr-keyword? keyword?)
+  (def-macro (BITS-PER-WORD) 29)
+  (def-macro (logical-or x . y) `(bit-or ,x ,@y))
+  (def-macro (lalr-error msg obj) `(error "lalr-parser" ,msg ,obj))
+  (define (note-source-location lvalue tok) lvalue))
+ ;; -- Chicken
+ (chicken
+  
+  (define-macro (def-macro form . body)
+    `(define-macro ,form (let () ,@body)))
+
+  (define pprint pretty-print)
+  (define lalr-keyword? symbol?)
+  (def-macro (BITS-PER-WORD) 30)
+  (def-macro (logical-or x . y) `(bitwise-ior ,x ,@y))
+  (def-macro (lalr-error msg obj) `(error ,msg ,obj))
+  (define (note-source-location lvalue tok) lvalue))
+
+ ;; -- STKlos
+ (stklos
+  (require "pp")
+
+  (define (pprint form) (pp form :port (current-output-port)))
+
+  (define lalr-keyword? keyword?)
+  (define-macro (BITS-PER-WORD) 30)
+  (define-macro (logical-or x . y) `(bit-or ,x ,@y))
+  (define-macro (lalr-error msg obj) `(error 'lalr-parser ,msg ,obj))
+  (define (note-source-location lvalue tok) lvalue))
+
+ ;; -- Guile
+ (guile
+  (use-modules (ice-9 pretty-print))
+  (use-modules (srfi srfi-9))
+
+  (define pprint pretty-print)
+  (define lalr-keyword? symbol?)
+  (define-macro (BITS-PER-WORD) 30)
+  (define-macro (logical-or x . y) `(logior ,x ,@y))
+  (define-macro (lalr-error msg obj) `(error ,msg ,obj))
+  (define (note-source-location lvalue tok)
+    (if (and (supports-source-properties? lvalue)
+             (not (source-property lvalue 'loc))
+             (lexical-token? tok))
+        (set-source-property! lvalue 'loc (lexical-token-source tok)))
+    lvalue))
+
+ ;; -- Mes
+  (mes
+   (define pprint display)
+   (define lalr-keyword? symbol?)
+   (define-macro (BITS-PER-WORD) 30)
+   (define-macro (logical-or x . y) `(logior ,x ,@y))
+   (define-macro (lalr-error msg obj) `(error ,msg ,obj))
+   (define (note-source-location lvalue tok) lvalue)
+   (define *eoi* -1))
+  
+ ;; -- Kawa
+ (kawa
+  (require 'pretty-print)
+  (define (BITS-PER-WORD) 30)
+  (define logical-or logior)
+  (define (lalr-keyword? obj) (keyword? obj))
+  (define (pprint obj) (pretty-print obj))
+  (define (lalr-error msg obj) (error msg obj))
+  (define (note-source-location lvalue tok) lvalue))
+
+ ;; -- SISC
+ (sisc
+  (import logicops)
+  (import record)
+       
+  (define pprint pretty-print)
+  (define lalr-keyword? symbol?)
+  (define-macro BITS-PER-WORD (lambda () 32))
+  (define-macro logical-or (lambda (x . y) `(logor ,x ,@y)))
+  (define-macro (lalr-error msg obj) `(error "~a ~S:" ,msg ,obj))
+  (define (note-source-location lvalue tok) lvalue))
+       
+ ;; -- Gauche
+ (gauche
+  (use gauche.record)
+  (define-macro (def-macro form . body)
+    `(define-macro ,form (let () ,@body)))
+  (define pprint (lambda (obj) (write obj) (newline)))
+  (define lalr-keyword? symbol?)
+  (def-macro (BITS-PER-WORD) 30)
+  (def-macro (logical-or x . y) `(logior ,x . ,y))
+  (def-macro (lalr-error msg obj) `(error "lalr-parser" ,msg ,obj))
+  (define (note-source-location lvalue tok) lvalue))
+
+ (else
+  (error "Unsupported Scheme system")))
+
+
+(define-record-type lexical-token
+  (make-lexical-token category source value)
+  lexical-token?
+  (category lexical-token-category)
+  (source   lexical-token-source)
+  (value    lexical-token-value))
+
+
+(define-record-type source-location
+  (make-source-location input line column offset length)
+  source-location?
+  (input   source-location-input)
+  (line    source-location-line)
+  (column  source-location-column)
+  (offset  source-location-offset)
+  (length  source-location-length))
+
+
+
+      ;; - Macros pour la gestion des vecteurs de bits
+
+(define-macro (lalr-parser . arguments)
+  (define (set-bit v b)
+    (let ((x (quotient b (BITS-PER-WORD)))
+         (y (expt 2 (remainder b (BITS-PER-WORD)))))
+      (vector-set! v x (logical-or (vector-ref v x) y))))
+
+  (define (bit-union v1 v2 n)
+    (do ((i 0 (+ i 1)))
+       ((= i n))
+      (vector-set! v1 i (logical-or (vector-ref v1 i)
+                                   (vector-ref v2 i)))))
+
+  ;; - Macro pour les structures de donnees
+
+  (define (new-core)              (make-vector 4 0))
+  (define (set-core-number! c n)  (vector-set! c 0 n))
+  (define (set-core-acc-sym! c s) (vector-set! c 1 s))
+  (define (set-core-nitems! c n)  (vector-set! c 2 n))
+  (define (set-core-items! c i)   (vector-set! c 3 i))
+  (define (core-number c)         (vector-ref c 0))
+  (define (core-acc-sym c)        (vector-ref c 1))
+  (define (core-nitems c)         (vector-ref c 2))
+  (define (core-items c)          (vector-ref c 3))
+
+  (define (new-shift)              (make-vector 3 0))
+  (define (set-shift-number! c x)  (vector-set! c 0 x))
+  (define (set-shift-nshifts! c x) (vector-set! c 1 x))
+  (define (set-shift-shifts! c x)  (vector-set! c 2 x))
+  (define (shift-number s)         (vector-ref s 0))
+  (define (shift-nshifts s)        (vector-ref s 1))
+  (define (shift-shifts s)         (vector-ref s 2))
+
+  (define (new-red)                (make-vector 3 0))
+  (define (set-red-number! c x)    (vector-set! c 0 x))
+  (define (set-red-nreds! c x)     (vector-set! c 1 x))
+  (define (set-red-rules! c x)     (vector-set! c 2 x))
+  (define (red-number c)           (vector-ref c 0))
+  (define (red-nreds c)            (vector-ref c 1))
+  (define (red-rules c)            (vector-ref c 2))
+
+
+  (define (new-set nelem)
+    (make-vector nelem 0))
+
+
+  (define (vector-map f v)
+    (let ((vm-n (- (vector-length v) 1)))
+      (let loop ((vm-low 0) (vm-high vm-n))
+       (if (= vm-low vm-high)
+           (vector-set! v vm-low (f (vector-ref v vm-low) vm-low))
+           (let ((vm-middle (quotient (+ vm-low vm-high) 2)))
+             (loop vm-low vm-middle)
+             (loop (+ vm-middle 1) vm-high))))))
+
+
+  ;; - Constantes
+  (define STATE-TABLE-SIZE 1009)
+
+
+  ;; - Tableaux 
+  (define rrhs         #f)
+  (define rlhs         #f)
+  (define ritem        #f)
+  (define nullable     #f)
+  (define derives      #f)
+  (define fderives     #f)
+  (define firsts       #f)
+  (define kernel-base  #f)
+  (define kernel-end   #f)
+  (define shift-symbol #f)
+  (define shift-set    #f)
+  (define red-set      #f)
+  (define state-table  #f)
+  (define acces-symbol #f)
+  (define reduction-table #f)
+  (define shift-table  #f)
+  (define consistent   #f)
+  (define lookaheads   #f)
+  (define LA           #f)
+  (define LAruleno     #f)
+  (define lookback     #f)
+  (define goto-map     #f)
+  (define from-state   #f)
+  (define to-state     #f)
+  (define includes     #f)
+  (define F            #f)
+  (define action-table #f)
+
+  ;; - Variables
+  (define nitems          #f)
+  (define nrules          #f)
+  (define nvars           #f)
+  (define nterms          #f)
+  (define nsyms           #f)
+  (define nstates         #f)
+  (define first-state     #f)
+  (define last-state      #f)
+  (define final-state     #f)
+  (define first-shift     #f)
+  (define last-shift      #f)
+  (define first-reduction #f)
+  (define last-reduction  #f)
+  (define nshifts         #f)
+  (define maxrhs          #f)
+  (define ngotos          #f)
+  (define token-set-size  #f)
+
+  (define driver-name     'lr-driver)
+
+  (define (glr-driver?)
+    (eq? driver-name 'glr-driver))
+  (define (lr-driver?)
+    (eq? driver-name 'lr-driver))
+
+  (define (gen-tables! tokens gram )
+    (initialize-all)
+    (rewrite-grammar
+     tokens
+     gram
+     (lambda (terms terms/prec vars gram gram/actions)
+       (set! the-terminals/prec (list->vector terms/prec))
+       (set! the-terminals (list->vector terms))
+       (set! the-nonterminals (list->vector vars))
+       (set! nterms (length terms))
+       (set! nvars  (length vars))
+       (set! nsyms  (+ nterms nvars))
+       (let ((no-of-rules (length gram/actions))
+            (no-of-items (let loop ((l gram/actions) (count 0))
+                           (if (null? l)
+                               count
+                               (loop (cdr l) (+ count (length (caar l))))))))
+        (pack-grammar no-of-rules no-of-items gram)
+        (set-derives)
+        (set-nullable)
+        (generate-states)
+        (lalr)
+        (build-tables)
+        (compact-action-table terms)
+        gram/actions))))
+
+
+  (define (initialize-all)
+    (set! rrhs         #f)
+    (set! rlhs         #f)
+    (set! ritem        #f)
+    (set! nullable     #f)
+    (set! derives      #f)
+    (set! fderives     #f)
+    (set! firsts       #f)
+    (set! kernel-base  #f)
+    (set! kernel-end   #f)
+    (set! shift-symbol #f)
+    (set! shift-set    #f)
+    (set! red-set      #f)
+    (set! state-table  (make-vector STATE-TABLE-SIZE '()))
+    (set! acces-symbol #f)
+    (set! reduction-table #f)
+    (set! shift-table  #f)
+    (set! consistent   #f)
+    (set! lookaheads   #f)
+    (set! LA           #f)
+    (set! LAruleno     #f)
+    (set! lookback     #f)
+    (set! goto-map     #f)
+    (set! from-state   #f)
+    (set! to-state     #f)
+    (set! includes     #f)
+    (set! F            #f)
+    (set! action-table #f)
+    (set! nstates         #f)
+    (set! first-state     #f)
+    (set! last-state      #f)
+    (set! final-state     #f)
+    (set! first-shift     #f)
+    (set! last-shift      #f)
+    (set! first-reduction #f)
+    (set! last-reduction  #f)
+    (set! nshifts         #f)
+    (set! maxrhs          #f)
+    (set! ngotos          #f)
+    (set! token-set-size  #f)
+    (set! rule-precedences '()))
+
+
+  (define (pack-grammar no-of-rules no-of-items gram)
+    (set! nrules (+  no-of-rules 1))
+    (set! nitems no-of-items)
+    (set! rlhs (make-vector nrules #f))
+    (set! rrhs (make-vector nrules #f))
+    (set! ritem (make-vector (+ 1 nitems) #f))
+
+    (let loop ((p gram) (item-no 0) (rule-no 1))
+      (if (not (null? p))
+         (let ((nt (caar p)))
+           (let loop2 ((prods (cdar p)) (it-no2 item-no) (rl-no2 rule-no))
+             (if (null? prods)
+                 (loop (cdr p) it-no2 rl-no2)
+                 (begin
+                   (vector-set! rlhs rl-no2 nt)
+                   (vector-set! rrhs rl-no2 it-no2)
+                   (let loop3 ((rhs (car prods)) (it-no3 it-no2))
+                     (if (null? rhs)
+                         (begin
+                           (vector-set! ritem it-no3 (- rl-no2))
+                           (loop2 (cdr prods) (+ it-no3 1) (+ rl-no2 1)))
+                         (begin
+                           (vector-set! ritem it-no3 (car rhs))
+                           (loop3 (cdr rhs) (+ it-no3 1))))))))))))
+
+
+  (define (set-derives)
+    (define delts (make-vector (+ nrules 1) 0))
+    (define dset  (make-vector nvars -1))
+
+    (let loop ((i 1) (j 0))            ; i = 0
+      (if (< i nrules)
+         (let ((lhs (vector-ref rlhs i)))
+           (if (>= lhs 0)
+               (begin
+                 (vector-set! delts j (cons i (vector-ref dset lhs)))
+                 (vector-set! dset lhs j)
+                 (loop (+ i 1) (+ j 1)))
+               (loop (+ i 1) j)))))
+
+    (set! derives (make-vector nvars 0))
+
+    (let loop ((i 0))
+      (if (< i nvars)
+         (let ((q (let loop2 ((j (vector-ref dset i)) (s '()))
+                    (if (< j 0)
+                        s
+                        (let ((x (vector-ref delts j)))
+                          (loop2 (cdr x) (cons (car x) s)))))))
+           (vector-set! derives i q)
+           (loop (+ i 1))))))
+
+
+
+  (define (set-nullable)
+    (set! nullable (make-vector nvars #f))
+    (let ((squeue (make-vector nvars #f))
+         (rcount (make-vector (+ nrules 1) 0))
+         (rsets  (make-vector nvars #f))
+         (relts  (make-vector (+ nitems nvars 1) #f)))
+      (let loop ((r 0) (s2 0) (p 0))
+       (let ((*r (vector-ref ritem r)))
+         (if *r
+             (if (< *r 0)
+                 (let ((symbol (vector-ref rlhs (- *r))))
+                   (if (and (>= symbol 0)
+                            (not (vector-ref nullable symbol)))
+                       (begin
+                         (vector-set! nullable symbol #t)
+                         (vector-set! squeue s2 symbol)
+                         (loop (+ r 1) (+ s2 1) p))))
+                 (let loop2 ((r1 r) (any-tokens #f))
+                   (let* ((symbol (vector-ref ritem r1)))
+                     (if (> symbol 0)
+                         (loop2 (+ r1 1) (or any-tokens (>= symbol nvars)))
+                         (if (not any-tokens)
+                             (let ((ruleno (- symbol)))
+                               (let loop3 ((r2 r) (p2 p))
+                                 (let ((symbol (vector-ref ritem r2)))
+                                   (if (> symbol 0)
+                                       (begin
+                                         (vector-set! rcount ruleno
+                                                      (+ (vector-ref rcount ruleno) 1))
+                                         (vector-set! relts p2
+                                                      (cons (vector-ref rsets symbol)
+                                                            ruleno))
+                                         (vector-set! rsets symbol p2)
+                                         (loop3 (+ r2 1) (+ p2 1)))
+                                       (loop (+ r2 1) s2 p2)))))
+                             (loop (+ r1 1) s2 p))))))
+             (let loop ((s1 0) (s3 s2))
+               (if (< s1 s3)
+                   (let loop2 ((p (vector-ref rsets (vector-ref squeue s1))) (s4 s3))
+                     (if p
+                         (let* ((x (vector-ref relts p))
+                                (ruleno (cdr x))
+                                (y (- (vector-ref rcount ruleno) 1)))
+                           (vector-set! rcount ruleno y)
+                           (if (= y 0)
+                               (let ((symbol (vector-ref rlhs ruleno)))
+                                 (if (and (>= symbol 0)
+                                          (not (vector-ref nullable symbol)))
+                                     (begin
+                                       (vector-set! nullable symbol #t)
+                                       (vector-set! squeue s4 symbol)
+                                       (loop2 (car x) (+ s4 1)))
+                                     (loop2 (car x) s4)))
+                               (loop2 (car x) s4))))
+                     (loop (+ s1 1) s4)))))))))
+
+
+
+  (define (set-firsts)
+    (set! firsts (make-vector nvars '()))
+
+    ;; -- initialization
+    (let loop ((i 0))
+      (if (< i nvars)
+         (let loop2 ((sp (vector-ref derives i)))
+           (if (null? sp)
+               (loop (+ i 1))
+               (let ((sym (vector-ref ritem (vector-ref rrhs (car sp)))))
+                 (if (< -1 sym nvars)
+                     (vector-set! firsts i (sinsert sym (vector-ref firsts i))))
+                 (loop2 (cdr sp)))))))
+
+    ;; -- reflexive and transitive closure
+    (let loop ((continue #t))
+      (if continue
+         (let loop2 ((i 0) (cont #f))
+           (if (>= i nvars)
+               (loop cont)
+               (let* ((x (vector-ref firsts i))
+                      (y (let loop3 ((l x) (z x))
+                           (if (null? l)
+                               z
+                               (loop3 (cdr l)
+                                      (sunion (vector-ref firsts (car l)) z))))))
+                 (if (equal? x y)
+                     (loop2 (+ i 1) cont)
+                     (begin
+                       (vector-set! firsts i y)
+                       (loop2 (+ i 1) #t))))))))
+
+    (let loop ((i 0))
+      (if (< i nvars)
+         (begin
+           (vector-set! firsts i (sinsert i (vector-ref firsts i)))
+           (loop (+ i 1))))))
+
+
+
+
+  (define (set-fderives)
+    (set! fderives (make-vector nvars #f))
+
+    (set-firsts)
+
+    (let loop ((i 0))
+      (if (< i nvars)
+         (let ((x (let loop2 ((l (vector-ref firsts i)) (fd '()))
+                    (if (null? l)
+                        fd
+                        (loop2 (cdr l)
+                               (sunion (vector-ref derives (car l)) fd))))))
+           (vector-set! fderives i x)
+           (loop (+ i 1))))))
+
+
+  (define (closure core)
+    ;; Initialization
+    (define ruleset (make-vector nrules #f))
+
+    (let loop ((csp core))
+      (if (not (null? csp))
+         (let ((sym (vector-ref ritem (car csp))))
+           (if (< -1 sym nvars)
+               (let loop2 ((dsp (vector-ref fderives sym)))
+                 (if (not (null? dsp))
+                     (begin
+                       (vector-set! ruleset (car dsp) #t)
+                       (loop2 (cdr dsp))))))
+           (loop (cdr csp)))))
+
+    (let loop ((ruleno 1) (csp core) (itemsetv '())) ; ruleno = 0
+      (if (< ruleno nrules)
+         (if (vector-ref ruleset ruleno)
+             (let ((itemno (vector-ref rrhs ruleno)))
+               (let loop2 ((c csp) (itemsetv2 itemsetv))
+                 (if (and (pair? c)
+                          (< (car c) itemno))
+                     (loop2 (cdr c) (cons (car c) itemsetv2))
+                     (loop (+ ruleno 1) c (cons itemno itemsetv2)))))
+             (loop (+ ruleno 1) csp itemsetv))
+         (let loop2 ((c csp) (itemsetv2 itemsetv))
+           (if (pair? c)
+               (loop2 (cdr c) (cons (car c) itemsetv2))
+               (reverse itemsetv2))))))
+
+
+
+  (define (allocate-item-sets)
+    (set! kernel-base (make-vector nsyms 0))
+    (set! kernel-end  (make-vector nsyms #f)))
+
+
+  (define (allocate-storage)
+    (allocate-item-sets)
+    (set! red-set (make-vector (+ nrules 1) 0)))
+
+                                       ; --
+
+
+  (define (initialize-states)
+    (let ((p (new-core)))
+      (set-core-number! p 0)
+      (set-core-acc-sym! p #f)
+      (set-core-nitems! p 1)
+      (set-core-items! p '(0))
+
+      (set! first-state (list p))
+      (set! last-state first-state)
+      (set! nstates 1)))
+
+
+
+  (define (generate-states)
+    (allocate-storage)
+    (set-fderives)
+    (initialize-states)
+    (let loop ((this-state first-state))
+      (if (pair? this-state)
+         (let* ((x (car this-state))
+                (is (closure (core-items x))))
+           (save-reductions x is)
+           (new-itemsets is)
+           (append-states)
+           (if (> nshifts 0)
+               (save-shifts x))
+           (loop (cdr this-state))))))
+
+
+  (define (new-itemsets itemset)
+    ;; - Initialization
+    (set! shift-symbol '())
+    (let loop ((i 0))
+      (if (< i nsyms)
+         (begin
+           (vector-set! kernel-end i '())
+           (loop (+ i 1)))))
+
+    (let loop ((isp itemset))
+      (if (pair? isp)
+         (let* ((i (car isp))
+                (sym (vector-ref ritem i)))
+           (if (>= sym 0)
+               (begin
+                 (set! shift-symbol (sinsert sym shift-symbol))
+                 (let ((x (vector-ref kernel-end sym)))
+                   (if (null? x)
+                       (begin
+                         (vector-set! kernel-base sym (cons (+ i 1) x))
+                         (vector-set! kernel-end sym (vector-ref kernel-base sym)))
+                       (begin
+                         (set-cdr! x (list (+ i 1)))
+                         (vector-set! kernel-end sym (cdr x)))))))
+           (loop (cdr isp)))))
+
+    (set! nshifts (length shift-symbol)))
+
+
+
+  (define (get-state sym)
+    (let* ((isp  (vector-ref kernel-base sym))
+          (n    (length isp))
+          (key  (let loop ((isp1 isp) (k 0))
+                  (if (null? isp1)
+                      (modulo k STATE-TABLE-SIZE)
+                      (loop (cdr isp1) (+ k (car isp1))))))
+          (sp   (vector-ref state-table key)))
+      (if (null? sp)
+         (let ((x (new-state sym)))
+           (vector-set! state-table key (list x))
+           (core-number x))
+         (let loop ((sp1 sp))
+           (if (and (= n (core-nitems (car sp1)))
+                    (let loop2 ((i1 isp) (t (core-items (car sp1))))
+                      (if (and (pair? i1)
+                               (= (car i1)
+                                  (car t)))
+                          (loop2 (cdr i1) (cdr t))
+                          (null? i1))))
+               (core-number (car sp1))
+               (if (null? (cdr sp1))
+                   (let ((x (new-state sym)))
+                     (set-cdr! sp1 (list x))
+                     (core-number x))
+                   (loop (cdr sp1))))))))
+
+
+  (define (new-state sym)
+    (let* ((isp  (vector-ref kernel-base sym))
+          (n    (length isp))
+          (p    (new-core)))
+      (set-core-number! p nstates)
+      (set-core-acc-sym! p sym)
+      (if (= sym nvars) (set! final-state nstates))
+      (set-core-nitems! p n)
+      (set-core-items! p isp)
+      (set-cdr! last-state (list p))
+      (set! last-state (cdr last-state))
+      (set! nstates (+ nstates 1))
+      p))
+
+
+                                       ; --
+
+  (define (append-states)
+    (set! shift-set
+         (let loop ((l (reverse shift-symbol)))
+           (if (null? l)
+               '()
+               (cons (get-state (car l)) (loop (cdr l)))))))
+
+                                       ; --
+
+  (define (save-shifts core)
+    (let ((p (new-shift)))
+      (set-shift-number! p (core-number core))
+      (set-shift-nshifts! p nshifts)
+      (set-shift-shifts! p shift-set)
+      (if last-shift
+         (begin
+           (set-cdr! last-shift (list p))
+           (set! last-shift (cdr last-shift)))
+         (begin
+           (set! first-shift (list p))
+           (set! last-shift first-shift)))))
+
+  (define (save-reductions core itemset)
+    (let ((rs (let loop ((l itemset))
+               (if (null? l)
+                   '()
+                   (let ((item (vector-ref ritem (car l))))
+                     (if (< item 0)
+                         (cons (- item) (loop (cdr l)))
+                         (loop (cdr l))))))))
+      (if (pair? rs)
+         (let ((p (new-red)))
+           (set-red-number! p (core-number core))
+           (set-red-nreds!  p (length rs))
+           (set-red-rules!  p rs)
+           (if last-reduction
+               (begin
+                 (set-cdr! last-reduction (list p))
+                 (set! last-reduction (cdr last-reduction)))
+               (begin
+                 (set! first-reduction (list p))
+                 (set! last-reduction first-reduction)))))))
+
+
+                                       ; --
+
+  (define (lalr)
+    (set! token-set-size (+ 1 (quotient nterms (BITS-PER-WORD))))
+    (set-accessing-symbol)
+    (set-shift-table)
+    (set-reduction-table)
+    (set-max-rhs)
+    (initialize-LA)
+    (set-goto-map)
+    (initialize-F)
+    (build-relations)
+    (digraph includes)
+    (compute-lookaheads))
+
+  (define (set-accessing-symbol)
+    (set! acces-symbol (make-vector nstates #f))
+    (let loop ((l first-state))
+      (if (pair? l)
+         (let ((x (car l)))
+           (vector-set! acces-symbol (core-number x) (core-acc-sym x))
+           (loop (cdr l))))))
+
+  (define (set-shift-table)
+    (set! shift-table (make-vector nstates #f))
+    (let loop ((l first-shift))
+      (if (pair? l)
+         (let ((x (car l)))
+           (vector-set! shift-table (shift-number x) x)
+           (loop (cdr l))))))
+
+  (define (set-reduction-table)
+    (set! reduction-table (make-vector nstates #f))
+    (let loop ((l first-reduction))
+      (if (pair? l)
+         (let ((x (car l)))
+           (vector-set! reduction-table (red-number x) x)
+           (loop (cdr l))))))
+
+  (define (set-max-rhs)
+    (let loop ((p 0) (curmax 0) (length 0))
+      (let ((x (vector-ref ritem p)))
+       (if x
+           (if (>= x 0)
+               (loop (+ p 1) curmax (+ length 1))
+               (loop (+ p 1) (max curmax length) 0))
+           (set! maxrhs curmax)))))
+
+  (define (initialize-LA)
+    (define (last l)
+      (if (null? (cdr l))
+         (car l)
+         (last (cdr l))))
+
+    (set! consistent (make-vector nstates #f))
+    (set! lookaheads (make-vector (+ nstates 1) #f))
+
+    (let loop ((count 0) (i 0))
+      (if (< i nstates)
+         (begin
+           (vector-set! lookaheads i count)
+           (let ((rp (vector-ref reduction-table i))
+                 (sp (vector-ref shift-table i)))
+             (if (and rp
+                      (or (> (red-nreds rp) 1)
+                          (and sp
+                               (not
+                                (< (vector-ref acces-symbol
+                                               (last (shift-shifts sp)))
+                                   nvars)))))
+                 (loop (+ count (red-nreds rp)) (+ i 1))
+                 (begin
+                   (vector-set! consistent i #t)
+                   (loop count (+ i 1))))))
+
+         (begin
+           (vector-set! lookaheads nstates count)
+           (let ((c (max count 1)))
+             (set! LA (make-vector c #f))
+             (do ((j 0 (+ j 1))) ((= j c)) (vector-set! LA j (new-set token-set-size)))
+             (set! LAruleno (make-vector c -1))
+             (set! lookback (make-vector c #f)))
+           (let loop ((i 0) (np 0))
+             (if (< i nstates)
+                 (if (vector-ref consistent i)
+                     (loop (+ i 1) np)
+                     (let ((rp (vector-ref reduction-table i)))
+                       (if rp
+                           (let loop2 ((j (red-rules rp)) (np2 np))
+                             (if (null? j)
+                                 (loop (+ i 1) np2)
+                                 (begin
+                                   (vector-set! LAruleno np2 (car j))
+                                   (loop2 (cdr j) (+ np2 1)))))
+                           (loop (+ i 1) np))))))))))
+
+
+  (define (set-goto-map)
+    (set! goto-map (make-vector (+ nvars 1) 0))
+    (let ((temp-map (make-vector (+ nvars 1) 0)))
+      (let loop ((ng 0) (sp first-shift))
+       (if (pair? sp)
+           (let loop2 ((i (reverse (shift-shifts (car sp)))) (ng2 ng))
+             (if (pair? i)
+                 (let ((symbol (vector-ref acces-symbol (car i))))
+                   (if (< symbol nvars)
+                       (begin
+                         (vector-set! goto-map symbol
+                                      (+ 1 (vector-ref goto-map symbol)))
+                         (loop2 (cdr i) (+ ng2 1)))
+                       (loop2 (cdr i) ng2)))
+                 (loop ng2 (cdr sp))))
+
+           (let loop ((k 0) (i 0))
+             (if (< i nvars)
+                 (begin
+                   (vector-set! temp-map i k)
+                   (loop (+ k (vector-ref goto-map i)) (+ i 1)))
+
+                 (begin
+                   (do ((i 0 (+ i 1)))
+                       ((>= i nvars))
+                     (vector-set! goto-map i (vector-ref temp-map i)))
+
+                   (set! ngotos ng)
+                   (vector-set! goto-map nvars ngotos)
+                   (vector-set! temp-map nvars ngotos)
+                   (set! from-state (make-vector ngotos #f))
+                   (set! to-state (make-vector ngotos #f))
+
+                   (do ((sp first-shift (cdr sp)))
+                       ((null? sp))
+                     (let* ((x (car sp))
+                            (state1 (shift-number x)))
+                       (do ((i (shift-shifts x) (cdr i)))
+                           ((null? i))
+                         (let* ((state2 (car i))
+                                (symbol (vector-ref acces-symbol state2)))
+                           (if (< symbol nvars)
+                               (let ((k (vector-ref temp-map symbol)))
+                                 (vector-set! temp-map symbol (+ k 1))
+                                 (vector-set! from-state k state1)
+                                 (vector-set! to-state k state2))))))))))))))
+
+
+  (define (map-goto state symbol)
+    (let loop ((low (vector-ref goto-map symbol))
+              (high (- (vector-ref goto-map (+ symbol 1)) 1)))
+      (if (> low high)
+         (begin
+           (display (list "Error in map-goto" state symbol)) (newline)
+           0)
+         (let* ((middle (quotient (+ low high) 2))
+                (s (vector-ref from-state middle)))
+           (cond
+            ((= s state)
+             middle)
+            ((< s state)
+             (loop (+ middle 1) high))
+            (else
+             (loop low (- middle 1))))))))
+
+
+  (define (initialize-F)
+    (set! F (make-vector ngotos #f))
+    (do ((i 0 (+ i 1))) ((= i ngotos)) (vector-set! F i (new-set token-set-size)))
+
+    (let ((reads (make-vector ngotos #f)))
+
+      (let loop ((i 0) (rowp 0))
+       (if (< i ngotos)
+           (let* ((rowf (vector-ref F rowp))
+                  (stateno (vector-ref to-state i))
+                  (sp (vector-ref shift-table stateno)))
+             (if sp
+                 (let loop2 ((j (shift-shifts sp)) (edges '()))
+                   (if (pair? j)
+                       (let ((symbol (vector-ref acces-symbol (car j))))
+                         (if (< symbol nvars)
+                             (if (vector-ref nullable symbol)
+                                 (loop2 (cdr j) (cons (map-goto stateno symbol)
+                                                      edges))
+                                 (loop2 (cdr j) edges))
+                             (begin
+                               (set-bit rowf (- symbol nvars))
+                               (loop2 (cdr j) edges))))
+                       (if (pair? edges)
+                           (vector-set! reads i (reverse edges))))))
+             (loop (+ i 1) (+ rowp 1)))))
+      (digraph reads)))
+
+  (define (add-lookback-edge stateno ruleno gotono)
+    (let ((k (vector-ref lookaheads (+ stateno 1))))
+      (let loop ((found #f) (i (vector-ref lookaheads stateno)))
+       (if (and (not found) (< i k))
+           (if (= (vector-ref LAruleno i) ruleno)
+               (loop #t i)
+               (loop found (+ i 1)))
+
+           (if (not found)
+               (begin (display "Error in add-lookback-edge : ")
+                      (display (list stateno ruleno gotono)) (newline))
+               (vector-set! lookback i
+                            (cons gotono (vector-ref lookback i))))))))
+
+
+  (define (transpose r-arg n)
+    (let ((new-end (make-vector n #f))
+         (new-R  (make-vector n #f)))
+      (do ((i 0 (+ i 1)))
+         ((= i n))
+       (let ((x (list 'bidon)))
+         (vector-set! new-R i x)
+         (vector-set! new-end i x)))
+      (do ((i 0 (+ i 1)))
+         ((= i n))
+       (let ((sp (vector-ref r-arg i)))
+         (if (pair? sp)
+             (let loop ((sp2 sp))
+               (if (pair? sp2)
+                   (let* ((x (car sp2))
+                          (y (vector-ref new-end x)))
+                     (set-cdr! y (cons i (cdr y)))
+                     (vector-set! new-end x (cdr y))
+                     (loop (cdr sp2))))))))
+      (do ((i 0 (+ i 1)))
+         ((= i n))
+       (vector-set! new-R i (cdr (vector-ref new-R i))))
+
+      new-R))
+
+
+
+  (define (build-relations)
+
+    (define (get-state stateno symbol)
+      (let loop ((j (shift-shifts (vector-ref shift-table stateno)))
+                (stno stateno))
+       (if (null? j)
+           stno
+           (let ((st2 (car j)))
+             (if (= (vector-ref acces-symbol st2) symbol)
+                 st2
+                 (loop (cdr j) st2))))))
+
+    (set! includes (make-vector ngotos #f))
+    (do ((i 0 (+ i 1)))
+       ((= i ngotos))
+      (let ((state1 (vector-ref from-state i))
+           (symbol1 (vector-ref acces-symbol (vector-ref to-state i))))
+       (let loop ((rulep (vector-ref derives symbol1))
+                  (edges '()))
+         (if (pair? rulep)
+             (let ((*rulep (car rulep)))
+               (let loop2 ((rp (vector-ref rrhs *rulep))
+                           (stateno state1)
+                           (states (list state1)))
+                 (let ((*rp (vector-ref ritem rp)))
+                   (if (> *rp 0)
+                       (let ((st (get-state stateno *rp)))
+                         (loop2 (+ rp 1) st (cons st states)))
+                       (begin
+
+                         (if (not (vector-ref consistent stateno))
+                             (add-lookback-edge stateno *rulep i))
+
+                         (let loop2 ((done #f)
+                                     (stp (cdr states))
+                                     (rp2 (- rp 1))
+                                     (edgp edges))
+                           (if (not done)
+                               (let ((*rp (vector-ref ritem rp2)))
+                                 (if (< -1 *rp nvars)
+                                     (loop2 (not (vector-ref nullable *rp))
+                                            (cdr stp)
+                                            (- rp2 1)
+                                            (cons (map-goto (car stp) *rp) edgp))
+                                     (loop2 #t stp rp2 edgp)))
+
+                               (loop (cdr rulep) edgp))))))))
+             (vector-set! includes i edges)))))
+    (set! includes (transpose includes ngotos)))
+
+
+
+  (define (compute-lookaheads)
+    (let ((n (vector-ref lookaheads nstates)))
+      (let loop ((i 0))
+       (if (< i n)
+           (let loop2 ((sp (vector-ref lookback i)))
+             (if (pair? sp)
+                 (let ((LA-i (vector-ref LA i))
+                       (F-j  (vector-ref F (car sp))))
+                   (bit-union LA-i F-j token-set-size)
+                   (loop2 (cdr sp)))
+                 (loop (+ i 1))))))))
+
+
+
+  (define (digraph relation)
+    (define infinity (+ ngotos 2))
+    (define INDEX (make-vector (+ ngotos 1) 0))
+    (define VERTICES (make-vector (+ ngotos 1) 0))
+    (define top 0)
+    (define R relation)
+
+    (define (traverse i)
+      (set! top (+ 1 top))
+      (vector-set! VERTICES top i)
+      (let ((height top))
+       (vector-set! INDEX i height)
+       (let ((rp (vector-ref R i)))
+         (if (pair? rp)
+             (let loop ((rp2 rp))
+               (if (pair? rp2)
+                   (let ((j (car rp2)))
+                     (if (= 0 (vector-ref INDEX j))
+                         (traverse j))
+                     (if (> (vector-ref INDEX i)
+                            (vector-ref INDEX j))
+                         (vector-set! INDEX i (vector-ref INDEX j)))
+                     (let ((F-i (vector-ref F i))
+                           (F-j (vector-ref F j)))
+                       (bit-union F-i F-j token-set-size))
+                     (loop (cdr rp2))))))
+         (if (= (vector-ref INDEX i) height)
+             (let loop ()
+               (let ((j (vector-ref VERTICES top)))
+                 (set! top (- top 1))
+                 (vector-set! INDEX j infinity)
+                 (if (not (= i j))
+                     (begin
+                       (bit-union (vector-ref F i)
+                                  (vector-ref F j)
+                                  token-set-size)
+                       (loop)))))))))
+
+    (let loop ((i 0))
+      (if (< i ngotos)
+         (begin
+           (if (and (= 0 (vector-ref INDEX i))
+                    (pair? (vector-ref R i)))
+               (traverse i))
+           (loop (+ i 1))))))
+
+
+  ;; ----------------------------------------------------------------------
+  ;; operator precedence management
+  ;; ----------------------------------------------------------------------
+      
+  ;; a vector of precedence descriptors where each element
+  ;; is of the form (terminal type precedence)
+  (define the-terminals/prec #f)   ; terminal symbols with precedence 
+                                       ; the precedence is an integer >= 0
+  (define (get-symbol-precedence sym)
+    (caddr (vector-ref the-terminals/prec sym)))
+                                       ; the operator type is either 'none, 'left, 'right, or 'nonassoc
+  (define (get-symbol-assoc sym)
+    (cadr (vector-ref the-terminals/prec sym)))
+
+  (define rule-precedences '())
+  (define (add-rule-precedence! rule sym)
+    (set! rule-precedences
+         (cons (cons rule sym) rule-precedences)))
+
+  (define (get-rule-precedence ruleno)
+    (cond
+     ((assq ruleno rule-precedences)
+      => (lambda (p)
+          (get-symbol-precedence (cdr p))))
+     (else
+      ;; process the rule symbols from left to right
+      (let loop ((i    (vector-ref rrhs ruleno))
+                (prec 0))
+       (let ((item (vector-ref ritem i)))
+         ;; end of rule
+         (if (< item 0)
+             prec
+             (let ((i1 (+ i 1)))
+               (if (>= item nvars)
+                   ;; it's a terminal symbol
+                   (loop i1 (get-symbol-precedence (- item nvars)))
+                   (loop i1 prec)))))))))
+
+  ;; ----------------------------------------------------------------------
+  ;; Build the various tables
+  ;; ----------------------------------------------------------------------
+
+  (define expected-conflicts 0)
+
+  (define (build-tables)
+
+    (define (resolve-conflict sym rule)
+      (let ((sym-prec   (get-symbol-precedence sym))
+           (sym-assoc  (get-symbol-assoc sym))
+           (rule-prec  (get-rule-precedence rule)))
+       (cond
+        ((> sym-prec rule-prec)     'shift)
+        ((< sym-prec rule-prec)     'reduce)
+        ((eq? sym-assoc 'left)      'reduce)
+        ((eq? sym-assoc 'right)     'shift)
+        (else                       'none))))
+
+    (define conflict-messages '())
+
+    (define (add-conflict-message . l)
+      (set! conflict-messages (cons l conflict-messages)))
+
+    (define (log-conflicts)
+      (if (> (length conflict-messages) expected-conflicts)
+         (for-each
+          (lambda (message)
+            (for-each display message)
+            (newline))
+          conflict-messages)))
+
+    ;; --- Add an action to the action table
+    (define (add-action state symbol new-action)
+      (let* ((state-actions (vector-ref action-table state))
+            (actions       (assv symbol state-actions)))
+       (if (pair? actions)
+           (let ((current-action (cadr actions)))
+             (if (not (= new-action current-action))
+                 ;; -- there is a conflict 
+                 (begin
+                   (if (and (<= current-action 0) (<= new-action 0))
+                       ;; --- reduce/reduce conflict
+                       (begin
+                         (add-conflict-message
+                          "%% Reduce/Reduce conflict (reduce " (- new-action) ", reduce " (- current-action) 
+                          ") on '" (get-symbol (+ symbol nvars)) "' in state " state)
+                         (if (glr-driver?)
+                             (set-cdr! (cdr actions) (cons new-action (cddr actions)))
+                             (set-car! (cdr actions) (max current-action new-action))))
+                       ;; --- shift/reduce conflict
+                       ;; can we resolve the conflict using precedences?
+                       (case (resolve-conflict symbol (- current-action))
+                         ;; -- shift
+                         ((shift)   (if (glr-driver?)
+                                        (set-cdr! (cdr actions) (cons new-action (cddr actions)))
+                                        (set-car! (cdr actions) new-action)))
+                         ;; -- reduce
+                         ((reduce)  #f) ; well, nothing to do...
+                         ;; -- signal a conflict!
+                         (else      (add-conflict-message
+                                     "%% Shift/Reduce conflict (shift " new-action ", reduce " (- current-action)
+                                     ") on '" (get-symbol (+ symbol nvars)) "' in state " state)
+                                    (if (glr-driver?)
+                                        (set-cdr! (cdr actions) (cons new-action (cddr actions)))
+                                        (set-car! (cdr actions) new-action))))))))
+          
+           (vector-set! action-table state (cons (list symbol new-action) state-actions)))
+       ))
+
+    (define (add-action-for-all-terminals state action)
+      (do ((i 1 (+ i 1)))
+         ((= i nterms))
+       (add-action state i action)))
+
+    (set! action-table (make-vector nstates '()))
+
+    (do ((i 0 (+ i 1)))                        ; i = state
+       ((= i nstates))
+      (let ((red (vector-ref reduction-table i)))
+       (if (and red (>= (red-nreds red) 1))
+           (if (and (= (red-nreds red) 1) (vector-ref consistent i))
+               (if (glr-driver?)
+                   (add-action-for-all-terminals i (- (car (red-rules red))))
+                   (add-action i 'default (- (car (red-rules red)))))
+               (let ((k (vector-ref lookaheads (+ i 1))))
+                 (let loop ((j (vector-ref lookaheads i)))
+                   (if (< j k)
+                       (let ((rule (- (vector-ref LAruleno j)))
+                             (lav  (vector-ref LA j)))
+                         (let loop2 ((token 0) (x (vector-ref lav 0)) (y 1) (z 0))
+                           (if (< token nterms)
+                               (begin
+                                 (let ((in-la-set? (modulo x 2)))
+                                   (if (= in-la-set? 1)
+                                       (add-action i token rule)))
+                                 (if (= y (BITS-PER-WORD))
+                                     (loop2 (+ token 1)
+                                            (vector-ref lav (+ z 1))
+                                            1
+                                            (+ z 1))
+                                     (loop2 (+ token 1) (quotient x 2) (+ y 1) z)))))
+                         (loop (+ j 1)))))))))
+
+      (let ((shiftp (vector-ref shift-table i)))
+       (if shiftp
+           (let loop ((k (shift-shifts shiftp)))
+             (if (pair? k)
+                 (let* ((state (car k))
+                        (symbol (vector-ref acces-symbol state)))
+                   (if (>= symbol nvars)
+                       (add-action i (- symbol nvars) state))
+                   (loop (cdr k))))))))
+
+    (add-action final-state 0 'accept)
+    (log-conflicts))
+
+  (define (compact-action-table terms)
+    (define (most-common-action acts)
+      (let ((accums '()))
+       (let loop ((l acts))
+         (if (pair? l)
+             (let* ((x (cadar l))
+                    (y (assv x accums)))
+               (if (and (number? x) (< x 0))
+                   (if y
+                       (set-cdr! y (+ 1 (cdr y)))
+                       (set! accums (cons `(,x . 1) accums))))
+               (loop (cdr l)))))
+
+       (let loop ((l accums) (max 0) (sym #f))
+         (if (null? l)
+             sym
+             (let ((x (car l)))
+               (if (> (cdr x) max)
+                   (loop (cdr l) (cdr x) (car x))
+                   (loop (cdr l) max sym)))))))
+
+    (define (translate-terms acts)
+      (map (lambda (act)
+            (cons (list-ref terms (car act))
+                  (cdr act)))
+          acts))
+
+    (do ((i 0 (+ i 1)))
+       ((= i nstates))
+      (let ((acts (vector-ref action-table i)))
+       (if (vector? (vector-ref reduction-table i))
+           (let ((act (most-common-action acts)))
+             (vector-set! action-table i
+                          (cons `(*default* ,(if act act '*error*))
+                                (translate-terms
+                                 (lalr-filter (lambda (x)
+                                                (not (and (= (length x) 2)
+                                                          (eq? (cadr x) act))))
+                                              acts)))))
+           (vector-set! action-table i
+                        (cons `(*default* *error*)
+                              (translate-terms acts)))))))
+
+
+
+  ;; --
+
+  (define (rewrite-grammar tokens grammar k)
+
+    (define eoi '*eoi*)
+
+    (define (check-terminal term terms)
+      (cond
+       ((not (valid-terminal? term))
+       (lalr-error "invalid terminal: " term))
+       ((member term terms)
+       (lalr-error "duplicate definition of terminal: " term))))
+
+    (define (prec->type prec)
+      (cdr (assq prec '((left:     . left)
+                       (right:    . right)
+                       (nonassoc: . nonassoc)))))
+
+    (cond
+     ;; --- a few error conditions
+     ((not (list? tokens))
+      (lalr-error "Invalid token list: " tokens))
+     ((not (pair? grammar))
+      (lalr-error "Grammar definition must have a non-empty list of productions" '()))
+
+     (else
+      ;; --- check the terminals
+      (let loop1 ((lst            tokens)
+                 (rev-terms      '())
+                 (rev-terms/prec '())
+                 (prec-level     0))
+       (if (pair? lst)
+           (let ((term (car lst)))
+             (cond
+              ((pair? term)
+               (if (and (memq (car term) '(left: right: nonassoc:))
+                        (not (null? (cdr term))))
+                   (let ((prec    (+ prec-level 1))
+                         (optype  (prec->type (car term))))
+                     (let loop-toks ((l             (cdr term))
+                                     (rev-terms      rev-terms)
+                                     (rev-terms/prec rev-terms/prec))
+                       (if (null? l)
+                           (loop1 (cdr lst) rev-terms rev-terms/prec prec)
+                           (let ((term (car l)))
+                             (check-terminal term rev-terms)
+                             (loop-toks
+                              (cdr l)
+                              (cons term rev-terms)
+                              (cons (list term optype prec) rev-terms/prec))))))
+
+                   (lalr-error "invalid operator precedence specification: " term)))
+
+              (else
+               (check-terminal term rev-terms)
+               (loop1 (cdr lst)
+                      (cons term rev-terms)
+                      (cons (list term 'none 0) rev-terms/prec)
+                      prec-level))))
+
+           ;; --- check the grammar rules
+           (let loop2 ((lst grammar) (rev-nonterm-defs '()))
+             (if (pair? lst)
+                 (let ((def (car lst)))
+                   (if (not (pair? def))
+                       (lalr-error "Nonterminal definition must be a non-empty list" '())
+                       (let ((nonterm (car def)))
+                         (cond ((not (valid-nonterminal? nonterm))
+                                (lalr-error "Invalid nonterminal:" nonterm))
+                               ((or (member nonterm rev-terms)
+                                    (assoc nonterm rev-nonterm-defs))
+                                (lalr-error "Nonterminal previously defined:" nonterm))
+                               (else
+                                (loop2 (cdr lst)
+                                       (cons def rev-nonterm-defs)))))))
+                 (let* ((terms        (cons eoi            (cons 'error          (reverse rev-terms))))
+                        (terms/prec   (cons '(eoi none 0)  (cons '(error none 0) (reverse rev-terms/prec))))
+                        (nonterm-defs (reverse rev-nonterm-defs))
+                        (nonterms     (cons '*start* (map car nonterm-defs))))
+                   (if (= (length nonterms) 1)
+                       (lalr-error "Grammar must contain at least one nonterminal" '())
+                       (let loop-defs ((defs      (cons `(*start* (,(cadr nonterms) ,eoi) : $1)
+                                                        nonterm-defs))
+                                       (ruleno    0)
+                                       (comp-defs '()))
+                         (if (pair? defs)
+                             (let* ((nonterm-def  (car defs))
+                                    (compiled-def (rewrite-nonterm-def
+                                                   nonterm-def
+                                                   ruleno
+                                                   terms nonterms)))
+                               (loop-defs (cdr defs)
+                                          (+ ruleno (length compiled-def))
+                                          (cons compiled-def comp-defs)))
+
+                             (let ((compiled-nonterm-defs (reverse comp-defs)))
+                               (k terms
+                                  terms/prec
+                                  nonterms
+                                  (map (lambda (x) (cons (caaar x) (map cdar x)))
+                                       compiled-nonterm-defs)
+                                  (apply append compiled-nonterm-defs))))))))))))))
+
+
+  (define (rewrite-nonterm-def nonterm-def ruleno terms nonterms)
+
+    (define No-NT (length nonterms))
+
+    (define (encode x)
+      (let ((PosInNT (pos-in-list x nonterms)))
+       (if PosInNT
+           PosInNT
+           (let ((PosInT (pos-in-list x terms)))
+             (if PosInT
+                 (+ No-NT PosInT)
+                 (lalr-error "undefined symbol : " x))))))
+
+    (define (process-prec-directive rhs ruleno)
+      (let loop ((l rhs))
+       (if (null? l)
+           '()
+           (let ((first (car l))
+                 (rest  (cdr l)))
+             (cond
+              ((or (member first terms) (member first nonterms))
+               (cons first (loop rest)))
+              ((and (pair? first)
+                    (eq? (car first) 'prec:))
+               (if (and (pair? (cdr first))
+                        (null? (cddr first))
+                        (member (cadr first) terms))
+                   (if (null? rest)
+                       (begin
+                         (add-rule-precedence! ruleno (pos-in-list (cadr first) terms))
+                         (loop rest))
+                       (lalr-error "prec: directive should be at end of rule: " rhs))
+                   (lalr-error "Invalid prec: directive: " first)))
+              (else
+               (lalr-error "Invalid terminal or nonterminal: " first)))))))
+
+    (define (check-error-production rhs)
+      (let loop ((rhs rhs))
+       (if (pair? rhs)
+           (begin
+             (if (and (eq? (car rhs) 'error)
+                      (or (null? (cdr rhs))
+                          (not (member (cadr rhs) terms))
+                          (not (null? (cddr rhs)))))
+                 (lalr-error "Invalid 'error' production. A single terminal symbol must follow the 'error' token.:" rhs))
+             (loop (cdr rhs))))))
+
+
+    (if (not (pair? (cdr nonterm-def)))
+       (lalr-error "At least one production needed for nonterminal:" (car nonterm-def))
+       (let ((name (symbol->string (car nonterm-def))))
+         (let loop1 ((lst (cdr nonterm-def))
+                     (i 1)
+                     (rev-productions-and-actions '()))
+           (if (not (pair? lst))
+               (reverse rev-productions-and-actions)
+               (let* ((rhs  (process-prec-directive (car lst) (+ ruleno i -1)))
+                      (rest (cdr lst))
+                      (prod (map encode (cons (car nonterm-def) rhs))))
+                 ;; -- check for undefined tokens
+                 (for-each (lambda (x)
+                             (if (not (or (member x terms) (member x nonterms)))
+                                 (lalr-error "Invalid terminal or nonterminal:" x)))
+                           rhs)
+                 ;; -- check 'error' productions
+                 (check-error-production rhs)
+
+                 (if (and (pair? rest)
+                          (eq? (car rest) ':)
+                          (pair? (cdr rest)))
+                     (loop1 (cddr rest)
+                            (+ i 1)
+                            (cons (cons prod (cadr rest))
+                                  rev-productions-and-actions))
+                     (let* ((rhs-length (length rhs))
+                            (action
+                             (cons 'vector
+                                   (cons (list 'quote (string->symbol
+                                                       (string-append
+                                                        name
+                                                        "-"
+                                                        (number->string i))))
+                                         (let loop-j ((j 1))
+                                           (if (> j rhs-length)
+                                               '()
+                                               (cons (string->symbol
+                                                      (string-append
+                                                       "$"
+                                                       (number->string j)))
+                                                     (loop-j (+ j 1)))))))))
+                       (loop1 rest
+                              (+ i 1)
+                              (cons (cons prod action)
+                                    rev-productions-and-actions))))))))))
+
+  (define (valid-nonterminal? x)
+    (symbol? x))
+
+  (define (valid-terminal? x)
+    (symbol? x))                       ; DB 
+
+  ;; ----------------------------------------------------------------------
+  ;; Miscellaneous
+  ;; ----------------------------------------------------------------------
+  (define (pos-in-list x lst)
+    (let loop ((lst lst) (i 0))
+      (cond ((not (pair? lst))    #f)
+           ((equal? (car lst) x) i)
+           (else                 (loop (cdr lst) (+ i 1))))))
+
+  (define (sunion lst1 lst2)           ; union of sorted lists
+    (let loop ((L1 lst1)
+              (L2 lst2))
+      (cond ((null? L1)    L2)
+           ((null? L2)    L1)
+           (else
+            (let ((x (car L1)) (y (car L2)))
+              (cond
+               ((> x y)
+                (cons y (loop L1 (cdr L2))))
+               ((< x y)
+                (cons x (loop (cdr L1) L2)))
+               (else
+                (loop (cdr L1) L2))
+               ))))))
+
+  (define (sinsert elem lst)
+    (let loop ((l1 lst))
+      (if (null? l1)
+         (cons elem l1)
+         (let ((x (car l1)))
+           (cond ((< elem x)
+                  (cons elem l1))
+                 ((> elem x)
+                  (cons x (loop (cdr l1))))
+                 (else
+                  l1))))))
+
+  (define (lalr-filter p lst)
+    (let loop ((l lst))
+      (if (null? l)
+         '()
+         (let ((x (car l)) (y (cdr l)))
+           (if (p x)
+               (cons x (loop y))
+               (loop y))))))
+      
+  ;; ----------------------------------------------------------------------
+  ;; Debugging tools ...
+  ;; ----------------------------------------------------------------------
+  (define the-terminals #f)            ; names of terminal symbols
+  (define the-nonterminals #f)         ; non-terminals
+
+  (define (print-item item-no)
+    (let loop ((i item-no))
+      (let ((v (vector-ref ritem i)))
+       (if (>= v 0)
+           (loop (+ i 1))
+           (let* ((rlno    (- v))
+                  (nt      (vector-ref rlhs rlno)))
+             (display (vector-ref the-nonterminals nt)) (display " --> ")
+             (let loop ((i (vector-ref rrhs rlno)))
+               (let ((v (vector-ref ritem i)))
+                 (if (= i item-no)
+                     (display ". "))
+                 (if (>= v 0)
+                     (begin
+                       (display (get-symbol v))
+                       (display " ")
+                       (loop (+ i 1)))
+                     (begin
+                       (display "   (rule ")
+                       (display (- v))
+                       (display ")")
+                       (newline))))))))))
+
+  (define (get-symbol n)
+    (if (>= n nvars)
+       (vector-ref the-terminals (- n nvars))
+       (vector-ref the-nonterminals n)))
+
+
+  (define (print-states)
+    (define (print-action act)
+      (cond
+       ((eq? act '*error*)
+       (display " : Error"))
+       ((eq? act 'accept)
+       (display " : Accept input"))
+       ((< act 0)
+       (display " : reduce using rule ")
+       (display (- act)))
+       (else
+       (display " : shift and goto state ")
+       (display act)))
+      (newline)
+      #t)
+
+    (define (print-actions acts)
+      (let loop ((l acts))
+       (if (null? l)
+           #t
+           (let ((sym (caar l))
+                 (act (cadar l)))
+             (display "   ")
+             (cond
+              ((eq? sym 'default)
+               (display "default action"))
+              (else
+               (if (number? sym)
+                   (display (get-symbol (+ sym nvars)))
+                   (display sym))))
+             (print-action act)
+             (loop (cdr l))))))
+
+    (if (not action-table)
+       (begin
+         (display "No generated parser available!")
+         (newline)
+         #f)
+       (begin
+         (display "State table") (newline)
+         (display "-----------") (newline) (newline)
+
+         (let loop ((l first-state))
+           (if (null? l)
+               #t
+               (let* ((core  (car l))
+                      (i     (core-number core))
+                      (items (core-items core))
+                      (actions (vector-ref action-table i)))
+                 (display "state ") (display i) (newline)
+                 (newline)
+                 (for-each (lambda (x) (display "   ") (print-item x))
+                           items)
+                 (newline)
+                 (print-actions actions)
+                 (newline)
+                 (loop (cdr l))))))))
+
+
+
+  ;; ----------------------------------------------------------------------
+      
+  (define build-goto-table
+    (lambda ()
+      `(vector
+       ,@(map
+          (lambda (shifts)
+            (list 'quote
+                  (if shifts
+                      (let loop ((l (shift-shifts shifts)))
+                        (if (null? l)
+                            '()
+                            (let* ((state  (car l))
+                                   (symbol (vector-ref acces-symbol state)))
+                              (if (< symbol nvars)
+                                  (cons `(,symbol . ,state)
+                                        (loop (cdr l)))
+                                  (loop (cdr l))))))
+                      '())))
+          (vector->list shift-table)))))
+
+
+  (define build-reduction-table
+    (lambda (gram/actions)
+      `(vector
+       '()
+       ,@(map
+          (lambda (p)
+            (let ((act (cdr p)))
+              `(lambda ,(if (eq? driver-name 'lr-driver)
+                            '(___stack ___sp ___goto-table ___push yypushback)
+                            '(___sp ___goto-table ___push))
+                 ,(let* ((nt (caar p)) (rhs (cdar p)) (n (length rhs)))
+                    `(let* (,@(if act
+                                  (let loop ((i 1) (l rhs))
+                                    (if (pair? l)
+                                        (let ((rest (cdr l))
+                                               (ns (number->string (+ (- n i) 1))))
+                                           (cons
+                                            `(tok ,(if (eq? driver-name 'lr-driver)
+                                                       `(vector-ref ___stack (- ___sp ,(- (* i 2) 1)))
+                                                       `(list-ref ___sp ,(+ (* (- i 1) 2) 1))))
+                                            (cons
+                                             `(,(string->symbol (string-append "$" ns))
+                                               (if (lexical-token? tok) (lexical-token-value tok) tok))
+                                             (cons
+                                              `(,(string->symbol (string-append "@" ns))
+                                                (if (lexical-token? tok) (lexical-token-source tok) tok))
+                                              (loop (+ i 1) rest)))))
+                                        '()))
+                                  '()))
+                       ,(if (= nt 0)
+                            '$1
+                            `(___push ,n ,nt ,(cdr p) ,@(if (eq? driver-name 'lr-driver) '() '(___sp)) 
+                                       ,(if (eq? driver-name 'lr-driver)
+                                            `(vector-ref ___stack (- ___sp ,(length rhs)))
+                                            `(list-ref ___sp ,(length rhs))))))))))
+
+          gram/actions))))
+
+
+
+  ;; Options
+
+  (define *valid-options*
+    (list
+     (cons 'out-table:
+          (lambda (option)
+            (and (list? option)
+                 (= (length option) 2)
+                 (string? (cadr option)))))
+     (cons 'output:
+          (lambda (option)
+            (and (list? option)
+                 (= (length option) 3)
+                 (symbol? (cadr option))
+                 (string? (caddr option)))))
+     (cons 'expect:
+          (lambda (option)
+            (and (list? option)
+                 (= (length option) 2)
+                 (integer? (cadr option))
+                 (>= (cadr option) 0))))
+
+     (cons 'driver:
+          (lambda (option)
+            (and (list? option)
+                 (= (length option) 2)
+                 (symbol? (cadr option))
+                 (memq (cadr option) '(lr glr)))))))
+
+
+  (define (validate-options options)
+    (for-each
+     (lambda (option)
+       (let ((p (assoc (car option) *valid-options*)))
+        (if (or (not p)
+                (not ((cdr p) option)))
+            (lalr-error "Invalid option:" option))))
+     options))
+
+
+  (define (output-parser! options code)
+    (let ((option (assq 'output: options)))
+      (if option
+         (let ((parser-name (cadr option))
+               (file-name   (caddr option)))
+           (with-output-to-file file-name
+             (lambda ()
+               (pprint `(define ,parser-name ,code))
+               (newline)))))))
+
+
+  (define (output-table! options)
+    (let ((option (assq 'out-table: options)))
+      (if option
+         (let ((file-name (cadr option)))
+           (with-output-to-file file-name print-states)))))
+
+
+  (define (set-expected-conflicts! options)
+    (let ((option (assq 'expect: options)))
+      (set! expected-conflicts (if option (cadr option) 0))))
+
+  (define (set-driver-name! options)
+    (let ((option (assq 'driver: options)))
+      (if option
+         (let ((driver-type (cadr option)))
+           (set! driver-name (if (eq? driver-type 'glr) 'glr-driver 'lr-driver))))))
+
+
+  ;; -- arguments
+
+  (define (extract-arguments lst proc)
+    (let loop ((options '())
+              (tokens  '())
+              (rules   '())
+              (lst     lst))
+      (if (pair? lst)
+         (let ((p (car lst)))
+           (cond
+            ((and (pair? p)
+                  (lalr-keyword? (car p))
+                  (assq (car p) *valid-options*))
+             (loop (cons p options) tokens rules (cdr lst)))
+            (else
+             (proc options p (cdr lst)))))
+         (lalr-error "Malformed lalr-parser form" lst))))
+
+
+  (define (build-driver options tokens rules)
+    (validate-options options)
+    (set-expected-conflicts! options)
+    (set-driver-name! options)
+    (let* ((gram/actions (gen-tables! tokens rules))
+          (code         `(,driver-name ',action-table ,(build-goto-table) ,(build-reduction-table gram/actions))))
+    
+      (output-table! options)
+      (output-parser! options code)
+      code))
+
+  (extract-arguments arguments build-driver))
+   
+
+
+;;;
+;;;; --
+;;;; Implementation of the lr-driver
+;;;
+
+
+(cond-expand
+ (gambit
+  (declare
+   (standard-bindings)
+   (fixnum)
+   (block)
+   (not safe)))
+ (chicken
+  (declare
+   (uses extras)
+   (usual-integrations)
+   (fixnum)
+   (not safe)))
+ (guile)
+ (else))
+
+
+;;;
+;;;; Source location utilities
+;;;
+
+
+;; This function assumes that src-location-1 and src-location-2 are source-locations
+;; Returns #f if they are not locations for the same input 
+(define (combine-locations src-location-1 src-location-2)
+  (let ((offset-1 (source-location-offset src-location-1))
+        (offset-2 (source-location-offset src-location-2))
+        (length-1 (source-location-length src-location-1))
+        (length-2 (source-location-length src-location-2)))
+
+    (cond ((not (equal? (source-location-input src-location-1)
+                        (source-location-input src-location-2)))
+           #f)
+          ((or (not (number? offset-1)) (not (number? offset-2))
+               (not (number? length-1)) (not (number? length-2))
+               (< offset-1 0) (< offset-2 0)
+               (< length-1 0) (< length-2 0))
+           (make-source-location (source-location-input src-location-1)
+                                 (source-location-line src-location-1)
+                                 (source-location-column src-location-1)
+                                 -1 -1))
+          ((<= offset-1 offset-2)
+           (make-source-location (source-location-input src-location-1)
+                                 (source-location-line src-location-1)
+                                 (source-location-column src-location-1)
+                                 offset-1
+                                 (- (+ offset-2 length-2) offset-1)))
+          (else
+           (make-source-location (source-location-input src-location-1)
+                                 (source-location-line src-location-1)
+                                 (source-location-column src-location-1)
+                                 offset-2
+                                 (- (+ offset-1 length-1) offset-2))))))
+
+
+;;;
+;;;;  LR-driver
+;;;
+
+
+(define *max-stack-size* 500)
+
+(define (lr-driver action-table goto-table reduction-table)
+  (define ___atable action-table)
+  (define ___gtable goto-table)
+  (define ___rtable reduction-table)
+
+  (define ___lexerp #f)
+  (define ___errorp #f)
+  
+  (define ___stack  #f)
+  (define ___sp     0)
+  
+  (define ___curr-input #f)
+  (define ___reuse-input #f)
+  
+  (define ___input #f)
+  (define (___consume)
+    (set! ___input (if ___reuse-input ___curr-input (___lexerp)))
+    (set! ___reuse-input #f)
+    (set! ___curr-input ___input))
+  
+  (define (___pushback)
+    (set! ___reuse-input #t))
+  
+  (define (___initstack)
+    (set! ___stack (make-vector *max-stack-size* 0))
+    (set! ___sp 0))
+  
+  (define (___growstack)
+    (let ((new-stack (make-vector (* 2 (vector-length ___stack)) 0)))
+      (let loop ((i (- (vector-length ___stack) 1)))
+        (if (>= i 0)
+           (begin
+             (vector-set! new-stack i (vector-ref ___stack i))
+             (loop (- i 1)))))
+      (set! ___stack new-stack)))
+  
+  (define (___checkstack)
+    (if (>= ___sp (vector-length ___stack))
+        (___growstack)))
+  
+  (define (___push delta new-category lvalue tok)
+    (set! ___sp (- ___sp (* delta 2)))
+    (let* ((state     (vector-ref ___stack ___sp))
+           (new-state (cdr (assoc new-category (vector-ref ___gtable state)))))
+      (set! ___sp (+ ___sp 2))
+      (___checkstack)
+      (vector-set! ___stack ___sp new-state)
+      (vector-set! ___stack (- ___sp 1) (note-source-location lvalue tok))))
+  
+  (define (___reduce st)
+    ((vector-ref ___rtable st) ___stack ___sp ___gtable ___push ___pushback))
+  
+  (define (___shift token attribute)
+    (set! ___sp (+ ___sp 2))
+    (___checkstack)
+    (vector-set! ___stack (- ___sp 1) attribute)
+    (vector-set! ___stack ___sp token))
+  
+  (define (___action x l)
+    (let ((y (assoc x l)))
+      (if y (cadr y) (cadar l))))
+  
+  (define (___recover tok)
+    (let find-state ((sp ___sp))
+      (if (< sp 0)
+          (set! ___sp sp)
+          (let* ((state (vector-ref ___stack sp))
+                 (act   (assoc 'error (vector-ref ___atable state))))
+            (if act
+                (begin
+                  (set! ___sp sp)
+                  (___sync (cadr act) tok))
+                (find-state (- sp 2)))))))
+  
+  (define (___sync state tok)
+    (let ((sync-set (map car (cdr (vector-ref ___atable state)))))
+      (set! ___sp (+ ___sp 4))
+      (___checkstack)
+      (vector-set! ___stack (- ___sp 3) #f)
+      (vector-set! ___stack (- ___sp 2) state)
+      (let skip ()
+        (let ((i (___category ___input)))
+          (if (eq? i '*eoi*)
+              (set! ___sp -1)
+              (if (memq i sync-set)
+                  (let ((act (assoc i (vector-ref ___atable state))))
+                    (vector-set! ___stack (- ___sp 1) #f)
+                    (vector-set! ___stack ___sp (cadr act)))
+                  (begin
+                    (___consume)
+                    (skip))))))))
+  
+  (define (___category tok)
+    (if (lexical-token? tok)
+        (lexical-token-category tok)
+        tok))
+
+  (define (___run)
+    (let loop ()
+      (if ___input
+          (let* ((state (vector-ref ___stack ___sp))
+                 (i     (___category ___input))
+                 (act   (___action i (vector-ref ___atable state))))
+            
+            (cond ((not (symbol? i))
+                   (___errorp "Syntax error: invalid token: " ___input)
+                   #f)
+             
+                  ;; Input succesfully parsed
+                  ((eq? act 'accept)
+                   (vector-ref ___stack 1))
+                  
+                  ;; Syntax error in input
+                  ((eq? act '*error*)
+                   (if (eq? i '*eoi*)
+                       (begin
+                         (___errorp "Syntax error: unexpected end of input")
+                         #f)
+                       (begin
+                         (___errorp "Syntax error: unexpected token : " ___input)
+                         (___recover i)
+                         (if (>= ___sp 0)
+                             (set! ___input #f)
+                             (begin
+                               (set! ___sp 0)
+                               (set! ___input '*eoi*)))
+                         (loop))))
+             
+                  ;; Shift current token on top of the stack
+                  ((>= act 0)
+                   (___shift act ___input)
+                   (set! ___input (if (eq? i '*eoi*) '*eoi* #f))
+                   (loop))
+             
+                  ;; Reduce by rule (- act)
+                  (else
+                   (___reduce (- act))
+                   (loop))))
+          
+          ;; no lookahead, so check if there is a default action
+          ;; that does not require the lookahead
+          (let* ((state  (vector-ref ___stack ___sp))
+                 (acts   (vector-ref ___atable state))
+                 (defact (if (pair? acts) (cadar acts) #f)))
+            (if (and (= 1 (length acts)) (< defact 0))
+                (___reduce (- defact))
+                (___consume))
+            (loop)))))
+  
+
+  (lambda (lexerp errorp)
+    (set! ___errorp errorp)
+    (set! ___lexerp lexerp)
+    (___initstack)
+    (___run)))
+
+
+;;;
+;;;;  Simple-minded GLR-driver
+;;;
+
+
+(define (glr-driver action-table goto-table reduction-table)
+  (define ___atable action-table)
+  (define ___gtable goto-table)
+  (define ___rtable reduction-table)
+
+  (define ___lexerp #f)
+  (define ___errorp #f)
+  
+  ;; -- Input handling 
+  
+  (define *input* #f)
+  (define (initialize-lexer lexer)
+    (set! ___lexerp lexer)
+    (set! *input* #f))
+  (define (consume)
+    (set! *input* (___lexerp)))
+  
+  (define (token-category tok)
+    (if (lexical-token? tok)
+        (lexical-token-category tok)
+        tok))
+
+  (define (token-attribute tok)
+    (if (lexical-token? tok)
+        (lexical-token-value tok)
+        tok))
+
+  ;; -- Processes (stacks) handling
+  
+  (define *processes* '())
+  
+  (define (initialize-processes)
+    (set! *processes* '()))
+  (define (add-process process)
+    (set! *processes* (cons process *processes*)))
+  (define (get-processes)
+    (reverse *processes*))
+  
+  (define (for-all-processes proc)
+    (let ((processes (get-processes)))
+      (initialize-processes)
+      (for-each proc processes)))
+  
+  ;; -- parses
+  (define *parses* '())
+  (define (get-parses)
+    *parses*)
+  (define (initialize-parses)
+    (set! *parses* '()))
+  (define (add-parse parse)
+    (set! *parses* (cons parse *parses*)))
+    
+
+  (define (push delta new-category lvalue stack tok)
+    (let* ((stack     (drop stack (* delta 2)))
+           (state     (car stack))
+           (new-state (cdr (assv new-category (vector-ref ___gtable state)))))
+        (cons new-state (cons (note-source-location lvalue tok) stack))))
+  
+  (define (reduce state stack)
+    ((vector-ref ___rtable state) stack ___gtable push))
+  
+  (define (shift state symbol stack)
+    (cons state (cons symbol stack)))
+  
+  (define (get-actions token action-list)
+    (let ((pair (assoc token action-list)))
+      (if pair 
+          (cdr pair)
+          (cdar action-list)))) ;; get the default action
+  
+
+  (define (run)
+    (let loop-tokens ()
+      (consume)
+      (let ((symbol (token-category *input*)))
+        (for-all-processes
+         (lambda (process)
+           (let loop ((stacks (list process)) (active-stacks '()))
+             (cond ((pair? stacks)
+                    (let* ((stack   (car stacks))
+                           (state   (car stack)))
+                      (let actions-loop ((actions      (get-actions symbol (vector-ref ___atable state)))
+                                         (active-stacks active-stacks))
+                        (if (pair? actions)
+                            (let ((action        (car actions))
+                                  (other-actions (cdr actions)))
+                              (cond ((eq? action '*error*)
+                                     (actions-loop other-actions active-stacks))
+                                    ((eq? action 'accept)
+                                     (add-parse (car (take-right stack 2)))
+                                     (actions-loop other-actions active-stacks))
+                                    ((>= action 0)
+                                     (let ((new-stack (shift action *input* stack)))
+                                       (add-process new-stack))
+                                     (actions-loop other-actions active-stacks))
+                                    (else
+                                     (let ((new-stack (reduce (- action) stack)))
+                                      (actions-loop other-actions (cons new-stack active-stacks))))))
+                            (loop (cdr stacks) active-stacks)))))
+                   ((pair? active-stacks)
+                    (loop (reverse active-stacks) '())))))))
+      (if (pair? (get-processes))
+          (loop-tokens))))
+
+  
+  (lambda (lexerp errorp)
+    (set! ___errorp errorp)
+    (initialize-lexer lexerp)
+    (initialize-processes)
+    (initialize-parses)
+    (add-process '(0))
+    (run)
+    (get-parses)))
+
+
+(define (drop l n)
+  (cond ((and (> n 0) (pair? l))
+        (drop (cdr l) (- n 1)))
+       (else
+        l)))
+
+(define (take-right l n)
+  (drop l (- (length l) n)))
diff --git a/mes/module/mes/let.mes b/mes/module/mes/let.mes
new file mode 100644 (file)
index 0000000..6cc5102
--- /dev/null
@@ -0,0 +1,74 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; let.mes is loaded after base and quasiquote.  It provides
+;;; let, let* and named let.
+
+;;; Code:
+
+(mes-use-module (mes base))
+(mes-use-module (mes quasiquote))
+
+(define-macro (simple-let bindings . rest)
+  (cons (cons 'lambda (cons (map1 car bindings) rest))
+        (map1 cadr bindings)))
+
+(define-macro (xsimple-let bindings rest)
+  `(,`(lambda ,(map1 car bindings) ,@rest)
+    ,@(map1 cadr bindings)))
+
+(define-macro (xnamed-let name bindings rest)
+  `(simple-let ((,name *unspecified*))
+     (set! ,name (lambda ,(map1 car bindings) ,@rest))
+     (,name ,@(map1 cadr bindings))))
+
+(define-macro (let bindings-or-name . rest)
+  (if (symbol? bindings-or-name)
+      `(xnamed-let ,bindings-or-name ,(car rest) ,(cdr rest))
+      `(xsimple-let ,bindings-or-name ,rest)))
+
+(define (expand-let* bindings body)
+  (if (null? bindings)
+      `((lambda () ,@body))
+      `((lambda (,(caar bindings))
+          ,(expand-let* (cdr bindings) body))
+        ,@(cdar bindings))))
+
+(define-macro (let* bindings . body)
+  (expand-let* bindings body))
+
+(define (unspecified-bindings bindings params)
+  (if (null? bindings) params
+      (unspecified-bindings
+       (cdr bindings)
+       (append params (cons (cons (caar bindings) '(*unspecified*)) '())))))
+
+(define (letrec-setters bindings setters)
+  (if (null? bindings) setters
+      (letrec-setters (cdr bindings)
+                      (append setters
+                              (cons (cons 'set! (car bindings)) '())))))
+
+(define-macro (letrec bindings . body)
+  `(let ,(unspecified-bindings bindings '())
+     ,@(letrec-setters bindings '())
+     ,@body))
diff --git a/mes/module/mes/match.mes b/mes/module/mes/match.mes
new file mode 100644 (file)
index 0000000..537ba0b
--- /dev/null
@@ -0,0 +1,26 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; portable matcher
+
+(mes-use-module (mes syntax))
+(include-from-path "mes/match.scm")
diff --git a/mes/module/mes/match.scm b/mes/module/mes/match.scm
new file mode 100644 (file)
index 0000000..a89cb9a
--- /dev/null
@@ -0,0 +1,934 @@
+;;; match.scm -- portable hygienic pattern matcher -*- coding: utf-8; mode: scheme -*-
+;;
+;; This code is written by Alex Shinn and placed in the
+;; Public Domain.  All warranties are disclaimed.
+
+;;> @example-import[(srfi 9)]
+
+;;> This is a full superset of the popular @hyperlink[
+;;> "http://www.cs.indiana.edu/scheme-repository/code.match.html"]{match}
+;;> package by Andrew Wright, written in fully portable @scheme{syntax-rules}
+;;> and thus preserving hygiene.
+
+;;> The most notable extensions are the ability to use @emph{non-linear}
+;;> patterns - patterns in which the same identifier occurs multiple
+;;> times, tail patterns after ellipsis, and the experimental tree patterns.
+
+;;> @subsubsection{Patterns}
+
+;;> Patterns are written to look like the printed representation of
+;;> the objects they match.  The basic usage is
+
+;;> @scheme{(match expr (pat body ...) ...)}
+
+;;> where the result of @var{expr} is matched against each pattern in
+;;> turn, and the corresponding body is evaluated for the first to
+;;> succeed.  Thus, a list of three elements matches a list of three
+;;> elements.
+
+;;> @example{(let ((ls (list 1 2 3))) (match ls ((1 2 3) #t)))}
+
+;;> If no patterns match an error is signalled.
+
+;;> Identifiers will match anything, and make the corresponding
+;;> binding available in the body.
+
+;;> @example{(match (list 1 2 3) ((a b c) b))}
+
+;;> If the same identifier occurs multiple times, the first instance
+;;> will match anything, but subsequent instances must match a value
+;;> which is @scheme{equal?} to the first.
+
+;;> @example{(match (list 1 2 1) ((a a b) 1) ((a b a) 2))}
+
+;;> The special identifier @scheme{_} matches anything, no matter how
+;;> many times it is used, and does not bind the result in the body.
+
+;;> @example{(match (list 1 2 1) ((_ _ b) 1) ((a b a) 2))}
+
+;;> To match a literal identifier (or list or any other literal), use
+;;> @scheme{quote}.
+
+;;> @example{(match 'a ('b 1) ('a 2))}
+
+;;> Analogous to its normal usage in scheme, @scheme{quasiquote} can
+;;> be used to quote a mostly literally matching object with selected
+;;> parts unquoted.
+
+;;> @example|{(match (list 1 2 3) (`(1 ,b ,c) (list b c)))}|
+
+;;> Often you want to match any number of a repeated pattern.  Inside
+;;> a list pattern you can append @scheme{...} after an element to
+;;> match zero or more of that pattern (like a regexp Kleene star).
+
+;;> @example{(match (list 1 2) ((1 2 3 ...) #t))}
+;;> @example{(match (list 1 2 3) ((1 2 3 ...) #t))}
+;;> @example{(match (list 1 2 3 3 3) ((1 2 3 ...) #t))}
+
+;;> Pattern variables matched inside the repeated pattern are bound to
+;;> a list of each matching instance in the body.
+
+;;> @example{(match (list 1 2) ((a b c ...) c))}
+;;> @example{(match (list 1 2 3) ((a b c ...) c))}
+;;> @example{(match (list 1 2 3 4 5) ((a b c ...) c))}
+
+;;> More than one @scheme{...} may not be used in the same list, since
+;;> this would require exponential backtracking in the general case.
+;;> However, @scheme{...} need not be the final element in the list,
+;;> and may be succeeded by a fixed number of patterns.
+
+;;> @example{(match (list 1 2 3 4) ((a b c ... d e) c))}
+;;> @example{(match (list 1 2 3 4 5) ((a b c ... d e) c))}
+;;> @example{(match (list 1 2 3 4 5 6 7) ((a b c ... d e) c))}
+
+;;> @scheme{___} is provided as an alias for @scheme{...} when it is
+;;> inconvenient to use the ellipsis (as in a syntax-rules template).
+
+;;> The @scheme{..1} syntax is exactly like the @scheme{...} except
+;;> that it matches one or more repetitions (like a regexp "+").
+
+;;> @example{(match (list 1 2) ((a b c ..1) c))}
+;;> @example{(match (list 1 2 3) ((a b c ..1) c))}
+
+;;> The boolean operators @scheme{and}, @scheme{or} and @scheme{not}
+;;> can be used to group and negate patterns analogously to their
+;;> Scheme counterparts.
+
+;;> The @scheme{and} operator ensures that all subpatterns match.
+;;> This operator is often used with the idiom @scheme{(and x pat)} to
+;;> bind @var{x} to the entire value that matches @var{pat}
+;;> (c.f. "as-patterns" in ML or Haskell).  Another common use is in
+;;> conjunction with @scheme{not} patterns to match a general case
+;;> with certain exceptions.
+
+;;> @example{(match 1 ((and) #t))}
+;;> @example{(match 1 ((and x) x))}
+;;> @example{(match 1 ((and x 1) x))}
+
+;;> The @scheme{or} operator ensures that at least one subpattern
+;;> matches.  If the same identifier occurs in different subpatterns,
+;;> it is matched independently.  All identifiers from all subpatterns
+;;> are bound if the @scheme{or} operator matches, but the binding is
+;;> only defined for identifiers from the subpattern which matched.
+
+;;> @example{(match 1 ((or) #t) (else #f))}
+;;> @example{(match 1 ((or x) x))}
+;;> @example{(match 1 ((or x 2) x))}
+
+;;> The @scheme{not} operator succeeds if the given pattern doesn't
+;;> match.  None of the identifiers used are available in the body.
+
+;;> @example{(match 1 ((not 2) #t))}
+
+;;> The more general operator @scheme{?} can be used to provide a
+;;> predicate.  The usage is @scheme{(? predicate pat ...)} where
+;;> @var{predicate} is a Scheme expression evaluating to a predicate
+;;> called on the value to match, and any optional patterns after the
+;;> predicate are then matched as in an @scheme{and} pattern.
+
+;;> @example{(match 1 ((? odd? x) x))}
+
+;;> The field operator @scheme{=} is used to extract an arbitrary
+;;> field and match against it.  It is useful for more complex or
+;;> conditional destructuring that can't be more directly expressed in
+;;> the pattern syntax.  The usage is @scheme{(= field pat)}, where
+;;> @var{field} can be any expression, and should result in a
+;;> procedure of one argument, which is applied to the value to match
+;;> to generate a new value to match against @var{pat}.
+
+;;> Thus the pattern @scheme{(and (= car x) (= cdr y))} is equivalent
+;;> to @scheme{(x . y)}, except it will result in an immediate error
+;;> if the value isn't a pair.
+
+;;> @example{(match '(1 . 2) ((= car x) x))}
+;;> @example{(match 4 ((= sqrt x) x))}
+
+;;> The record operator @scheme{$} is used as a concise way to match
+;;> records defined by SRFI-9 (or SRFI-99).  The usage is
+;;> @scheme{($ rtd field ...)}, where @var{rtd} should be the record
+;;> type descriptor specified as the first argument to
+;;> @scheme{define-record-type}, and each @var{field} is a subpattern
+;;> matched against the fields of the record in order.  Not all fields
+;;> must be present.
+
+;;> @example{
+;;> (let ()
+;;>   (define-record-type employee
+;;>     (make-employee name title)
+;;>     employee?
+;;>     (name get-name)
+;;>     (title get-title))
+;;>   (match (make-employee "Bob" "Doctor")
+;;>     (($ employee n t) (list t n))))
+;;> }
+
+;;> The @scheme{set!} and @scheme{get!} operators are used to bind an
+;;> identifier to the setter and getter of a field, respectively.  The
+;;> setter is a procedure of one argument, which mutates the field to
+;;> that argument.  The getter is a procedure of no arguments which
+;;> returns the current value of the field.
+
+;;> @example{(let ((x (cons 1 2))) (match x ((1 . (set! s)) (s 3) x)))}
+;;> @example{(match '(1 . 2) ((1 . (get! g)) (g)))}
+
+;;> The new operator @scheme{***} can be used to search a tree for
+;;> subpatterns.  A pattern of the form @scheme{(x *** y)} represents
+;;> the subpattern @var{y} located somewhere in a tree where the path
+;;> from the current object to @var{y} can be seen as a list of the
+;;> form @scheme{(x ...)}.  @var{y} can immediately match the current
+;;> object in which case the path is the empty list.  In a sense it's
+;;> a 2-dimensional version of the @scheme{...} pattern.
+
+;;> As a common case the pattern @scheme{(_ *** y)} can be used to
+;;> search for @var{y} anywhere in a tree, regardless of the path
+;;> used.
+
+;;> @example{(match '(a (a (a b))) ((x *** 'b) x))}
+;;> @example{(match '(a (b) (c (d e) (f g))) ((x *** 'g) x))}
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Notes
+
+;; The implementation is a simple generative pattern matcher - each
+;; pattern is expanded into the required tests, calling a failure
+;; continuation if the tests fail.  This makes the logic easy to
+;; follow and extend, but produces sub-optimal code in cases where you
+;; have many similar clauses due to repeating the same tests.
+;; Nonetheless a smart compiler should be able to remove the redundant
+;; tests.  For MATCH-LET and DESTRUCTURING-BIND type uses there is no
+;; performance hit.
+
+;; The original version was written on 2006/11/29 and described in the
+;; following Usenet post:
+;;   http://groups.google.com/group/comp.lang.scheme/msg/0941234de7112ffd
+;; and is still available at
+;;   http://synthcode.com/scheme/match-simple.scm
+;; It's just 80 lines for the core MATCH, and an extra 40 lines for
+;; MATCH-LET, MATCH-LAMBDA and other syntactic sugar.
+;;
+;; A variant of this file which uses COND-EXPAND in a few places for
+;; performance can be found at
+;;   http://synthcode.com/scheme/match-cond-expand.scm
+;;
+;; 2012/05/23 - fixing combinatorial explosion of code in certain or patterns
+;; 2011/09/25 - fixing bug when directly matching an identifier repeated in
+;;              the pattern (thanks to Stefan Israelsson Tampe)
+;; 2011/01/27 - fixing bug when matching tail patterns against improper lists
+;; 2010/09/26 - adding `..1' patterns (thanks to Ludovic Courtès)
+;; 2010/09/07 - fixing identifier extraction in some `...' and `***' patterns
+;; 2009/11/25 - adding `***' tree search patterns
+;; 2008/03/20 - fixing bug where (a ...) matched non-lists
+;; 2008/03/15 - removing redundant check in vector patterns
+;; 2008/03/06 - you can use `...' portably now (thanks to Taylor Campbell)
+;; 2007/09/04 - fixing quasiquote patterns
+;; 2007/07/21 - allowing ellipse patterns in non-final list positions
+;; 2007/04/10 - fixing potential hygiene issue in match-check-ellipse
+;;              (thanks to Taylor Campbell)
+;; 2007/04/08 - clean up, commenting
+;; 2006/12/24 - bugfixes
+;; 2006/12/01 - non-linear patterns, shared variables in OR, get!/set!
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; force compile-time syntax errors with useful messages
+
+(define-syntax match-syntax-error
+  (syntax-rules ()
+    ((_) (match-syntax-error "invalid match-syntax-error usage"))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;> @subsubsection{Syntax}
+
+;;> @subsubsubsection{@rawcode{(match expr (pattern . body) ...)@br{}
+;;> (match expr (pattern (=> failure) . body) ...)}}
+
+;;> The result of @var{expr} is matched against each @var{pattern} in
+;;> turn, according to the pattern rules described in the previous
+;;> section, until the the first @var{pattern} matches.  When a match is
+;;> found, the corresponding @var{body}s are evaluated in order,
+;;> and the result of the last expression is returned as the result
+;;> of the entire @scheme{match}.  If a @var{failure} is provided,
+;;> then it is bound to a procedure of no arguments which continues,
+;;> processing at the next @var{pattern}.  If no @var{pattern} matches,
+;;> an error is signalled.
+
+;; The basic interface.  MATCH just performs some basic syntax
+;; validation, binds the match expression to a temporary variable `v',
+;; and passes it on to MATCH-NEXT.  It's a constant throughout the
+;; code below that the binding `v' is a direct variable reference, not
+;; an expression.
+
+(define-syntax match
+  (syntax-rules ()
+    ((match)
+     (match-syntax-error "missing match expression"))
+    ((match atom)
+     (match-syntax-error "no match clauses"))
+    ((match (app ...) (pat . body) ...)
+     (let ((v (app ...)))
+       (match-next v ((app ...) (set! (app ...))) (pat . body) ...)))
+    ((match #(vec ...) (pat . body) ...)
+     (let ((v #(vec ...)))
+       (match-next v (v (set! v)) (pat . body) ...)))
+    ((match atom (pat . body) ...)
+     (let ((v atom))
+       (match-next v (atom (set! atom)) (pat . body) ...)))
+    ))
+
+;; MATCH-NEXT passes each clause to MATCH-ONE in turn with its failure
+;; thunk, which is expanded by recursing MATCH-NEXT on the remaining
+;; clauses.  `g+s' is a list of two elements, the get! and set!
+;; expressions respectively.
+
+(define-syntax match-next
+  (syntax-rules (=>)
+    ;; no more clauses, the match failed
+    ((match-next v g+s)
+     ;; Here we call error in non-tail context, so that the backtrace
+     ;; can show the source location of the failing match form.
+     (begin
+       (error 'match "no matching pattern" v)
+       #f))
+    ;; named failure continuation
+    ((match-next v g+s (pat (=> failure) . body) . rest)
+     (let ((failure (lambda () (match-next v g+s . rest))))
+       ;; match-one analyzes the pattern for us
+       (match-one v pat g+s (match-drop-ids (begin . body)) (failure) ())))
+    ;; anonymous failure continuation, give it a dummy name
+    ((match-next v g+s (pat . body) . rest)
+     (match-next v g+s (pat (=> failure) . body) . rest))))
+
+;; MATCH-ONE first checks for ellipse patterns, otherwise passes on to
+;; MATCH-TWO.
+
+(define-syntax match-one
+  (syntax-rules ()
+    ;; If it's a list of two or more values, check to see if the
+    ;; second one is an ellipse and handle accordingly, otherwise go
+    ;; to MATCH-TWO.
+    ((match-one v (p q . r) g+s sk fk i)
+     (match-check-ellipse
+      q
+      (match-extract-vars p (match-gen-ellipses v p r  g+s sk fk i) i ())
+      (match-two v (p q . r) g+s sk fk i)))
+    ;; Go directly to MATCH-TWO.
+    ((match-one . x)
+     (match-two . x))))
+
+;; This is the guts of the pattern matcher.  We are passed a lot of
+;; information in the form:
+;;
+;;   (match-two var pattern getter setter success-k fail-k (ids ...))
+;;
+;; usually abbreviated
+;;
+;;   (match-two v p g+s sk fk i)
+;;
+;; where VAR is the symbol name of the current variable we are
+;; matching, PATTERN is the current pattern, getter and setter are the
+;; corresponding accessors (e.g. CAR and SET-CAR! of the pair holding
+;; VAR), SUCCESS-K is the success continuation, FAIL-K is the failure
+;; continuation (which is just a thunk call and is thus safe to expand
+;; multiple times) and IDS are the list of identifiers bound in the
+;; pattern so far.
+
+(define-syntax match-two
+  (syntax-rules (_ ___ ..1 *** quote quasiquote ? $ = and or not set! get!)
+    ((match-two v () g+s (sk ...) fk i)
+     (if (null? v) (sk ... i) fk))
+    ((match-two v (quote p) g+s (sk ...) fk i)
+     (if (equal? v 'p) (sk ... i) fk))
+    ((match-two v (quasiquote p) . x)
+     (match-quasiquote v p . x))
+    ((match-two v (and) g+s (sk ...) fk i) (sk ... i))
+    ((match-two v (and p q ...) g+s sk fk i)
+     (match-one v p g+s (match-one v (and q ...) g+s sk fk) fk i))
+    ((match-two v (or) g+s sk fk i) fk)
+    ((match-two v (or p) . x)
+     (match-one v p . x))
+    ((match-two v (or p ...) g+s sk fk i)
+     (match-extract-vars (or p ...) (match-gen-or v (p ...) g+s sk fk i) i ()))
+    ((match-two v (not p) g+s (sk ...) fk i)
+     (match-one v p g+s (match-drop-ids fk) (sk ... i) i))
+    ((match-two v (get! getter) (g s) (sk ...) fk i)
+     (let ((getter (lambda () g))) (sk ... i)))
+    ((match-two v (set! setter) (g (s ...)) (sk ...) fk i)
+     (let ((setter (lambda (x) (s ... x)))) (sk ... i)))
+    ((match-two v (? pred . p) g+s sk fk i)
+     (if (pred v) (match-one v (and . p) g+s sk fk i) fk))
+    ((match-two v (= proc p) . x)
+     (let ((w (proc v))) (match-one w p . x))
+     ;;(let ((W (proc v))) (match-one W p . x))
+     )
+    ((match-two v (p ___ . r) g+s sk fk i)
+     (match-extract-vars p (match-gen-ellipses v p r g+s sk fk i) i ()))
+    ((match-two v (p) g+s sk fk i)
+     (if (and (pair? v) (null? (cdr v)))
+         (let ;;((w (car v)))
+             ((W (car v)))
+           ;;(match-one w p ((car v) (set-car! v)) sk fk i)
+           (match-one W p ((car v) (set-car! v)) sk fk i)
+           )
+         fk))
+    ((match-two v (p *** q) g+s sk fk i)
+     (match-extract-vars p (match-gen-search v p q g+s sk fk i) i ()))
+    ((match-two v (p *** . q) g+s sk fk i)
+     (match-syntax-error "invalid use of ***" (p *** . q)))
+    ((match-two v (p ..1) g+s sk fk i)
+     (if (pair? v)
+         (match-one v (p ___) g+s sk fk i)
+         fk))
+    ((match-two v ($ rec p ...) g+s sk fk i)
+     (if (is-a? v rec)
+         (match-record-refs v rec 0 (p ...) g+s sk fk i)
+         fk))
+    ((match-two v (p . q) g+s sk fk i)
+     (if (pair? v)
+         (let ;;((w (car v)) (x (cdr v)))
+             ((W (car v)) (X (cdr v)))
+           (match-one ;;w p ((car v) (set-car! v))
+                      W p ((car v) (set-car! v))
+                      ;;(match-one x q ((cdr v) (set-cdr! v)) sk fk)
+                      (match-one X q ((cdr v) (set-cdr! v)) sk fk)
+                      fk
+                      i))
+         fk))
+    ((match-two v #(p ...) g+s . x)
+     (match-vector v 0 () (p ...) . x))
+    ((match-two v _ g+s (sk ...) fk i) (sk ... i))
+    ;; Not a pair or vector or special literal, test to see if it's a
+    ;; new symbol, in which case we just bind it, or if it's an
+    ;; already bound symbol or some other literal, in which case we
+    ;; compare it with EQUAL?.
+    (;;(match-two v x g+s (sk ...) fk (id ...))
+     (match-two V X g+s (sk ...) fk (id ...))
+     (let-syntax
+         ((new-sym?
+           (syntax-rules (id ...)
+             ;;((new-sym? x sk2 fk2) sk2)
+             ((new-sym? X sk2 fk2) sk2)
+             ((new-sym? y sk2 fk2) fk2))))
+       (new-sym? random-sym-to-match
+                 ;;(let ((x v)) (sk ... (id ... x)))
+                 (let ((X V)) (sk ... (id ... X)))
+                 ;;(if (equal? v x) (sk ... (id ...)) fk)
+                 (if (equal? V X) (sk ... (id ...)) fk)
+                 )))
+    ))
+
+;; QUASIQUOTE patterns
+
+(define-syntax match-quasiquote
+  (syntax-rules (unquote unquote-splicing quasiquote)
+    ((_ v (unquote p) g+s sk fk i)
+     (match-one v p g+s sk fk i))
+    ((_ v ((unquote-splicing p) . rest) g+s sk fk i)
+     (if (pair? v)
+       (match-one v
+                  (p . tmp)
+                  (match-quasiquote tmp rest g+s sk fk)
+                  fk
+                  i)
+       fk))
+    ((_ v (quasiquote p) g+s sk fk i . depth)
+     (match-quasiquote v p g+s sk fk i #f . depth))
+    ((_ v (unquote p) g+s sk fk i x . depth)
+     (match-quasiquote v p g+s sk fk i . depth))
+    ((_ v (unquote-splicing p) g+s sk fk i x . depth)
+     (match-quasiquote v p g+s sk fk i . depth))
+    ((_ v (p . q) g+s sk fk i . depth)
+     (if (pair? v)
+         (let ;;((w (car v)) (x (cdr v)))
+             ((W (car v)) (X (cdr v)))
+         (match-quasiquote
+          ;;w p g+s
+          W p g+s
+          ;;(match-quasiquote-step x q g+s sk fk depth)
+          (match-quasiquote-step X q g+s sk fk depth)
+          fk i . depth))
+       fk))
+    ((_ v #(elt ...) g+s sk fk i . depth)
+     (if (vector? v)
+         (let ((ls (vector->list v)))
+           (match-quasiquote ls (elt ...) g+s sk fk i . depth))
+       fk))
+    ((_ v x g+s sk fk i . depth)
+     (match-one v 'x g+s sk fk i))))
+
+(define-syntax match-quasiquote-step
+  (syntax-rules ()
+    ((match-quasiquote-step x q g+s sk fk depth i)
+     (match-quasiquote x q g+s sk fk i . depth))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Utilities
+
+;; Takes two values and just expands into the first.
+(define-syntax match-drop-ids
+  (syntax-rules ()
+    ((_ expr ids ...) expr)))
+
+(define-syntax match-tuck-ids
+  (syntax-rules ()
+    ((_ (letish args (expr ...)) ids ...)
+     (letish args (expr ... ids ...)))))
+
+(define-syntax match-drop-first-arg
+  (syntax-rules ()
+    ((_ arg expr) expr)))
+
+;; To expand an OR group we try each clause in succession, passing the
+;; first that succeeds to the success continuation.  On failure for
+;; any clause, we just try the next clause, finally resorting to the
+;; failure continuation fk if all clauses fail.  The only trick is
+;; that we want to unify the identifiers, so that the success
+;; continuation can refer to a variable from any of the OR clauses.
+
+(define-syntax match-gen-or
+  (syntax-rules ()
+    ((_ v p g+s (sk ...) fk (i ...) ((id id-ls) ...))
+     (let ((sk2 (lambda (id ...) (sk ... (i ... id ...)))))
+       (match-gen-or-step v p g+s (match-drop-ids (sk2 id ...)) fk (i ...))))))
+
+(define-syntax match-gen-or-step
+  (syntax-rules ()
+    ((_ v () g+s sk fk . x)
+     ;; no OR clauses, call the failure continuation
+     fk)
+    ((_ v (p) . x)
+     ;; last (or only) OR clause, just expand normally
+     (match-one v p . x))
+    ((_ v (p . q) g+s sk fk i)
+     ;; match one and try the remaining on failure
+     (let ((fk2 (lambda () (match-gen-or-step v q g+s sk fk i))))
+       (match-one v p g+s sk (fk2) i)))
+    ))
+
+;; We match a pattern (p ...) by matching the pattern p in a loop on
+;; each element of the variable, accumulating the bound ids into lists.
+
+;; Look at the body of the simple case - it's just a named let loop,
+;; matching each element in turn to the same pattern.  The only trick
+;; is that we want to keep track of the lists of each extracted id, so
+;; when the loop recurses we cons the ids onto their respective list
+;; variables, and on success we bind the ids (what the user input and
+;; expects to see in the success body) to the reversed accumulated
+;; list IDs.
+
+(define-syntax match-gen-ellipses
+  (syntax-rules ()
+    (;;(_ v p () g+s (sk ...) fk i ((id id-ls) ...))
+     (_ v P () g+s (sk ...) fk i ((id id-ls) ...))
+     (match-check-identifier
+      ;;p
+      P
+      ;; simplest case equivalent to (p ...), just bind the list
+      (let ;;((p v))
+          ((P v))
+        (if ;;(list? p)
+         (list? P)
+             (sk ... i)
+             fk))
+       ;; simple case, match all elements of the list
+       (let loop ((ls v) (id-ls '()) ...)
+         (cond
+           ((null? ls)
+            (let ((id (reverse id-ls)) ...) (sk ... i)))
+           ((pair? ls)
+            (let ;;((w (car ls)))
+                ((W (car ls)))
+              (match-one ;;w p ((car ls) (set-car! ls))
+                         W p ((car ls) (set-car! ls))
+                         (match-drop-ids (loop (cdr ls) (cons id id-ls) ...))
+                         fk i)))
+           (else
+            fk)))))
+    ((_ v p r g+s (sk ...) fk i ((id id-ls) ...))
+     ;; general case, trailing patterns to match, keep track of the
+     ;; remaining list length so we don't need any backtracking
+     (match-verify-no-ellipses
+      r
+      (let* ((tail-len (length 'r))
+             (ls v)
+             (len (and (list? ls) (length ls))))
+        (if (or (not len) (< len tail-len))
+            fk
+            (let loop ((ls ls) (n len) (id-ls '()) ...)
+              (cond
+                ((= n tail-len)
+                 (let ((id (reverse id-ls)) ...)
+                   (match-one ls r (#f #f) (sk ...) fk i)))
+                ((pair? ls)
+                 (let ((w (car ls)))
+                   (match-one w p ((car ls) (set-car! ls))
+                              (match-drop-ids
+                               (loop (cdr ls) (- n 1) (cons id id-ls) ...))
+                              fk
+                              i)))
+                (else
+                 fk)))))))))
+
+;; This is just a safety check.  Although unlike syntax-rules we allow
+;; trailing patterns after an ellipses, we explicitly disable multiple
+;; ellipses at the same level.  This is because in the general case
+;; such patterns are exponential in the number of ellipses, and we
+;; don't want to make it easy to construct very expensive operations
+;; with simple looking patterns.  For example, it would be O(n^2) for
+;; patterns like (a ... b ...) because we must consider every trailing
+;; element for every possible break for the leading "a ...".
+
+(define-syntax match-verify-no-ellipses
+  (syntax-rules ()
+    ((_ (x . y) sk)
+     (match-check-ellipse
+      x
+      (match-syntax-error
+       "multiple ellipse patterns not allowed at same level")
+      (match-verify-no-ellipses y sk)))
+    ((_ () sk)
+     sk)
+    ((_ x sk)
+     (match-syntax-error "dotted tail not allowed after ellipse" x))))
+
+;; To implement the tree search, we use two recursive procedures.  TRY
+;; attempts to match Y once, and on success it calls the normal SK on
+;; the accumulated list ids as in MATCH-GEN-ELLIPSES.  On failure, we
+;; call NEXT which first checks if the current value is a list
+;; beginning with X, then calls TRY on each remaining element of the
+;; list.  Since TRY will recursively call NEXT again on failure, this
+;; effects a full depth-first search.
+;;
+;; The failure continuation throughout is a jump to the next step in
+;; the tree search, initialized with the original failure continuation
+;; FK.
+
+(define-syntax match-gen-search
+  (syntax-rules ()
+    ((match-gen-search v p q g+s sk fk i ((id id-ls) ...))
+     (letrec ((try (lambda (w fail id-ls ...)
+                     (match-one w q g+s
+                                (match-tuck-ids
+                                 (let ((id (reverse id-ls)) ...)
+                                   sk))
+                                (next w fail id-ls ...) i)))
+              (next (lambda (w fail id-ls ...)
+                      (if (not (pair? w))
+                          (fail)
+                          (let ((u (car w)))
+                            (match-one
+                             u p ((car w) (set-car! w))
+                             (match-drop-ids
+                              ;; accumulate the head variables from
+                              ;; the p pattern, and loop over the tail
+                              (let ((id-ls (cons id id-ls)) ...)
+                                (let lp ((ls (cdr w)))
+                                  (if (pair? ls)
+                                      (try (car ls)
+                                           (lambda () (lp (cdr ls)))
+                                           id-ls ...)
+                                      (fail)))))
+                             (fail) i))))))
+       ;; the initial id-ls binding here is a dummy to get the right
+       ;; number of '()s
+       (let ((id-ls '()) ...)
+         (try v (lambda () fk) id-ls ...))))))
+
+;; Vector patterns are just more of the same, with the slight
+;; exception that we pass around the current vector index being
+;; matched.
+
+(define-syntax match-vector
+  (syntax-rules (___)
+    ((_ v n pats (p q) . x)
+     (match-check-ellipse q
+                          (match-gen-vector-ellipses v n pats p . x)
+                          (match-vector-two v n pats (p q) . x)))
+    ((_ v n pats (p ___) sk fk i)
+     (match-gen-vector-ellipses v n pats p sk fk i))
+    ((_ . x)
+     (match-vector-two . x))))
+
+;; Check the exact vector length, then check each element in turn.
+
+(define-syntax match-vector-two
+  (syntax-rules ()
+    ((_ v n ((pat index) ...) () sk fk i)
+     (if (vector? v)
+         (let ((len (vector-length v)))
+           (if (= len n)
+               (match-vector-step v ((pat index) ...) sk fk i)
+               fk))
+         fk))
+    ((_ v n (pats ...) (p . q) . x)
+     (match-vector v (+ n 1) (pats ... (p n)) q . x))))
+
+(define-syntax match-vector-step
+  (syntax-rules ()
+    ((_ v () (sk ...) fk i) (sk ... i))
+    ((_ v ((pat index) . rest) sk fk i)
+     (let ((w (vector-ref v index)))
+       (match-one w pat ((vector-ref v index) (vector-set! v index))
+                  (match-vector-step v rest sk fk)
+                  fk i)))))
+
+;; With a vector ellipse pattern we first check to see if the vector
+;; length is at least the required length.
+
+(define-syntax match-gen-vector-ellipses
+  (syntax-rules ()
+    ((_ v n ((pat index) ...) p sk fk i)
+     (if (vector? v)
+       (let ((len (vector-length v)))
+         (if (>= len n)
+           (match-vector-step v ((pat index) ...)
+                              (match-vector-tail v p n len sk fk)
+                              fk i)
+           fk))
+       fk))))
+
+(define-syntax match-vector-tail
+  (syntax-rules ()
+    ((_ v p n len sk fk i)
+     (match-extract-vars p (match-vector-tail-two v p n len sk fk i) i ()))))
+
+(define-syntax match-vector-tail-two
+  (syntax-rules ()
+    ((_ v p n len (sk ...) fk i ((id id-ls) ...))
+     (let loop ((j n) (id-ls '()) ...)
+       (if (>= j len)
+         (let ((id (reverse id-ls)) ...) (sk ... i))
+         (let ((w (vector-ref v j)))
+           (match-one w p ((vector-ref v j) (vetor-set! v j))
+                      (match-drop-ids (loop (+ j 1) (cons id id-ls) ...))
+                      fk i)))))))
+
+(define-syntax match-record-refs
+  (syntax-rules ()
+    ((_ v rec n (p . q) g+s sk fk i)
+     (let ((w (slot-ref rec v n)))
+       (match-one w p ((slot-ref rec v n) (slot-set! rec v n))
+                  (match-record-refs v rec (+ n 1) q g+s sk fk) fk i)))
+    ((_ v rec n () g+s (sk ...) fk i)
+     (sk ... i))))
+
+;; Extract all identifiers in a pattern.  A little more complicated
+;; than just looking for symbols, we need to ignore special keywords
+;; and non-pattern forms (such as the predicate expression in ?
+;; patterns), and also ignore previously bound identifiers.
+;;
+;; Calls the continuation with all new vars as a list of the form
+;; ((orig-var tmp-name) ...), where tmp-name can be used to uniquely
+;; pair with the original variable (e.g. it's used in the ellipse
+;; generation for list variables).
+;;
+;; (match-extract-vars pattern continuation (ids ...) (new-vars ...))
+
+(define-syntax match-extract-vars
+  (syntax-rules (_ ___ ..1 *** ? $ = quote quasiquote and or not get! set!)
+    ((match-extract-vars (? pred . p) . x)
+     (match-extract-vars p . x))
+    ((match-extract-vars ($ rec . p) . x)
+     (match-extract-vars p . x))
+    ((match-extract-vars (= proc p) . x)
+     (match-extract-vars p . x))
+    ((match-extract-vars (quote x) (k ...) i v)
+     (k ... v))
+    ((match-extract-vars (quasiquote x) k i v)
+     (match-extract-quasiquote-vars x k i v (#t)))
+    ((match-extract-vars (and . p) . x)
+     (match-extract-vars p . x))
+    ((match-extract-vars (or . p) . x)
+     (match-extract-vars p . x))
+    ((match-extract-vars (not . p) . x)
+     (match-extract-vars p . x))
+    ;; A non-keyword pair, expand the CAR with a continuation to
+    ;; expand the CDR.
+    ((match-extract-vars (p q . r) k i v)
+     (match-check-ellipse
+      q
+      (match-extract-vars (p . r) k i v)
+      (match-extract-vars p (match-extract-vars-step (q . r) k i v) i ())))
+    ((match-extract-vars (p . q) k i v)
+     (match-extract-vars p (match-extract-vars-step q k i v) i ()))
+    ((match-extract-vars #(p ...) . x)
+     (match-extract-vars (p ...) . x))
+    ((match-extract-vars _ (k ...) i v)    (k ... v))
+    ((match-extract-vars ___ (k ...) i v)  (k ... v))
+    ((match-extract-vars *** (k ...) i v)  (k ... v))
+    ((match-extract-vars ..1 (k ...) i v)  (k ... v))
+    ;; This is the main part, the only place where we might add a new
+    ;; var if it's an unbound symbol.
+    ((match-extract-vars p (k ...) (i ...) v)
+     (let-syntax
+         ((new-sym?
+           (syntax-rules (i ...)
+             ((new-sym? p sk fk) sk)
+             ((new-sym? any sk fk) fk))))
+       (new-sym? random-sym-to-match
+                 (k ... ((p p-ls) . v))
+                 (k ... v))))
+    ))
+
+;; Stepper used in the above so it can expand the CAR and CDR
+;; separately.
+
+(define-syntax match-extract-vars-step
+  (syntax-rules ()
+    ((_ p k i v ((v2 v2-ls) ...))
+     (match-extract-vars p k (v2 ... . i) ((v2 v2-ls) ... . v)))
+    ))
+
+(define-syntax match-extract-quasiquote-vars
+  (syntax-rules (quasiquote unquote unquote-splicing)
+    ((match-extract-quasiquote-vars (quasiquote x) k i v d)
+     (match-extract-quasiquote-vars x k i v (#t . d)))
+    ((match-extract-quasiquote-vars (unquote-splicing x) k i v d)
+     (match-extract-quasiquote-vars (unquote x) k i v d))
+    ((match-extract-quasiquote-vars (unquote x) k i v (#t))
+     (match-extract-vars x k i v))
+    ((match-extract-quasiquote-vars (unquote x) k i v (#t . d))
+     (match-extract-quasiquote-vars x k i v d))
+    ((match-extract-quasiquote-vars (x . y) k i v (#t . d))
+     (match-extract-quasiquote-vars
+      x
+      (match-extract-quasiquote-vars-step y k i v d) i ()))
+    ((match-extract-quasiquote-vars #(x ...) k i v (#t . d))
+     (match-extract-quasiquote-vars (x ...) k i v d))
+    ((match-extract-quasiquote-vars x (k ...) i v (#t . d))
+     (k ... v))
+    ))
+
+(define-syntax match-extract-quasiquote-vars-step
+  (syntax-rules ()
+    ((_ x k i v d ((v2 v2-ls) ...))
+     (match-extract-quasiquote-vars x k (v2 ... . i) ((v2 v2-ls) ... . v) d))
+    ))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Gimme some sugar baby.
+
+;;> Shortcut for @scheme{lambda} + @scheme{match}.  Creates a
+;;> procedure of one argument, and matches that argument against each
+;;> clause.
+
+(define-syntax match-lambda
+  (syntax-rules ()
+    ((_ (pattern . body) ...) (lambda (expr) (match expr (pattern . body) ...)))))
+
+;;> Similar to @scheme{match-lambda}.  Creates a procedure of any
+;;> number of arguments, and matches the argument list against each
+;;> clause.
+
+(define-syntax match-lambda*
+  (syntax-rules ()
+    ((_ (pattern . body) ...) (lambda expr (match expr (pattern . body) ...)))))
+
+;;> Matches each var to the corresponding expression, and evaluates
+;;> the body with all match variables in scope.  Raises an error if
+;;> any of the expressions fail to match.  Syntax analogous to named
+;;> let can also be used for recursive functions which match on their
+;;> arguments as in @scheme{match-lambda*}.
+
+(define-syntax match-let
+  (syntax-rules ()
+    ((_ ((var value) ...) . body)
+     (match-let/helper let () () ((var value) ...) . body))
+    ((_ loop ((var init) ...) . body)
+     (match-named-let loop ((var init) ...) . body))))
+
+;; ;;> Similar to @scheme{match-let}, but analogously to @scheme{letrec}
+;; ;;> matches and binds the variables with all match variables in scope.
+
+;; (define-syntax match-letrec
+;;   (syntax-rules ()
+;;     ((_ ((var value) ...) . body)
+;;      (match-let/helper letrec () () ((var value) ...) . body))))
+
+;; (define-syntax match-let/helper
+;;   (syntax-rules ()
+;;     ((_ let ((var expr) ...) () () . body)
+;;      (let ((var expr) ...) . body))
+;;     ((_ let ((var expr) ...) ((pat tmp) ...) () . body)
+;;      (let ((var expr) ...)
+;;        (match-let* ((pat tmp) ...)
+;;          . body)))
+;;     ((_ let (v ...) (p ...) (((a . b) expr) . rest) . body)
+;;      (match-let/helper
+;;       let (v ... (tmp expr)) (p ... ((a . b) tmp)) rest . body))
+;;     ((_ let (v ...) (p ...) ((#(a ...) expr) . rest) . body)
+;;      (match-let/helper
+;;       let (v ... (tmp expr)) (p ... (#(a ...) tmp)) rest . body))
+;;     ((_ let (v ...) (p ...) ((a expr) . rest) . body)
+;;      (match-let/helper let (v ... (a expr)) (p ...) rest . body))))
+
+(define-syntax match-named-let
+  (syntax-rules ()
+    ((_ loop ((pat expr var) ...) () . body)
+     (let loop ((var expr) ...)
+       (match-let ((pat var) ...)
+         . body)))
+    ((_ loop (v ...) ((pat expr) . rest) . body)
+     (match-named-let loop (v ... (pat expr tmp)) rest . body))))
+
+;;> @subsubsubsection{@rawcode{(match-let* ((var value) ...) body ...)}}
+
+;;> Similar to @scheme{match-let}, but analogously to @scheme{let*}
+;;> matches and binds the variables in sequence, with preceding match
+;;> variables in scope.
+
+(define-syntax match-let*
+  (syntax-rules ()
+    ((_ () . body)
+     (begin . body))
+    ((_ ((pat expr) . rest) . body)
+     (match expr (pat (match-let* rest . body))))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Otherwise COND-EXPANDed bits.
+
+;; This *should* work, but doesn't :(
+;;   (define-syntax match-check-ellipse
+;;     (syntax-rules (...)
+;;       ((_ ... sk fk) sk)
+;;       ((_ x sk fk) fk)))
+
+;; This is a little more complicated, and introduces a new let-syntax,
+;; but should work portably in any R[56]RS Scheme.  Taylor Campbell
+;; originally came up with the idea.
+(define-syntax match-check-ellipse
+  (syntax-rules ()
+    ;; these two aren't necessary but provide fast-case failures
+    ((match-check-ellipse (a . b) success-k failure-k) failure-k)
+    ((match-check-ellipse #(a ...) success-k failure-k) failure-k)
+    ;; matching an atom
+    ((match-check-ellipse id success-k failure-k)
+     (let-syntax ((ellipse? (syntax-rules ()
+                              ;; iff `id' is `...' here then this will
+                              ;; match a list of any length
+                              ((ellipse? (foo id) sk fk) sk)
+                              ((ellipse? other sk fk) fk))))
+       ;; this list of three elements will only many the (foo id) list
+       ;; above if `id' is `...'
+       (ellipse? (a b c) success-k failure-k)))))
+
+;; This is portable but can be more efficient with non-portable
+;; extensions.  This trick was originally discovered by Oleg Kiselyov.
+
+(define-syntax match-check-identifier
+  (syntax-rules ()
+    ;; fast-case failures, lists and vectors are not identifiers
+    ((_ (x . y) success-k failure-k) failure-k)
+    ((_ #(x ...) success-k failure-k) failure-k)
+    ;; x is an atom
+    ((_ x success-k failure-k)
+     (let-syntax
+         ((sym?
+           (syntax-rules ()
+             ;; if the symbol `abracadabra' matches x, then x is a
+             ;; symbol
+             ((sym? x sk fk) sk)
+             ;; otherwise x is a non-symbol datum
+             ((sym? y sk fk) fk))))
+       (sym? abracadabra success-k failure-k)))))
diff --git a/mes/module/mes/mescc.mes b/mes/module/mes/mescc.mes
new file mode 100644 (file)
index 0000000..cb8ff2a
--- /dev/null
@@ -0,0 +1,25 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(include-from-path "mes/mescc.scm")
diff --git a/mes/module/mes/misc.mes b/mes/module/mes/misc.mes
new file mode 100644 (file)
index 0000000..6988ce8
--- /dev/null
@@ -0,0 +1,21 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+(include-from-path "mes/misc.scm")
diff --git a/mes/module/mes/module.mes b/mes/module/mes/module.mes
new file mode 100644 (file)
index 0000000..667817e
--- /dev/null
@@ -0,0 +1,64 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(define (module->file o)
+  (string-append (string-join (map symbol->string o) "/") ".mes"))
+
+(define *modules* '(mes/base-0.mes))
+(define-macro (mes-use-module module)
+  (list 'if (list not (list memq (list string->symbol (module->file module)) '*modules*))
+        (list
+         'begin
+         (list 'set! '*modules* (list cons (list string->symbol (module->file module)) '*modules*))
+         (list 'load (list string-append '%moduledir (module->file module))))
+        (list 'if (and (getenv "MES_DEBUG") (list '> (list 'core:cdr (list 'car (list 'string->list (getenv "MES_DEBUG")))) 50))
+              (list 'begin
+                    (list core:display-error ";;; already loaded: ")
+                    (list core:display-error (list 'quote module))
+                    (list core:display-error "\n")))))
+
+(define *input-ports* '())
+(define-macro (push! stack o)
+  (cons
+   'begin
+   (list
+    (list 'set! stack (list cons o stack))
+    stack)))
+(define-macro (pop! stack)
+  (list 'let (list (list 'o (list car stack)))
+        (list 'set! stack (list cdr stack))
+        'o))
+(define (mes-load-module-env module a)
+  (push! *input-ports* (current-input-port))
+  (set-current-input-port (open-input-file (string-append %moduledir (module->file module))))
+  (let ((x (core:eval (append2 (cons 'begin (read-input-file-env a))
+                               '((current-module)))
+                      a)))
+    (set-current-input-port (pop! *input-ports*))
+    x))
+(define (mes-load-module-env module a)
+  ((lambda (file-name)
+     (core:write-error file-name) (core:display-error "\n")
+     (primitive-load file-name))
+   (string-append %moduledir (module->file module))))
diff --git a/mes/module/mes/optargs.mes b/mes/module/mes/optargs.mes
new file mode 100644 (file)
index 0000000..cf6e670
--- /dev/null
@@ -0,0 +1,38 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Optargs (define*, lambda* et al.) from Guile
+
+;;; Code:
+
+(mes-use-module (mes scm))
+
+(define-macro (defmacro name args . body)
+  `(define-macro ,(cons name args) ,@body))
+
+(define-macro (set-procedure-property! proc key value)
+  proc)
+
+(include-from-path "mes/optargs.scm")
+
+(define-macro (define-macro* NAME+ARGLIST . BODY)
+  `(define-macro ,(car NAME+ARGLIST) #f (lambda* ,(cdr NAME+ARGLIST) ,@BODY)))
diff --git a/mes/module/mes/optargs.scm b/mes/module/mes/optargs.scm
new file mode 100644 (file)
index 0000000..943e21f
--- /dev/null
@@ -0,0 +1,500 @@
+;;;; optargs.scm -- support for optional arguments
+;;;;
+;;;;   Copyright (C) 1997, 1998, 1999, 2001, 2002, 2004, 2006 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+;;;; Contributed by Maciej Stachowiak <mstachow@alum.mit.edu>
+
+\f
+
+;;; Commentary:
+
+;;; {Optional Arguments}
+;;;
+;;; The C interface for creating Guile procedures has a very handy
+;;; "optional argument" feature. This module attempts to provide
+;;; similar functionality for procedures defined in Scheme with
+;;; a convenient and attractive syntax.
+;;;
+;;; exported macros are:
+;;;   let-optional
+;;;   let-optional*
+;;;   let-keywords
+;;;   let-keywords*
+;;;   lambda*
+;;;   define*
+;;;   define*-public
+;;;   defmacro*
+;;;   defmacro*-public
+;;;
+;;;
+;;; Summary of the lambda* extended parameter list syntax (brackets
+;;; are used to indicate grouping only):
+;;;
+;;; ext-param-list ::= [identifier]* [#:optional [ext-var-decl]+]?
+;;;   [#:key [ext-var-decl]+ [#:allow-other-keys]?]?
+;;;   [[#:rest identifier]|[. identifier]]?
+;;;
+;;; ext-var-decl ::= identifier | ( identifier expression )
+;;;
+;;; The characters `*', `+' and `?' are not to be taken literally; they
+;;; mean respectively, zero or more occurences, one or more occurences,
+;;; and one or zero occurences.
+;;;
+
+;;; Code:
+
+(define-module (ice-9 optargs)
+  #:use-module (system base pmatch)
+  #:replace (lambda*)
+  #:export-syntax (let-optional
+                 let-optional*
+                 let-keywords
+                 let-keywords*
+                 define*
+                  define*-public
+                 defmacro*
+                 defmacro*-public))
+
+;; let-optional rest-arg (binding ...) . body
+;; let-optional* rest-arg (binding ...) . body
+;;   macros used to bind optional arguments
+;;
+;; These two macros give you an optional argument interface that is
+;; very "Schemey" and introduces no fancy syntax. They are compatible
+;; with the scsh macros of the same name, but are slightly
+;; extended. Each of binding may be of one of the forms <var> or
+;; (<var> <default-value>). rest-arg should be the rest-argument of
+;; the procedures these are used from. The items in rest-arg are
+;; sequentially bound to the variable namess are given. When rest-arg
+;; runs out, the remaining vars are bound either to the default values
+;; or to `#f' if no default value was specified. rest-arg remains
+;; bound to whatever may have been left of rest-arg.
+;;
+
+(defmacro let-optional (REST-ARG BINDINGS . BODY)
+  (let-optional-template REST-ARG BINDINGS BODY 'let))
+
+(defmacro let-optional* (REST-ARG BINDINGS . BODY)
+  (let-optional-template REST-ARG BINDINGS BODY 'let*))
+
+
+
+;; let-keywords rest-arg allow-other-keys? (binding ...) . body
+;; let-keywords* rest-arg allow-other-keys? (binding ...) . body
+;;   macros used to bind keyword arguments
+;;
+;; These macros pick out keyword arguments from rest-arg, but do not
+;; modify it. This is consistent at least with Common Lisp, which
+;; duplicates keyword args in the rest arg. More explanation of what
+;; keyword arguments in a lambda list look like can be found below in
+;; the documentation for lambda*.  Bindings can have the same form as
+;; for let-optional. If allow-other-keys? is false, an error will be
+;; thrown if anything that looks like a keyword argument but does not
+;; match a known keyword parameter will result in an error.
+;;
+
+
+(defmacro let-keywords (REST-ARG ALLOW-OTHER-KEYS? BINDINGS . BODY)
+  (let-keywords-template REST-ARG ALLOW-OTHER-KEYS? BINDINGS BODY 'let))
+
+(defmacro let-keywords* (REST-ARG ALLOW-OTHER-KEYS? BINDINGS . BODY)
+  (let-keywords-template REST-ARG ALLOW-OTHER-KEYS? BINDINGS BODY 'let*))
+
+
+;; some utility procedures for implementing the various let-forms.
+
+(define (let-o-k-template REST-ARG BINDINGS BODY let-type proc)
+  (let ((bindings (map (lambda (x)
+                        (if (list? x)
+                            x
+                            (list x #f)))
+                      BINDINGS)))
+    `(,let-type ,(map proc bindings) ,@BODY)))
+
+(define (let-optional-template REST-ARG BINDINGS BODY let-type)
+    (if (null? BINDINGS)
+       `(let () ,@BODY)
+       (let-o-k-template REST-ARG BINDINGS BODY let-type
+                         (lambda (optional)
+                           `(,(car optional)
+                             (cond
+                              ((not (null? ,REST-ARG))
+                               (let ((result (car ,REST-ARG)))
+                                 ,(list 'set! REST-ARG
+                                        `(cdr ,REST-ARG))
+                                 result))
+                              (else
+                               ,(cadr optional))))))))
+
+(define (let-keywords-template REST-ARG ALLOW-OTHER-KEYS? BINDINGS BODY let-type)
+    (if (null? BINDINGS)
+       `(let () ,@BODY)
+       (let* ((kb-list-gensym (gensym "kb:G"))
+              (bindfilter (lambda (key)
+                            `(,(car key)
+                              (cond
+                               ((assq ',(car key) ,kb-list-gensym)
+                                => cdr)
+                               (else
+                                ,(cadr key)))))))
+         `(let ((,kb-list-gensym (;;(@@ (ice-9 optargs) rest-arg->keyword-binding-list)
+                                   rest-arg->keyword-binding-list
+                                   ,REST-ARG ',(map (lambda (x) (symbol->keyword (if (pair? x) (car x) x)))
+                                                    BINDINGS)
+                                   ,ALLOW-OTHER-KEYS?)))
+            ,(let-o-k-template REST-ARG BINDINGS BODY let-type bindfilter)))))
+
+
+(define (rest-arg->keyword-binding-list rest-arg keywords allow-other-keys?)
+  (if (null? rest-arg)
+      '()
+      (let loop ((first (car rest-arg))
+                (rest (cdr rest-arg))
+                (accum '()))
+       (let ((next (lambda (a)
+                     (if (null? (cdr rest))
+                         a
+                         (loop (cadr rest) (cddr rest) a)))))
+         (if (keyword? first)
+             (cond
+              ((memq first keywords)
+               (if (null? rest)
+                    (error "Keyword argument has no value:" first)
+                   (next (cons (cons (keyword->symbol first)
+                                     (car rest)) accum))))
+              ((not allow-other-keys?)
+                (error "Unknown keyword in arguments:" first))
+              (else (if (null? rest)
+                        accum
+                        (next accum))))
+             (if (null? rest)
+                 accum
+                 (loop (car rest) (cdr rest) accum)))))))
+
+
+;; lambda* args . body
+;;   lambda extended for optional and keyword arguments
+;;
+;; lambda* creates a procedure that takes optional arguments. These
+;; are specified by putting them inside brackets at the end of the
+;; paramater list, but before any dotted rest argument. For example,
+;;   (lambda* (a b #:optional c d . e) '())
+;; creates a procedure with fixed arguments a and b, optional arguments c
+;; and d, and rest argument e. If the optional arguments are omitted
+;; in a call, the variables for them are bound to `#f'.
+;;
+;; lambda* can also take keyword arguments. For example, a procedure
+;; defined like this:
+;;   (lambda* (#:key xyzzy larch) '())
+;; can be called with any of the argument lists (#:xyzzy 11)
+;; (#:larch 13) (#:larch 42 #:xyzzy 19) (). Whichever arguments
+;; are given as keywords are bound to values.
+;;
+;; Optional and keyword arguments can also be given default values
+;; which they take on when they are not present in a call, by giving a
+;; two-item list in place of an optional argument, for example in:
+;;   (lambda* (foo #:optional (bar 42) #:key (baz 73)) (list foo bar baz))
+;; foo is a fixed argument, bar is an optional argument with default
+;; value 42, and baz is a keyword argument with default value 73.
+;; Default value expressions are not evaluated unless they are needed
+;; and until the procedure is called.
+;;
+;; lambda* now supports two more special parameter list keywords.
+;;
+;; lambda*-defined procedures now throw an error by default if a
+;; keyword other than one of those specified is found in the actual
+;; passed arguments. However, specifying #:allow-other-keys
+;; immediately after the keyword argument declarations restores the
+;; previous behavior of ignoring unknown keywords. lambda* also now
+;; guarantees that if the same keyword is passed more than once, the
+;; last one passed is the one that takes effect. For example,
+;;   ((lambda* (#:key (heads 0) (tails 0)) (display (list heads tails)))
+;;    #:heads 37 #:tails 42 #:heads 99)
+;; would result in (99 47) being displayed.
+;;
+;; #:rest is also now provided as a synonym for the dotted syntax rest
+;; argument. The argument lists (a . b) and (a #:rest b) are equivalent in
+;; all respects to lambda*. This is provided for more similarity to DSSSL,
+;; MIT-Scheme and Kawa among others, as well as for refugees from other
+;; Lisp dialects.
+
+
+(defmacro lambda* (ARGLIST . BODY)
+  (parse-arglist
+   ARGLIST
+   (lambda (non-optional-args optionals keys aok? rest-arg)
+     ;; Check for syntax errors.
+     (if (not (every? symbol? non-optional-args))
+        (error "Syntax error in fixed argument declaration."))
+     (if (not (every? ext-decl? optionals))
+        (error "Syntax error in optional argument declaration."))
+     (if (not (every? ext-decl? keys))
+        (error "Syntax error in keyword argument declaration."))
+     (if (not (or (symbol? rest-arg) (eq? #f rest-arg)))
+        (error "Syntax error in rest argument declaration."))
+     ;; generate the code.
+     (let ((rest-gensym (or rest-arg (gensym "lambda*:G")))
+          (lambda-gensym (gensym "lambda*:L")))
+       (if (not (and (null? optionals) (null? keys)))
+          `(let ((,lambda-gensym
+                  (lambda (,@non-optional-args . ,rest-gensym)
+                    ;; Make sure that if the proc had a docstring, we put it
+                    ;; here where it will be visible.
+                    ,@(if (and (not (null? BODY))
+                               (string? (car BODY)))
+                          (list (car BODY))
+                          '())
+                    (let-optional*
+                     ,rest-gensym
+                     ,optionals
+                     (let-keywords* ,rest-gensym
+                                    ,aok?
+                                    ,keys
+                                    ,@(if (and (not rest-arg) (null? keys))
+                                          `((if (not (null? ,rest-gensym))
+                                                (error "Too many arguments.")))
+                                          '())
+                                    (let ()
+                                      ,@BODY))))))
+             (set-procedure-property! ,lambda-gensym 'arglist
+                                      '(,non-optional-args
+                                        ,optionals
+                                        ,keys
+                                        ,aok?
+                                        ,rest-arg))
+             ,lambda-gensym)
+          `(lambda (,@non-optional-args . ,(if rest-arg rest-arg '()))
+             ,@BODY))))))
+
+
+(define (every? pred lst)
+  (or (null? lst)
+      (and (pred (car lst))
+          (every? pred (cdr lst)))))
+
+(define (ext-decl? obj)
+  (or (symbol? obj)
+      (and (list? obj) (= 2 (length obj)) (symbol? (car obj)))))
+
+;; XXX - not tail recursive
+(define (improper-list-copy obj)
+  (if (pair? obj)
+      (cons (car obj) (improper-list-copy (cdr obj)))
+      obj))
+
+(define (parse-arglist arglist cont)
+  (define (split-list-at val lst cont)
+    (cond
+     ((memq val lst)
+      => (lambda (pos)
+          (if (memq val (cdr pos))
+              (error (with-output-to-string
+                       (lambda ()
+                         (map display `(,val
+                                        " specified more than once in argument list.")))))
+              (cont (reverse (cdr (memq val (reverse lst)))) (cdr pos) #t))))
+     (else (cont lst '() #f))))
+  (define (parse-opt-and-fixed arglist keys aok? rest cont)
+    (split-list-at
+     #:optional arglist
+     (lambda (before after split?)
+       (if (and split? (null? after))
+          (error "#:optional specified but no optional arguments declared.")
+          (cont before after keys aok? rest)))))
+  (define (parse-keys arglist rest cont)
+    (split-list-at
+     #:allow-other-keys arglist
+     (lambda (aok-before aok-after aok-split?)
+       (if (and aok-split? (not (null? aok-after)))
+          (error "#:allow-other-keys not at end of keyword argument declarations.")
+          (split-list-at
+           #:key aok-before
+           (lambda (key-before key-after key-split?)
+             (cond
+              ((and aok-split? (not key-split?))
+               (error "#:allow-other-keys specified but no keyword arguments declared."))
+              (key-split?
+               (cond
+                ((null? key-after) (error "#:key specified but no keyword arguments declared."))
+                ((memq #:optional key-after) (error "#:optional arguments declared after #:key arguments."))
+                (else (parse-opt-and-fixed key-before key-after aok-split? rest cont))))
+              (else (parse-opt-and-fixed arglist '() #f rest cont)))))))))
+  (define (parse-rest arglist cont)
+    (cond
+     ((null? arglist) (cont '() '() '() #f #f))
+     ((not (pair? arglist)) (cont '() '() '() #f arglist))
+     ((not (list? arglist))
+         (let* ((copy (improper-list-copy arglist))
+                (lp (last-pair copy))
+                (ra (cdr lp)))
+           (set-cdr! lp '())
+           (if (memq #:rest copy)
+               (error "Cannot specify both #:rest and dotted rest argument.")
+               (parse-keys copy ra cont))))
+     (else (split-list-at
+           #:rest arglist
+           (lambda (before after split?)
+             (if split?
+                 (case (length after)
+                   ((0) (error "#:rest not followed by argument."))
+                   ((1) (parse-keys before (car after) cont))
+                   (else (error "#:rest argument must be declared last.")))
+                 (parse-keys before #f cont)))))))
+
+  (parse-rest arglist cont))
+
+
+
+;; define* args . body
+;; define*-public args . body
+;;   define and define-public extended for optional and keyword arguments
+;;
+;; define* and define*-public support optional arguments with
+;; a similar syntax to lambda*. They also support arbitrary-depth
+;; currying, just like Guile's define. Some examples:
+;;   (define* (x y #:optional a (z 3) #:key w . u) (display (list y z u)))
+;; defines a procedure x with a fixed argument y, an optional agument
+;; a, another optional argument z with default value 3, a keyword argument w,
+;; and a rest argument u.
+;;   (define-public* ((foo #:optional bar) #:optional baz) '())
+;; This illustrates currying. A procedure foo is defined, which,
+;; when called with an optional argument bar, returns a procedure that
+;; takes an optional argument baz.
+;;
+;; Of course, define*[-public] also supports #:rest and #:allow-other-keys
+;; in the same way as lambda*.
+
+(defmacro define* (ARGLIST . BODY)
+  (define*-guts 'define ARGLIST BODY))
+
+(defmacro define*-public (ARGLIST . BODY)
+  (define*-guts 'define-public ARGLIST BODY))
+
+;; The guts of define* and define*-public.
+(define (define*-guts DT ARGLIST BODY)
+  (define (nest-lambda*s arglists)
+    (if (null? arglists)
+        BODY
+        `((lambda* ,(car arglists) ,@(nest-lambda*s (cdr arglists))))))
+  (define (define*-guts-helper ARGLIST arglists)
+    (let ((first (car ARGLIST))
+         (al (cons (cdr ARGLIST) arglists)))
+      (if (symbol? first)
+         `(,DT ,first ,@(nest-lambda*s al))
+         (define*-guts-helper first al))))
+  (if (symbol? ARGLIST)
+      `(,DT ,ARGLIST ,@BODY)
+      (define*-guts-helper ARGLIST '())))
+
+
+
+;; defmacro* name args . body
+;; defmacro*-public args . body
+;;   defmacro and defmacro-public extended for optional and keyword arguments
+;;
+;; These are just like defmacro and defmacro-public except that they
+;; take lambda*-style extended paramter lists, where #:optional,
+;; #:key, #:allow-other-keys and #:rest are allowed with the usual
+;; semantics. Here is an example of a macro with an optional argument:
+;;   (defmacro* transmorgify (a #:optional b)
+
+(defmacro defmacro* (NAME ARGLIST . BODY)
+  `(define-macro ,NAME #f (lambda* ,ARGLIST ,@BODY)))
+
+(defmacro defmacro*-public (NAME ARGLIST . BODY)
+  `(begin
+     (defmacro* ,NAME ,ARGLIST ,@BODY)
+     (export-syntax ,NAME)))
+
+;;; Support for optional & keyword args with the interpreter.
+(define *uninitialized* (list 'uninitialized))
+(define (parse-lambda-case spec inits predicate args)
+  (pmatch spec
+    ((,nreq ,nopt ,rest-idx ,nargs ,allow-other-keys? ,kw-indices)
+     (define (req args prev tail n)
+       (cond
+        ((zero? n)
+         (if prev (set-cdr! prev '()))
+         (let ((slots-tail (make-list (- nargs nreq) *uninitialized*)))
+           (opt (if prev (append! args slots-tail) slots-tail)
+                slots-tail tail nopt inits)))
+        ((null? tail)
+         #f) ;; fail
+        (else
+         (req args tail (cdr tail) (1- n)))))
+     (define (opt slots slots-tail args-tail n inits)
+       (cond
+        ((zero? n)
+         (rest-or-key slots slots-tail args-tail inits rest-idx))
+        ((null? args-tail)
+         (set-car! slots-tail (apply (car inits) slots))
+         (opt slots (cdr slots-tail) '() (1- n) (cdr inits)))
+        (else
+         (set-car! slots-tail (car args-tail))
+         (opt slots (cdr slots-tail) (cdr args-tail) (1- n) (cdr inits)))))
+     (define (rest-or-key slots slots-tail args-tail inits rest-idx)
+       (cond
+        (rest-idx
+         ;; it has to be this way, vars are allocated in this order
+         (set-car! slots-tail args-tail)
+         (if (pair? kw-indices)
+             (key slots (cdr slots-tail) args-tail inits)
+             (rest-or-key slots (cdr slots-tail) '() inits #f)))
+        ((pair? kw-indices)
+         ;; fail early here, because once we're in keyword land we throw
+         ;; errors instead of failing
+         (and (or (null? args-tail) rest-idx (keyword? (car args-tail)))
+              (key slots slots-tail args-tail inits)))
+        ((pair? args-tail)
+         #f) ;; fail
+        (else
+         (pred slots))))
+     (define (key slots slots-tail args-tail inits)
+       (cond
+        ((null? args-tail)
+         (if (null? inits)
+             (pred slots)
+             (begin
+               (if (eq? (car slots-tail) *uninitialized*)
+                   (set-car! slots-tail (apply (car inits) slots)))
+               (key slots (cdr slots-tail) '() (cdr inits)))))
+        ((not (keyword? (car args-tail)))
+         (if rest-idx
+             ;; no error checking, everything goes to the rest..
+             (key slots slots-tail '() inits)
+             (error "bad keyword argument list" args-tail)))
+        ((and (keyword? (car args-tail))
+              (pair? (cdr args-tail))
+              (assq-ref kw-indices (car args-tail)))
+         => (lambda (i)
+              (list-set! slots i (cadr args-tail))
+              (key slots slots-tail (cddr args-tail) inits)))
+        ((and (keyword? (car args-tail))
+              (pair? (cdr args-tail))
+              allow-other-keys?)
+         (key slots slots-tail (cddr args-tail) inits))
+        (else (error "unrecognized keyword" args-tail))))
+     (define (pred slots)
+       (cond
+        (predicate
+         (if (apply predicate slots)
+             slots
+             #f))
+        (else slots)))
+     (let ((args (list-copy args)))
+       (req args #f args nreq)))
+    (else (error "unexpected spec" spec))))
diff --git a/mes/module/mes/peg.mes b/mes/module/mes/peg.mes
new file mode 100644 (file)
index 0000000..83b39af
--- /dev/null
@@ -0,0 +1,41 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; peg.mes is loaded after syntax-case: psyntax.  It provides PEG
+;;; from Guile-2.1.
+
+;;; Code:
+
+(mes-use-module (mes let))
+(mes-use-module (mes scm))
+(mes-use-module (mes guile))
+(mes-use-module (mes pretty-print))
+(mes-use-module (mes psyntax))
+(mes-use-module (srfi srfi-13))
+;;(mes-use-module (srfi srfi-9-psyntax))
+;;(mes-use-module (srfi srfi-9))
+(mes-use-module (mes pmatch))
+(include-from-path "mes/peg/cache.scm")
+(include-from-path "mes/peg/codegen.scm")
+(include-from-path "mes/peg/string-peg.scm")
+(include-from-path "mes/peg/using-parsers.scm")
+(include-from-path "mes/peg/simplify-tree.scm")
diff --git a/mes/module/mes/peg/cache.scm b/mes/module/mes/peg/cache.scm
new file mode 100644 (file)
index 0000000..c6e52db
--- /dev/null
@@ -0,0 +1,47 @@
+;;; -*-scheme-*-
+
+;;;; cache.scm --- cache the results of parsing
+;;;;
+;;;;   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 peg cache)
+  #:export (cg-cached-parser))
+
+;; The results of parsing using a nonterminal are cached.  Think of it like a
+;; hash with no conflict resolution.  Process for deciding on the cache size
+;; wasn't very scientific; just ran the benchmarks and stopped a little after
+;; the point of diminishing returns on my box.
+(define *cache-size* 512)
+
+(define (make-cache)
+  (make-vector *cache-size* #f))
+
+;; given a syntax object which is a parser function, returns syntax
+;; which, if evaluated, will become a parser function that uses a cache.
+(define (cg-cached-parser parser)
+  #`(let ((cache (make-cache)))
+      (lambda (str strlen at)
+        (let* ((vref (vector-ref cache (modulo at *cache-size*))))
+          ;; Check to see whether the value is cached.
+          (if (and vref (eq? (car vref) str) (= (cadr vref) at))
+              (caddr vref);; If it is return it.
+              (let ((fres ;; Else calculate it and cache it.
+                     (#,parser str strlen at)))
+                (vector-set! cache (modulo at *cache-size*)
+                             (list str at fres))
+                fres))))))
diff --git a/mes/module/mes/peg/codegen.scm b/mes/module/mes/peg/codegen.scm
new file mode 100644 (file)
index 0000000..701c5a8
--- /dev/null
@@ -0,0 +1,358 @@
+;;;; codegen.scm --- code generation for composable parsers
+;;;;
+;;;;   Copyright (C) 2011 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 peg codegen)
+  #:export (compile-peg-pattern wrap-parser-for-users add-peg-compiler!)
+  #:use-module (ice-9 pretty-print)
+  #:use-module (system base pmatch))
+
+(define-syntax single?
+  (syntax-rules ()
+    ;;"Return #t if X is a list of one element."
+    ((_ x)
+     (pmatch x
+       ((_) #t)
+       (else #f)))))
+
+(define-syntax single-filter
+  (syntax-rules ()
+    ;;"If EXP is a list of one element, return the element.  Otherwise return EXP."
+    ((_ exp)
+     (pmatch exp
+       ((,elt) elt)
+       (,elts elts)))))
+
+(define-syntax push-not-null!
+  (syntax-rules ()
+    ;;"If OBJ is non-null, push it onto LST, otherwise do nothing."
+    ((_ lst obj)
+     (if (not (null? obj))
+         (push! lst obj)))))
+
+(define-syntax push!
+  (syntax-rules ()
+    ;;"Push an object onto a list."
+    ((_ lst obj)
+     (set! lst (cons obj lst)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;; CODE GENERATORS
+;; These functions generate scheme code for parsing PEGs.
+;; Conventions:
+;;   accum: (all name body none)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Code we generate will have a certain return structure depending on how we're
+;; accumulating (the ACCUM variable).
+(define (cg-generic-ret accum name body-uneval at)
+  ;; name, body-uneval and at are syntax
+  #`(let ((body #,body-uneval))
+     #,(cond
+        ((and (eq? accum 'all) name)
+         #`(list #,at
+                 (cond
+                  ((not (list? body)) (list '#,name body))
+                  ((null? body) '#,name)
+                  ((symbol? (car body)) (list '#,name body))
+                  (else (cons '#,name body)))))
+        ((eq? accum 'name)
+         #`(list #,at '#,name))
+        ((eq? accum 'body)
+         #`(list #,at
+                 (cond
+                  ((single? body) (car body))
+                  (else body))))
+        ((eq? accum 'none)
+         #`(list #,at '()))
+        (else
+         (begin
+           (pretty-print `(cg-generic-ret-error ,accum ,name ,body-uneval ,at))
+           (pretty-print "Defaulting to accum of none.\n")
+           #`(list #,at '()))))))
+
+;; The short name makes the formatting below much easier to read.
+(define cggr cg-generic-ret)
+
+;; Generates code that matches a particular string.
+;; E.g.: (cg-string syntax "abc" 'body)
+(define (cg-string pat accum)
+  (let ((plen (string-length pat)))
+    #`(lambda (str len pos)
+        (let ((end (+ pos #,plen)))
+          (and (<= end len)
+               (string= str #,pat pos end)
+               #,(case accum
+                   ((all) #`(list end (list 'cg-string #,pat)))
+                   ((name) #`(list end 'cg-string))
+                   ((body) #`(list end #,pat))
+                   ((none) #`(list end '()))
+                   (else (error "bad accum" accum))))))))
+
+;; Generates code for matching any character.
+;; E.g.: (cg-peg-any syntax 'body)
+(define (cg-peg-any accum)
+  #`(lambda (str len pos)
+      (and (< pos len)
+           #,(case accum
+               ((all) #`(list (1+ pos)
+                              (list 'cg-peg-any (substring str pos (1+ pos)))))
+               ((name) #`(list (1+ pos) 'cg-peg-any))
+               ((body) #`(list (1+ pos) (substring str pos (1+ pos))))
+               ((none) #`(list (1+ pos) '()))
+               (else (error "bad accum" accum))))))
+
+;; Generates code for matching a range of characters between start and end.
+;; E.g.: (cg-range syntax #\a #\z 'body)
+(define (cg-range pat accum)
+  (syntax-case pat ()
+    ((start end)
+     (if (not (and (char? (syntax->datum #'start))
+                   (char? (syntax->datum #'end))))
+         (error "range PEG should have characters after it; instead got"
+                #'start #'end))
+     #`(lambda (str len pos)
+         (and (< pos len)
+              (let ((c (string-ref str pos)))
+                (and (char>=? c start)
+                     (char<=? c end)
+                     #,(case accum
+                         ((all) #`(list (1+ pos) (list 'cg-range (string c))))
+                         ((name) #`(list (1+ pos) 'cg-range))
+                         ((body) #`(list (1+ pos) (string c)))
+                         ((none) #`(list (1+ pos) '()))
+                         (else (error "bad accum" accum))))))))))
+
+;; Generate code to match a pattern and do nothing with the result
+(define (cg-ignore pat accum)
+  (syntax-case pat ()
+    ((inner)
+     (compile-peg-pattern #'inner 'none))))
+
+(define (cg-capture pat accum)
+  (syntax-case pat ()
+    ((inner)
+     (compile-peg-pattern #'inner 'body))))
+
+;; Filters the accum argument to compile-peg-pattern for buildings like string
+;; literals (since we don't want to tag them with their name if we're doing an
+;; "all" accum).
+(define (builtin-accum-filter accum)
+  (cond
+   ((eq? accum 'all) 'body)
+   ((eq? accum 'name) 'name)
+   ((eq? accum 'body) 'body)
+   ((eq? accum 'none) 'none)))
+(define baf builtin-accum-filter)
+
+;; Top-level function builder for AND.  Reduces to a call to CG-AND-INT.
+(define (cg-and clauses accum)
+  #`(lambda (str len pos)
+      (let ((body '()))
+        #,(cg-and-int clauses (baf accum) #'str #'len #'pos #'body))))
+
+;; Internal function builder for AND (calls itself).
+(define (cg-and-int clauses accum str strlen at body)
+  (syntax-case clauses ()
+    (()
+     (cggr accum 'cg-and #`(reverse #,body) at))
+    ((first rest ...)
+     #`(let ((res (#,(compile-peg-pattern #'first accum) #,str #,strlen #,at)))
+         (and res 
+              ;; update AT and BODY then recurse
+              (let ((newat (car res))
+                    (newbody (cadr res)))
+                (set! #,at newat)
+                (push-not-null! #,body (single-filter newbody))
+                #,(cg-and-int #'(rest ...) accum str strlen at body)))))))
+
+;; Top-level function builder for OR.  Reduces to a call to CG-OR-INT.
+(define (cg-or clauses accum)
+  #`(lambda (str len pos)
+      #,(cg-or-int clauses (baf accum) #'str #'len #'pos)))
+
+;; Internal function builder for OR (calls itself).
+(define (cg-or-int clauses accum str strlen at)
+  (syntax-case clauses ()
+    (()
+     #f)
+    ((first rest ...)
+     #`(or (#,(compile-peg-pattern #'first accum) #,str #,strlen #,at)
+           #,(cg-or-int #'(rest ...) accum str strlen at)))))
+
+(define (cg-* args accum)
+  (syntax-case args ()
+    ((pat)
+     #`(lambda (str strlen at)
+         (let ((body '()))
+           (let lp ((end at) (count 0))
+             (let* ((match (#,(compile-peg-pattern #'pat (baf accum))
+                            str strlen end))
+                    (new-end (if match (car match) end))
+                    (count (if (> new-end end) (1+ count) count)))
+               (if (> new-end end)
+                   (push-not-null! body (single-filter (cadr match))))
+               (if (and (> new-end end)
+                        #,#t)
+                   (lp new-end count)
+                   (let ((success #,#t))
+                     #,#`(and success
+                                 #,(cggr (baf accum) 'cg-body
+                                         #'(reverse body) #'new-end)))))))))))
+
+(define (cg-+ args accum)
+  (syntax-case args ()
+    ((pat)
+     #`(lambda (str strlen at)
+         (let ((body '()))
+           (let lp ((end at) (count 0))
+             (let* ((match (#,(compile-peg-pattern #'pat (baf accum))
+                            str strlen end))
+                    (new-end (if match (car match) end))
+                    (count (if (> new-end end) (1+ count) count)))
+               (if (> new-end end)
+                   (push-not-null! body (single-filter (cadr match))))
+               (if (and (> new-end end)
+                        #,#t)
+                   (lp new-end count)
+                   (let ((success #,#'(>= count 1)))
+                     #,#`(and success
+                                 #,(cggr (baf accum) 'cg-body
+                                         #'(reverse body) #'new-end)))))))))))
+
+(define (cg-? args accum)
+  (syntax-case args ()
+    ((pat)
+     #`(lambda (str strlen at)
+         (let ((body '()))
+           (let lp ((end at) (count 0))
+             (let* ((match (#,(compile-peg-pattern #'pat (baf accum))
+                            str strlen end))
+                    (new-end (if match (car match) end))
+                    (count (if (> new-end end) (1+ count) count)))
+               (if (> new-end end)
+                   (push-not-null! body (single-filter (cadr match))))
+               (if (and (> new-end end)
+                        #,#'(< count 1))
+                   (lp new-end count)
+                   (let ((success #,#t))
+                     #,#`(and success
+                                 #,(cggr (baf accum) 'cg-body
+                                         #'(reverse body) #'new-end)))))))))))
+
+(define (cg-followed-by args accum)
+  (syntax-case args ()
+    ((pat)
+     #`(lambda (str strlen at)
+         (let ((body '()))
+           (let lp ((end at) (count 0))
+             (let* ((match (#,(compile-peg-pattern #'pat (baf accum))
+                            str strlen end))
+                    (new-end (if match (car match) end))
+                    (count (if (> new-end end) (1+ count) count)))
+               (if (> new-end end)
+                   (push-not-null! body (single-filter (cadr match))))
+               (if (and (> new-end end)
+                        #,#'(< count 1))
+                   (lp new-end count)
+                   (let ((success #,#'(= count 1)))
+                     #,#`(and success
+                              #,(cggr (baf accum) 'cg-body #''() #'at)))))))))))
+
+(define (cg-not-followed-by args accum)
+  (syntax-case args ()
+    ((pat)
+     #`(lambda (str strlen at)
+         (let ((body '()))
+           (let lp ((end at) (count 0))
+             (let* ((match (#,(compile-peg-pattern #'pat (baf accum))
+                            str strlen end))
+                    (new-end (if match (car match) end))
+                    (count (if (> new-end end) (1+ count) count)))
+               (if (> new-end end)
+                   (push-not-null! body (single-filter (cadr match))))
+               (if (and (> new-end end)
+                        #,#'(< count 1))
+                   (lp new-end count)
+                   (let ((success #,#'(= count 1)))
+                     #,#`(if success
+                                #f
+                                #,(cggr (baf accum) 'cg-body #''() #'at)))))))))))
+
+;; Association list of functions to handle different expressions as PEGs
+(define peg-compiler-alist '())
+
+(define (add-peg-compiler! symbol function)
+  (set! peg-compiler-alist
+        (assq-set! peg-compiler-alist symbol function)))
+
+(add-peg-compiler! 'range cg-range)
+(add-peg-compiler! 'ignore cg-ignore)
+(add-peg-compiler! 'capture cg-capture)
+(add-peg-compiler! 'and cg-and)
+(add-peg-compiler! 'or cg-or)
+(add-peg-compiler! '* cg-*)
+(add-peg-compiler! '+ cg-+)
+(add-peg-compiler! '? cg-?)
+(add-peg-compiler! 'followed-by cg-followed-by)
+(add-peg-compiler! 'not-followed-by cg-not-followed-by)
+
+;; Takes an arbitrary expressions and accumulation variable, then parses it.
+;; E.g.: (compile-peg-pattern syntax '(and "abc" (or "-" (range #\a #\z))) 'all)
+(define (compile-peg-pattern pat accum)
+  (syntax-case pat (peg-any)
+    (peg-any
+     (cg-peg-any (baf accum)))
+    (sym (identifier? #'sym) ;; nonterminal
+     #'sym)
+    (str (string? (syntax->datum #'str)) ;; literal string
+     (cg-string (syntax->datum #'str) (baf accum)))
+    ((name . args) (let* ((nm (syntax->datum #'name))
+                          (entry (assq-ref peg-compiler-alist nm)))
+                     (if entry
+                         (entry #'args accum)
+                         (error "Bad peg form" nm #'args
+                                "Not one of" (map car peg-compiler-alist)))))))
+
+;; Packages the results of a parser
+(define (wrap-parser-for-users for-syntax parser accumsym s-syn)
+   #`(lambda (str strlen at)
+      (let ((res (#,parser str strlen at)))
+        ;; Try to match the nonterminal.
+        (if res
+            ;; If we matched, do some post-processing to figure out
+            ;; what data to propagate upward.
+            (let ((at (car res))
+                  (body (cadr res)))
+              #,(cond
+                 ((eq? accumsym 'name)
+                  #`(list at '#,s-syn))
+                 ((eq? accumsym 'all)
+                  #`(list (car res)
+                          (cond
+                           ((not (list? body))
+                            (list '#,s-syn body))
+                           ((null? body) '#,s-syn)
+                           ((symbol? (car body))
+                            (list '#,s-syn body))
+                           (else (cons '#,s-syn body)))))
+                 ((eq? accumsym 'none) #`(list (car res) '()))
+                 (else #`(begin res))))
+            ;; If we didn't match, just return false.
+            #f))))
diff --git a/mes/module/mes/peg/simplify-tree.scm b/mes/module/mes/peg/simplify-tree.scm
new file mode 100644 (file)
index 0000000..82eb004
--- /dev/null
@@ -0,0 +1,97 @@
+;;;; simplify-tree.scm --- utility functions for the PEG parser
+;;;;
+;;;;   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 peg simplify-tree)
+  #:export (keyword-flatten context-flatten string-collapse)
+  #:use-module (system base pmatch))
+
+(define-syntax single?
+  (syntax-rules ()
+    ;;"Return #t if X is a list of one element."
+    ((_ x)
+     (pmatch x
+       ((_) #t)
+       (else #f)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;; POST-PROCESSING FUNCTIONS (TO CANONICALIZE MATCH TREES)
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Is everything in LST true?
+(define (andlst lst)
+  (or (null? lst)
+      (and (car lst) (andlst (cdr lst)))))
+
+;; Is LST a list of strings?
+(define (string-list? lst)
+  (and (list? lst) (not (null? lst))
+       (andlst (map string? lst))))
+
+;; Groups all strings that are next to each other in LST.  Used in
+;; STRING-COLLAPSE.
+(define (string-group lst)
+  (if (not (list? lst))
+      lst
+      (if (null? lst)
+          '()
+          (let ((next (string-group (cdr lst))))
+            (if (not (string? (car lst)))
+                (cons (car lst) next)
+                (if (and (not (null? next))
+                         (list? (car next))
+                         (string? (caar next)))
+                    (cons (cons (car lst) (car next)) (cdr next))
+                    (cons (list (car lst)) next)))))))
+
+
+;; Collapses all the string in LST.
+;; ("a" "b" (c d) "e" "f") -> ("ab" (c d) "ef")
+(define (string-collapse lst)
+  (if (list? lst)
+      (let ((res (map (lambda (x) (if (string-list? x)
+                                      (apply string-append x)
+                                      x))
+                      (string-group (map string-collapse lst)))))
+        (if (single? res) (car res) res))
+      lst))
+
+;; If LST is an atom, return (list LST), else return LST.
+(define (mklst lst)
+  (if (not (list? lst)) (list lst) lst))
+
+;; Takes a list and "flattens" it, using the predicate TST to know when to stop
+;; instead of terminating on atoms (see tutorial).
+(define (context-flatten tst lst)
+  (if (or (not (list? lst)) (null? lst))
+      lst
+      (if (tst lst)
+          (list lst)
+          (apply append
+                 (map (lambda (x) (mklst (context-flatten tst x)))
+                      lst)))))
+
+;; Takes a list and "flattens" it, using the list of keywords KEYWORD-LST to
+;; know when to stop at (see tutorial).
+(define (keyword-flatten keyword-lst lst)
+  (context-flatten
+   (lambda (x)
+     (if (or (not (list? x)) (null? x))
+         #t
+         (member (car x) keyword-lst)))
+   lst))
diff --git a/mes/module/mes/peg/string-peg.scm b/mes/module/mes/peg/string-peg.scm
new file mode 100644 (file)
index 0000000..45ed14b
--- /dev/null
@@ -0,0 +1,273 @@
+;;;; string-peg.scm --- representing PEG grammars as strings
+;;;;
+;;;;   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 peg string-peg)
+  #:export (peg-as-peg
+            define-peg-string-patterns
+            peg-grammar)
+  #:use-module (ice-9 peg using-parsers)
+  #:use-module (ice-9 peg codegen)
+  #:use-module (ice-9 peg simplify-tree))
+
+;; Gets the left-hand depth of a list.
+(define (depth lst)
+  (if (or (not (list? lst)) (null? lst))
+      0
+      (+ 1 (depth (car lst)))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;; Parse string PEGs using sexp PEGs.
+;; See the variable PEG-AS-PEG for an easier-to-read syntax.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Grammar for PEGs in PEG grammar.
+(define peg-as-peg
+"grammar <-- (nonterminal ('<--' / '<-' / '<') sp pattern)+
+pattern <-- alternative (SLASH sp alternative)*
+alternative <-- ([!&]? sp suffix)+
+suffix <-- primary ([*+?] sp)*
+primary <-- '(' sp pattern ')' sp / '.' sp / literal / charclass / nonterminal !'<'
+literal <-- ['] (!['] .)* ['] sp
+charclass <-- LB (!']' (CCrange / CCsingle))* RB sp
+CCrange <-- . '-' .
+CCsingle <-- .
+nonterminal <-- [a-zA-Z0-9-]+ sp
+sp < [ \t\n]*
+SLASH < '/'
+LB < '['
+RB < ']'
+")
+
+(define-syntax define-sexp-parser
+  (lambda (x)
+    (syntax-case x ()
+      ((_ sym accum pat)
+       (let* ((matchf (compile-peg-pattern #'pat (syntax->datum #'accum)))
+              (accumsym (syntax->datum #'accum))
+              (syn (wrap-parser-for-users x matchf accumsym #'sym)))
+           #`(define sym #,syn))))))
+
+(define-sexp-parser peg-grammar all
+  (+ (and peg-nonterminal (or "<--" "<-" "<") peg-sp peg-pattern)))
+(define-sexp-parser peg-pattern all
+  (and peg-alternative
+       (* (and (ignore "/") peg-sp peg-alternative))))
+(define-sexp-parser peg-alternative all
+  (+ (and (? (or "!" "&")) peg-sp peg-suffix)))
+(define-sexp-parser peg-suffix all
+  (and peg-primary (* (and (or "*" "+" "?") peg-sp))))
+(define-sexp-parser peg-primary all
+  (or (and "(" peg-sp peg-pattern ")" peg-sp)
+      (and "." peg-sp)
+      peg-literal
+      peg-charclass
+      (and peg-nonterminal (not-followed-by "<"))))
+(define-sexp-parser peg-literal all
+  (and "'" (* (and (not-followed-by "'") peg-any)) "'" peg-sp))
+(define-sexp-parser peg-charclass all
+  (and (ignore "[")
+       (* (and (not-followed-by "]")
+               (or charclass-range charclass-single)))
+       (ignore "]")
+       peg-sp))
+(define-sexp-parser charclass-range all (and peg-any "-" peg-any))
+(define-sexp-parser charclass-single all peg-any)
+(define-sexp-parser peg-nonterminal all
+  (and (+ (or (range #\a #\z) (range #\A #\Z) (range #\0 #\9) "-")) peg-sp))
+(define-sexp-parser peg-sp none
+  (* (or " " "\t" "\n")))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;; PARSE STRING PEGS
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Takes a string representing a PEG grammar and returns syntax that
+;; will define all of the nonterminals in the grammar with equivalent
+;; PEG s-expressions.
+(define (peg-parser str for-syntax)
+  (let ((parsed (match-pattern peg-grammar str)))
+    (if (not parsed)
+        (begin
+          ;; (display "Invalid PEG grammar!\n")
+          #f)
+        (let ((lst (peg:tree parsed)))
+          (cond
+           ((or (not (list? lst)) (null? lst))
+            lst)
+           ((eq? (car lst) 'peg-grammar)
+            #`(begin
+                #,@(map (lambda (x) (peg-nonterm->defn x for-syntax))
+                        (context-flatten (lambda (lst) (<= (depth lst) 2))
+                                         (cdr lst))))))))))
+
+;; Macro wrapper for PEG-PARSER.  Parses PEG grammars expressed as strings and
+;; defines all the appropriate nonterminals.
+(define-syntax define-peg-string-patterns
+  (lambda (x)
+    (syntax-case x ()
+      ((_ str)
+       (peg-parser (syntax->datum #'str) x)))))
+
+;; lst has format (nonterm grabber pattern), where
+;;   nonterm is a symbol (the name of the nonterminal),
+;;   grabber is a string (either "<", "<-" or "<--"), and
+;;   pattern is the parse of a PEG pattern expressed as as string.
+(define (peg-nonterm->defn lst for-syntax)
+  (let* ((nonterm (car lst))
+         (grabber (cadr lst))
+         (pattern (caddr lst))
+         (nonterm-name (datum->syntax for-syntax
+                                      (string->symbol (cadr nonterm)))))
+    #`(define-peg-pattern #,nonterm-name
+       #,(cond
+          ((string=? grabber "<--") (datum->syntax for-syntax 'all))
+          ((string=? grabber "<-") (datum->syntax for-syntax 'body))
+          (else (datum->syntax for-syntax 'none)))
+       #,(compressor (peg-pattern->defn pattern for-syntax) for-syntax))))
+
+;; lst has format ('peg-pattern ...).
+;; After the context-flatten, (cdr lst) has format
+;;   (('peg-alternative ...) ...), where the outer list is a collection
+;;   of elements from a '/' alternative.
+(define (peg-pattern->defn lst for-syntax)
+  #`(or #,@(map (lambda (x) (peg-alternative->defn x for-syntax))
+                (context-flatten (lambda (x) (eq? (car x) 'peg-alternative))
+                                 (cdr lst)))))
+
+;; lst has format ('peg-alternative ...).
+;; After the context-flatten, (cdr lst) has the format
+;;   (item ...), where each item has format either ("!" ...), ("&" ...),
+;;   or ('peg-suffix ...).
+(define (peg-alternative->defn lst for-syntax)
+  #`(and #,@(map (lambda (x) (peg-body->defn x for-syntax))
+                 (context-flatten (lambda (x) (or (string? (car x))
+                                             (eq? (car x) 'peg-suffix)))
+                                  (cdr lst)))))
+
+;; lst has the format either
+;;   ("!" ('peg-suffix ...)), ("&" ('peg-suffix ...)), or
+;;     ('peg-suffix ...).
+(define (peg-body->defn lst for-syntax)
+    (cond
+      ((equal? (car lst) "&")
+       #`(followed-by #,(peg-suffix->defn (cadr lst) for-syntax)))
+      ((equal? (car lst) "!")
+       #`(not-followed-by #,(peg-suffix->defn (cadr lst) for-syntax)))
+      ((eq? (car lst) 'peg-suffix)
+       (peg-suffix->defn lst for-syntax))
+      (else `(peg-parse-body-fail ,lst))))
+
+;; lst has format ('peg-suffix <peg-primary> (? (/ "*" "?" "+")))
+(define (peg-suffix->defn lst for-syntax)
+  (let ((inner-defn (peg-primary->defn (cadr lst) for-syntax)))
+    (cond
+      ((null? (cddr lst))
+       inner-defn)
+      ((equal? (caddr lst) "*")
+       #`(* #,inner-defn))
+      ((equal? (caddr lst) "?")
+       #`(? #,inner-defn))
+      ((equal? (caddr lst) "+")
+       #`(+ #,inner-defn)))))
+
+;; Parse a primary.
+(define (peg-primary->defn lst for-syntax)
+  (let ((el (cadr lst)))
+  (cond
+   ((list? el)
+    (cond
+     ((eq? (car el) 'peg-literal)
+      (peg-literal->defn el for-syntax))
+     ((eq? (car el) 'peg-charclass)
+      (peg-charclass->defn el for-syntax))
+     ((eq? (car el) 'peg-nonterminal)
+      (datum->syntax for-syntax (string->symbol (cadr el))))))
+   ((string? el)
+    (cond
+     ((equal? el "(")
+      (peg-pattern->defn (caddr lst) for-syntax))
+     ((equal? el ".")
+      (datum->syntax for-syntax 'peg-any))
+     (else (datum->syntax for-syntax
+                          `(peg-parse-any unknown-string ,lst)))))
+   (else (datum->syntax for-syntax
+                        `(peg-parse-any unknown-el ,lst))))))
+
+;; Trims characters off the front and end of STR.
+;; (trim-1chars "'ab'") -> "ab"
+(define (trim-1chars str) (substring str 1 (- (string-length str) 1)))
+
+;; Parses a literal.
+(define (peg-literal->defn lst for-syntax)
+  (datum->syntax for-syntax (trim-1chars (cadr lst))))
+
+;; Parses a charclass.
+(define (peg-charclass->defn lst for-syntax)
+  #`(or
+     #,@(map
+         (lambda (cc)
+           (cond
+            ((eq? (car cc) 'charclass-range)
+             #`(range #,(datum->syntax
+                         for-syntax
+                         (string-ref (cadr cc) 0))
+                      #,(datum->syntax
+                         for-syntax
+                         (string-ref (cadr cc) 2))))
+            ((eq? (car cc) 'charclass-single)
+             (datum->syntax for-syntax (cadr cc)))))
+         (context-flatten
+          (lambda (x) (or (eq? (car x) 'charclass-range)
+                          (eq? (car x) 'charclass-single)))
+          (cdr lst)))))
+
+;; Compresses a list to save the optimizer work.
+;; e.g. (or (and a)) -> a
+(define (compressor-core lst)
+  (if (or (not (list? lst)) (null? lst))
+      lst
+      (cond
+       ((and (or (eq? (car lst) 'or) (eq? (car lst) 'and))
+             (null? (cddr lst)))
+        (compressor-core (cadr lst)))
+       ((and (eq? (car lst) 'body)
+             (eq? (cadr lst) 'lit)
+             (eq? (cadddr lst) 1))
+        (compressor-core (caddr lst)))
+       (else (map compressor-core lst)))))
+
+(define (compressor syn for-syntax)
+  (datum->syntax for-syntax
+                 (compressor-core (syntax->datum syn))))
+
+;; Builds a lambda-expressions for the pattern STR using accum.
+(define (peg-string-compile args accum)
+  (syntax-case args ()
+    ((str-stx) (string? (syntax->datum #'str-stx))
+     (let ((string (syntax->datum #'str-stx)))
+       (compile-peg-pattern
+        (compressor
+         (peg-pattern->defn
+          (peg:tree (match-pattern peg-pattern string)) #'str-stx)
+         #'str-stx)
+        (if (eq? accum 'all) 'body accum))))
+     (else (error "Bad embedded PEG string" args))))
+
+(add-peg-compiler! 'peg peg-string-compile)
+
diff --git a/mes/module/mes/peg/using-parsers.scm b/mes/module/mes/peg/using-parsers.scm
new file mode 100644 (file)
index 0000000..d1a9382
--- /dev/null
@@ -0,0 +1,115 @@
+;;;; using-parsers.scm --- utilities to make using parsers easier
+;;;;
+;;;;   Copyright (C) 2010, 2011 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;; 
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;; 
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 peg using-parsers)
+  #:use-module (ice-9 peg simplify-tree)
+  #:use-module (ice-9 peg codegen)
+  #:use-module (ice-9 peg cache)
+  #:export (match-pattern define-peg-pattern search-for-pattern
+            prec make-prec peg:start peg:end peg:string
+            peg:tree peg:substring peg-record?))
+
+;;;
+;;; Helper Macros
+;;;
+
+(define-syntax until
+  (syntax-rules ()
+    ;;"Evaluate TEST.  If it is true, return its value.  Otherwise,execute the STMTs and try again."
+    ((_ test stmt stmt* ...)
+     (let lp ()
+       (or test
+           (begin stmt stmt* ... (lp)))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;; FOR DEFINING AND USING NONTERMINALS
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; Parses STRING using NONTERM
+(define (match-pattern nonterm string)
+  ;; We copy the string before using it because it might have been modified
+  ;; in-place since the last time it was parsed, which would invalidate the
+  ;; cache.  Guile uses copy-on-write for strings, so this is fast.
+  (let ((res (nonterm (string-copy string) (string-length string) 0)))
+    (if (not res)
+        #f
+        (make-prec 0 (car res) string (string-collapse (cadr res))))))
+
+;; Defines a new nonterminal symbol accumulating with ACCUM.
+(define-syntax define-peg-pattern
+  (lambda (x)
+    (syntax-case x ()
+      ((_ sym accum pat)
+       (let ((matchf (compile-peg-pattern #'pat (syntax->datum #'accum)))
+             (accumsym (syntax->datum #'accum)))
+         ;; CODE is the code to parse the string if the result isn't cached.
+         (let ((syn (wrap-parser-for-users x matchf accumsym #'sym)))
+           #`(define sym #,(cg-cached-parser syn))))))))
+
+(define (peg-like->peg pat)
+  (syntax-case pat ()
+    (str (string? (syntax->datum #'str)) #'(peg str))
+    (else pat)))
+
+;; Searches through STRING for something that parses to PEG-MATCHER.  Think
+;; regexp search.
+(define-syntax search-for-pattern
+  (lambda (x)
+    (syntax-case x ()
+      ((_ pattern string-uncopied)
+       (let ((pmsym (syntax->datum #'pattern)))
+         (let ((matcher (compile-peg-pattern (peg-like->peg #'pattern) 'body)))
+           ;; We copy the string before using it because it might have been
+           ;; modified in-place since the last time it was parsed, which would
+           ;; invalidate the cache.  Guile uses copy-on-write for strings, so
+           ;; this is fast.
+           #`(let ((string (string-copy string-uncopied))
+                   (strlen (string-length string-uncopied))
+                   (at 0))
+               (let ((ret (until (or (>= at strlen)
+                                     (#,matcher string strlen at))
+                                 (set! at (+ at 1)))))
+                 (if (eq? ret #t) ;; (>= at strlen) succeeded
+                     #f
+                     (let ((end (car ret))
+                           (match (cadr ret)))
+                       (make-prec
+                        at end string
+                        (string-collapse match))))))))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;; PMATCH STRUCTURE MUNGING
+;; Pretty self-explanatory.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(define prec
+  (make-record-type "peg" '(start end string tree)))
+(define make-prec
+  (record-constructor prec '(start end string tree)))
+(define (peg:start pm)
+  (if pm ((record-accessor prec 'start) pm) #f))
+(define (peg:end pm)
+  (if pm ((record-accessor prec 'end) pm) #f))
+(define (peg:string pm)
+  (if pm ((record-accessor prec 'string) pm) #f))
+(define (peg:tree pm)
+  (if pm ((record-accessor prec 'tree) pm) #f))
+(define (peg:substring pm)
+  (if pm (substring (peg:string pm) (peg:start pm) (peg:end pm)) #f))
+(define peg-record? (record-predicate prec))
diff --git a/mes/module/mes/pmatch.mes b/mes/module/mes/pmatch.mes
new file mode 100644 (file)
index 0000000..3f6fba4
--- /dev/null
@@ -0,0 +1,28 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+;;(mes-use-module (mes guile))
+(mes-use-module (mes quasiquote))
+(mes-use-module (mes syntax))
+(include-from-path "mes/pmatch.scm")
diff --git a/mes/module/mes/pmatch.scm b/mes/module/mes/pmatch.scm
new file mode 100644 (file)
index 0000000..1dfd0ff
--- /dev/null
@@ -0,0 +1,79 @@
+;;; pmatch, a simple matcher
+
+;;; Copyright (C) 2009, 2010, 2012 Free Software Foundation, Inc
+;;; Copyright (C) 2005,2006,2007 Oleg Kiselyov
+;;; Copyright (C) 2007 Daniel P. Friedman
+;;; Copyright (C) 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This library is free software; you can redistribute it and/or
+;;; modify it under the terms of the GNU Lesser General Public
+;;; License as published by the Free Software Foundation; either
+;;; version 3 of the License, or (at your option) any later version.
+;;;
+;;; This library is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;; Lesser General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU Lesser General Public
+;;; License along with this library; if not, write to the Free Software
+;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+;;; Originally written by Oleg Kiselyov for LeanTAP in Kanren, which is
+;;; available under the MIT license.
+;;;
+;;; http://kanren.cvs.sourceforge.net/viewvc/kanren/kanren/mini/leanTAP.scm?view=log
+;;;
+;;; This version taken from:
+;;; αKanren: A Fresh Name in Nominal Logic Programming
+;;; by William E. Byrd and Daniel P. Friedman
+;;; Proceedings of the 2007 Workshop on Scheme and Functional Programming
+;;; Université Laval Technical Report DIUL-RT-0701
+
+;;; To be clear: the original code is MIT-licensed, and the modifications
+;;; made to it by Guile are under Guile's license (currently LGPL v3+).
+
+;;; Code:
+
+;; (pmatch exp <clause> ...[<else-clause>])
+;; <clause> ::= (<pattern> <guard> exp ...)
+;; <else-clause> ::= (else exp ...)
+;; <guard> ::= boolean exp | ()
+;; <pattern> :: =
+;;        ,var  -- matches always and binds the var
+;;                 pattern must be linear! No check is done
+;;         _    -- matches always
+;;        'exp  -- comparison with exp (using equal?)    REMOVED (August 8, 2012)
+;;        exp   -- comparison with exp (using equal?)
+;;        (<pattern1> <pattern2> ...) -- matches the list of patterns
+;;        (<pattern1> . <pattern2>)  -- ditto
+;;        ()    -- matches the empty list
+
+(define-module (system base pmatch)
+  #:export-syntax (pmatch))
+
+(define-syntax pmatch
+  (syntax-rules (else guard)
+    ((_ v) (if #f #f))
+    ((_ v (else e0 e ...)) (let () e0 e ...))
+    ((_ v (pat (guard g ...) e0 e ...) cs ...)
+     (let ((fk (lambda () (pmatch v cs ...))))
+       (ppat v pat
+             (if (and g ...) (let () e0 e ...) (fk))
+             (fk))))
+    ((_ v (pat e0 e ...) cs ...)
+     (let ((fk (lambda () (pmatch v cs ...))))
+       (ppat v pat (let () e0 e ...) (fk))))))
+
+(define-syntax ppat
+  (syntax-rules (_ quote unquote)
+    ((_ v _ kt kf) kt)
+    ((_ v () kt kf) (if (null? v) kt kf))
+    ((_ v (quote lit) kt kf)
+     (if (equal? v (quote lit)) kt kf))
+    ((_ v (unquote var) kt kf) (let ((var v)) kt))
+    ((_ v (x . y) kt kf)
+     (if (pair? v)
+         (ppat (pmatch-car v) x (ppat (pmatch-cdr v) y kt kf) kf)
+         kf))
+    ((_ v lit kt kf) (if (eq? v (quote lit)) kt kf))))
diff --git a/mes/module/mes/posix.mes b/mes/module/mes/posix.mes
new file mode 100644 (file)
index 0000000..1cacf70
--- /dev/null
@@ -0,0 +1,59 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2017 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with Mes.  If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(mes-use-module (srfi srfi-13))
+
+(define R_OK 0)
+(define S_IRWXU #o700)
+
+(define (basename file-name . ext)
+  (let ((base (last (string-split file-name #\/)))
+        (ext (and (pair? ext) (car ext))))
+    (if (and ext
+             (string-suffix? ext base)) (string-drop-right base (string-length ext))
+             base)))
+
+(define (search-path path file-name)
+  (if (access? file-name R_OK) file-name
+      (let loop ((path path))
+        (and (pair? path)
+             (let ((f (string-append (car path) "/" file-name)))
+               (if (access? f R_OK) f
+                   (loop (cdr path))))))))
+
+(define (execlp file-name args)
+  (let ((executable (if (string-index file-name #\/) file-name
+                        (search-path (string-split (getenv "PATH") #\:) file-name))))
+    (execl executable args)))
+
+(define (system* file-name . args)
+  (let ((pid (primitive-fork)))
+    (cond ((zero? pid) (apply execlp file-name (list args)))
+          ((= -1 pid) (error "fork failed:" file-name))
+          (else (let ((pid+status (waitpid 0)))
+                  (cdr pid+status))))))
+
+(define (waitpid pid . options)
+  (let ((options (if (null? options) 0 (car options))))
+    (core:waitpid pid options)))
diff --git a/mes/module/mes/pretty-print.mes b/mes/module/mes/pretty-print.mes
new file mode 100644 (file)
index 0000000..617cd3d
--- /dev/null
@@ -0,0 +1,27 @@
+;;; -*-scheme-*-
+
+;;; Mes --- Maxwell Equations of Software
+;;; Copyright © 2016 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+;;;
+;;; This file is part of Mes.
+;;;
+;;; Mes is free software; you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 3 of the License, or (at
+;;; your option) any later version.
+;;;
+;;; Mes is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;;