* 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.
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
# 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
./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)
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
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=.
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
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
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
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;
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}
#! /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
(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))) "")))
set -x
fi
+MES_ARENA=100000000
+
export LIBC MES_LIBS
GUILE=${GUILE-$MES}
+++ /dev/null
-;;; -*-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)
+++ /dev/null
-../module/language
\ No newline at end of file
+++ /dev/null
-../module/mes
\ No newline at end of file
+++ /dev/null
-;;; -*-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)
+++ /dev/null
-;;; -*-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)))
- '()))
+++ /dev/null
-#! /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)
+++ /dev/null
-../module/mescc
\ No newline at end of file
+++ /dev/null
-;;; -*-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))
- )
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
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" \
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" \
-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," \
--- /dev/null
+../include
\ No newline at end of file
--- /dev/null
+../lib
\ No newline at end of file
--- /dev/null
+;;; -*-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))) )))))
--- /dev/null
+;;; -*-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))
--- /dev/null
+;;; 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)
--- /dev/null
+;;; 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)
--- /dev/null
+;;; -*-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)
--- /dev/null
+;;; -*-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
--- /dev/null
+;;; -*-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)
--- /dev/null
+;;; -*-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))
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;; -*-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)
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;;
+;;;; 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)))
--- /dev/null
+;;; -*-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))
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;; 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)))))
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;; -*-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))))
--- /dev/null
+;;; -*-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)))
--- /dev/null
+;;;; 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))))
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;; -*-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))))))
--- /dev/null
+;;;; 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))))
--- /dev/null
+;;;; 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))
--- /dev/null
+;;;; 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)
+
--- /dev/null
+;;;; 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))
--- /dev/null
+;;; -*-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")
--- /dev/null
+;;; 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))))
--- /dev/null
+;;; -*-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)))
--- /dev/null
+;;; -*-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
+;;;