mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-29 19:30:36 +02:00
These GPLv2+-licensed GC benchmarks are available from http://www.ccs.neu.edu/home/will/GC/sourcecode.html .
9319 lines
390 KiB
Scheme
9319 lines
390 KiB
Scheme
; Soft Scheme -- Copyright (C) 1993, 1994 Andrew K. Wright
|
|
;
|
|
; This program 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 2 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 General Public License for more details.
|
|
;
|
|
; You should have received a copy of the GNU General Public License
|
|
; along with this program; if not, write to the Free Software
|
|
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
;
|
|
; Packaged as a single file for Larceny by Lars T Hansen.
|
|
; Modified 2000-02-15 by lth.
|
|
;
|
|
; Compilation notes.
|
|
;
|
|
; The macro definitions for MATCH in this file depend on the presence of
|
|
; certain helper functions in the compilation environment, eg. match:andmap.
|
|
; (That is not a problem when loading this file, but it is an issue when
|
|
; compiling it.) The easiest way to provide the helper functions during
|
|
; compilation is to load match.sch into the compilation environment before
|
|
; compiling.
|
|
;
|
|
; Once compiled, this program is self-contained.
|
|
|
|
; The SoftScheme benchmark performs soft typing on a program and prints
|
|
; a diagnostic report. All screen output is captured in an output
|
|
; string port, which is subsequently discarded. (There is a moderate
|
|
; amount of output). No file I/O occurs while the program is running.
|
|
|
|
(define (softscheme-benchmark)
|
|
(let ((expr `(begin ,@(readfile "ss-input.scm")))
|
|
(out (open-output-string)))
|
|
(run-benchmark "softscheme"
|
|
(lambda ()
|
|
(with-output-to-port out
|
|
(lambda ()
|
|
(soft-def expr #f)))))
|
|
(newline)
|
|
(display (string-length (get-output-string out)))
|
|
(display " characters of output written.")
|
|
(newline)))
|
|
|
|
;;; Define defmacro, macro?, and macroexpand-1.
|
|
|
|
(define *macros* '())
|
|
|
|
(define-syntax
|
|
defmacro
|
|
(transformer
|
|
(lambda (exp rename compare)
|
|
(define (arglist? x)
|
|
(or (symbol? x)
|
|
(null? x)
|
|
(and (pair? x)
|
|
(symbol? (car x))
|
|
(arglist? (cdr x)))))
|
|
(if (not (and (list? exp)
|
|
(>= (length exp) 4)
|
|
(symbol? (cadr exp))
|
|
(arglist? (caddr exp))))
|
|
(error "Bad macro definition: " exp))
|
|
(let ((name (cadr exp))
|
|
(args (caddr exp))
|
|
(body (cdddr exp)))
|
|
`(begin
|
|
(define-syntax
|
|
,name
|
|
(transformer
|
|
(lambda (_defmacro_exp
|
|
_defmacro_rename
|
|
_defmacro_compare)
|
|
(apply (lambda ,args ,@body) (cdr _defmacro_exp)))))
|
|
(set! *macros*
|
|
(cons (cons ',name
|
|
(lambda (_exp)
|
|
(apply (lambda ,args ,@body) (cdr _exp))))
|
|
*macros*))
|
|
)))))
|
|
|
|
(define (macroexpand-1 exp)
|
|
(cond ((pair? exp)
|
|
(let ((probe (assq (car exp) *macros*)))
|
|
(if probe ((cdr probe) exp) exp)))
|
|
(else exp)))
|
|
|
|
(define (macro? keyword)
|
|
(and (symbol? keyword) (assq keyword *macros*)))
|
|
|
|
;;; Other compatibility hacks
|
|
|
|
(define slib:error error)
|
|
|
|
(define force-output flush-output-port)
|
|
|
|
(define format
|
|
(let ((format format))
|
|
(lambda (port . rest)
|
|
(if (not port)
|
|
(let ((s (open-output-string)))
|
|
(apply format s rest)
|
|
(get-output-string s))
|
|
(apply format port rest)))))
|
|
|
|
(define gentemp
|
|
(let ((gensym gensym)) (lambda () (gensym "G"))))
|
|
|
|
(define getenv
|
|
(let ((getenv getenv))
|
|
(lambda (x)
|
|
(or (getenv x)
|
|
(if (string=? x "HOME")
|
|
"Ertevann:Desktop folder:"
|
|
#f)))))
|
|
|
|
;;; The rest of the file should be more or less portable.
|
|
|
|
(define match-file #f)
|
|
(define installation-directory #f)
|
|
(define customization-file #f)
|
|
(define fastlibrary-file #f)
|
|
(define st:version
|
|
"Larceny Version 0.18, April 21, 1995")
|
|
(define match:version
|
|
"Version 1.18, July 17, 1995")
|
|
(define match:error
|
|
(lambda (val . args)
|
|
(for-each pretty-print args)
|
|
(slib:error "no matching clause for " val)))
|
|
(define match:andmap
|
|
(lambda (f l)
|
|
(if (null? l)
|
|
(and)
|
|
(and (f (car l)) (match:andmap f (cdr l))))))
|
|
(define match:syntax-err
|
|
(lambda (obj msg) (slib:error msg obj)))
|
|
(define match:disjoint-structure-tags '())
|
|
(define match:make-structure-tag
|
|
(lambda (name)
|
|
(if (or (eq? match:structure-control 'disjoint)
|
|
match:runtime-structures)
|
|
(let ((tag (gentemp)))
|
|
(set! match:disjoint-structure-tags
|
|
(cons tag match:disjoint-structure-tags))
|
|
tag)
|
|
(string->symbol
|
|
(string-append "<" (symbol->string name) ">")))))
|
|
(define match:structure?
|
|
(lambda (tag)
|
|
(memq tag match:disjoint-structure-tags)))
|
|
(define match:structure-control 'vector)
|
|
(define match:set-structure-control
|
|
(lambda (v) (set! match:structure-control v)))
|
|
(define match:set-error
|
|
(lambda (v) (set! match:error v)))
|
|
(define match:error-control 'error)
|
|
(define match:set-error-control
|
|
(lambda (v) (set! match:error-control v)))
|
|
(define match:disjoint-predicates
|
|
(cons 'null
|
|
'(pair? symbol?
|
|
boolean?
|
|
number?
|
|
string?
|
|
char?
|
|
procedure?
|
|
vector?)))
|
|
(define match:vector-structures '())
|
|
(define match:expanders
|
|
(letrec ((genmatch
|
|
(lambda (x clauses match-expr)
|
|
(let* ((length>= (gentemp))
|
|
(eb-errf (error-maker match-expr))
|
|
(blist (car eb-errf))
|
|
(plist (map (lambda (c)
|
|
(let* ((x (bound (validate-pattern
|
|
(car c))))
|
|
(p (car x))
|
|
(bv (cadr x))
|
|
(bindings (caddr x))
|
|
(code (gentemp))
|
|
(fail (and (pair? (cdr c))
|
|
(pair? (cadr c))
|
|
(eq? (caadr c) '=>)
|
|
(symbol? (cadadr c))
|
|
(pair? (cdadr c))
|
|
(null? (cddadr c))
|
|
(pair? (cddr c))
|
|
(cadadr c)))
|
|
(bv2 (if fail (cons fail bv) bv))
|
|
(body (if fail (cddr c) (cdr c))))
|
|
(set! blist
|
|
(cons `(,code (lambda ,bv2 ,@body))
|
|
(append bindings blist)))
|
|
(list p
|
|
code
|
|
bv
|
|
(and fail (gentemp))
|
|
#f)))
|
|
clauses))
|
|
(code (gen x
|
|
'()
|
|
plist
|
|
(cdr eb-errf)
|
|
length>=
|
|
(gentemp))))
|
|
(unreachable plist match-expr)
|
|
(inline-let
|
|
`(let ((,length>=
|
|
(lambda (n) (lambda (l) (>= (length l) n))))
|
|
,@blist)
|
|
,code)))))
|
|
(genletrec
|
|
(lambda (pat exp body match-expr)
|
|
(let* ((length>= (gentemp))
|
|
(eb-errf (error-maker match-expr))
|
|
(x (bound (validate-pattern pat)))
|
|
(p (car x))
|
|
(bv (cadr x))
|
|
(bindings (caddr x))
|
|
(code (gentemp))
|
|
(plist (list (list p code bv #f #f)))
|
|
(x (gentemp))
|
|
(m (gen x
|
|
'()
|
|
plist
|
|
(cdr eb-errf)
|
|
length>=
|
|
(gentemp)))
|
|
(gs (map (lambda (_) (gentemp)) bv)))
|
|
(unreachable plist match-expr)
|
|
`(letrec ((,length>=
|
|
(lambda (n) (lambda (l) (>= (length l) n))))
|
|
,@(map (lambda (v) `(,v #f)) bv)
|
|
(,x ,exp)
|
|
(,code
|
|
(lambda ,gs
|
|
,@(map (lambda (v g) `(set! ,v ,g)) bv gs)
|
|
,@body))
|
|
,@bindings
|
|
,@(car eb-errf))
|
|
,m))))
|
|
(gendefine
|
|
(lambda (pat exp match-expr)
|
|
(let* ((length>= (gentemp))
|
|
(eb-errf (error-maker match-expr))
|
|
(x (bound (validate-pattern pat)))
|
|
(p (car x))
|
|
(bv (cadr x))
|
|
(bindings (caddr x))
|
|
(code (gentemp))
|
|
(plist (list (list p code bv #f #f)))
|
|
(x (gentemp))
|
|
(m (gen x
|
|
'()
|
|
plist
|
|
(cdr eb-errf)
|
|
length>=
|
|
(gentemp)))
|
|
(gs (map (lambda (_) (gentemp)) bv)))
|
|
(unreachable plist match-expr)
|
|
`(begin
|
|
,@(map (lambda (v) `(define ,v #f)) bv)
|
|
,(inline-let
|
|
`(let ((,length>=
|
|
(lambda (n) (lambda (l) (>= (length l) n))))
|
|
(,x ,exp)
|
|
(,code
|
|
(lambda ,gs
|
|
,@(map (lambda (v g) `(set! ,v ,g)) bv gs)
|
|
(cond (#f #f))))
|
|
,@bindings
|
|
,@(car eb-errf))
|
|
,m))))))
|
|
(pattern-var?
|
|
(lambda (x)
|
|
(and (symbol? x)
|
|
(not (dot-dot-k? x))
|
|
(not (memq x
|
|
'(quasiquote
|
|
quote
|
|
unquote
|
|
unquote-splicing
|
|
?
|
|
_
|
|
$
|
|
=
|
|
and
|
|
or
|
|
not
|
|
set!
|
|
get!
|
|
...
|
|
___))))))
|
|
(dot-dot-k?
|
|
(lambda (s)
|
|
(and (symbol? s)
|
|
(if (memq s '(... ___))
|
|
0
|
|
(let* ((s (symbol->string s)) (n (string-length s)))
|
|
(and (<= 3 n)
|
|
(memq (string-ref s 0) '(#\. #\_))
|
|
(memq (string-ref s 1) '(#\. #\_))
|
|
(match:andmap
|
|
char-numeric?
|
|
(string->list (substring s 2 n)))
|
|
(string->number (substring s 2 n))))))))
|
|
(error-maker
|
|
(lambda (match-expr)
|
|
(cond ((eq? match:error-control 'unspecified)
|
|
(cons '() (lambda (x) `(cond (#f #f)))))
|
|
((memq match:error-control '(error fail))
|
|
(cons '() (lambda (x) `(match:error ,x))))
|
|
((eq? match:error-control 'match)
|
|
(let ((errf (gentemp)) (arg (gentemp)))
|
|
(cons `((,errf
|
|
(lambda (,arg)
|
|
(match:error ,arg ',match-expr))))
|
|
(lambda (x) `(,errf ,x)))))
|
|
(else
|
|
(match:syntax-err
|
|
'(unspecified error fail match)
|
|
"invalid value for match:error-control, legal values are")))))
|
|
(unreachable
|
|
(lambda (plist match-expr)
|
|
(for-each
|
|
(lambda (x)
|
|
(if (not (car (cddddr x)))
|
|
(begin
|
|
(display "Warning: unreachable pattern ")
|
|
(display (car x))
|
|
(display " in ")
|
|
(display match-expr)
|
|
(newline))))
|
|
plist)))
|
|
(validate-pattern
|
|
(lambda (pattern)
|
|
(letrec ((simple?
|
|
(lambda (x)
|
|
(or (string? x)
|
|
(boolean? x)
|
|
(char? x)
|
|
(number? x)
|
|
(null? x))))
|
|
(ordinary
|
|
(lambda (p)
|
|
(let ((g88 (lambda (x y)
|
|
(cons (ordinary x) (ordinary y)))))
|
|
(if (simple? p)
|
|
((lambda (p) p) p)
|
|
(if (equal? p '_)
|
|
((lambda () '_))
|
|
(if (pattern-var? p)
|
|
((lambda (p) p) p)
|
|
(if (pair? p)
|
|
(if (equal? (car p) 'quasiquote)
|
|
(if (and (pair? (cdr p))
|
|
(null? (cddr p)))
|
|
((lambda (p) (quasi p)) (cadr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) 'quote)
|
|
(if (and (pair? (cdr p))
|
|
(null? (cddr p)))
|
|
((lambda (p) p) p)
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) '?)
|
|
(if (and (pair? (cdr p))
|
|
(list? (cddr p)))
|
|
((lambda (pred ps)
|
|
`(? ,pred
|
|
,@(map ordinary ps)))
|
|
(cadr p)
|
|
(cddr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) '=)
|
|
(if (and (pair? (cdr p))
|
|
(pair? (cddr p))
|
|
(null? (cdddr p)))
|
|
((lambda (sel p)
|
|
`(= ,sel ,(ordinary p)))
|
|
(cadr p)
|
|
(caddr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) 'and)
|
|
(if (and (list? (cdr p))
|
|
(pair? (cdr p)))
|
|
((lambda (ps)
|
|
`(and ,@(map ordinary
|
|
ps)))
|
|
(cdr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) 'or)
|
|
(if (and (list? (cdr p))
|
|
(pair? (cdr p)))
|
|
((lambda (ps)
|
|
`(or ,@(map ordinary
|
|
ps)))
|
|
(cdr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) 'not)
|
|
(if (and (list? (cdr p))
|
|
(pair? (cdr p)))
|
|
((lambda (ps)
|
|
`(not ,@(map ordinary
|
|
ps)))
|
|
(cdr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal? (car p) '$)
|
|
(if (and (pair? (cdr p))
|
|
(symbol?
|
|
(cadr p))
|
|
(list? (cddr p)))
|
|
((lambda (r ps)
|
|
`($ ,r
|
|
,@(map ordinary
|
|
ps)))
|
|
(cadr p)
|
|
(cddr p))
|
|
(g88 (car p) (cdr p)))
|
|
(if (equal?
|
|
(car p)
|
|
'set!)
|
|
(if (and (pair? (cdr p))
|
|
(pattern-var?
|
|
(cadr p))
|
|
(null? (cddr p)))
|
|
((lambda (p) p) p)
|
|
(g88 (car p)
|
|
(cdr p)))
|
|
(if (equal?
|
|
(car p)
|
|
'get!)
|
|
(if (and (pair? (cdr p))
|
|
(pattern-var?
|
|
(cadr p))
|
|
(null? (cddr p)))
|
|
((lambda (p) p) p)
|
|
(g88 (car p)
|
|
(cdr p)))
|
|
(if (equal?
|
|
(car p)
|
|
'unquote)
|
|
(g88 (car p)
|
|
(cdr p))
|
|
(if (equal?
|
|
(car p)
|
|
'unquote-splicing)
|
|
(g88 (car p)
|
|
(cdr p))
|
|
(if (and (pair? (cdr p))
|
|
(dot-dot-k?
|
|
(cadr p))
|
|
(null? (cddr p)))
|
|
((lambda (p
|
|
ddk)
|
|
`(,(ordinary
|
|
p)
|
|
,ddk))
|
|
(car p)
|
|
(cadr p))
|
|
(g88 (car p)
|
|
(cdr p)))))))))))))))
|
|
(if (vector? p)
|
|
((lambda (p)
|
|
(let* ((pl (vector->list p))
|
|
(rpl (reverse pl)))
|
|
(apply vector
|
|
(if (and (not (null? rpl))
|
|
(dot-dot-k?
|
|
(car rpl)))
|
|
(reverse
|
|
(cons (car rpl)
|
|
(map ordinary
|
|
(cdr rpl))))
|
|
(map ordinary pl)))))
|
|
p)
|
|
((lambda ()
|
|
(match:syntax-err
|
|
pattern
|
|
"syntax error in pattern")))))))))))
|
|
(quasi (lambda (p)
|
|
(let ((g109 (lambda (x y)
|
|
(cons (quasi x) (quasi y)))))
|
|
(if (simple? p)
|
|
((lambda (p) p) p)
|
|
(if (symbol? p)
|
|
((lambda (p) `',p) p)
|
|
(if (pair? p)
|
|
(if (equal? (car p) 'unquote)
|
|
(if (and (pair? (cdr p))
|
|
(null? (cddr p)))
|
|
((lambda (p) (ordinary p))
|
|
(cadr p))
|
|
(g109 (car p) (cdr p)))
|
|
(if (and (pair? (car p))
|
|
(equal?
|
|
(caar p)
|
|
'unquote-splicing)
|
|
(pair? (cdar p))
|
|
(null? (cddar p)))
|
|
(if (null? (cdr p))
|
|
((lambda (p) (ordinary p))
|
|
(cadar p))
|
|
((lambda (p y)
|
|
(append
|
|
(ordlist p)
|
|
(quasi y)))
|
|
(cadar p)
|
|
(cdr p)))
|
|
(if (and (pair? (cdr p))
|
|
(dot-dot-k? (cadr p))
|
|
(null? (cddr p)))
|
|
((lambda (p ddk)
|
|
`(,(quasi p) ,ddk))
|
|
(car p)
|
|
(cadr p))
|
|
(g109 (car p) (cdr p)))))
|
|
(if (vector? p)
|
|
((lambda (p)
|
|
(let* ((pl (vector->list p))
|
|
(rpl (reverse pl)))
|
|
(apply vector
|
|
(if (dot-dot-k?
|
|
(car rpl))
|
|
(reverse
|
|
(cons (car rpl)
|
|
(map quasi
|
|
(cdr rpl))))
|
|
(map ordinary pl)))))
|
|
p)
|
|
((lambda ()
|
|
(match:syntax-err
|
|
pattern
|
|
"syntax error in pattern"))))))))))
|
|
(ordlist
|
|
(lambda (p)
|
|
(cond ((null? p) '())
|
|
((pair? p)
|
|
(cons (ordinary (car p)) (ordlist (cdr p))))
|
|
(else
|
|
(match:syntax-err
|
|
pattern
|
|
"invalid use of unquote-splicing in pattern"))))))
|
|
(ordinary pattern))))
|
|
(bound (lambda (pattern)
|
|
(letrec ((pred-bodies '())
|
|
(bound (lambda (p a k)
|
|
(cond ((eq? '_ p) (k p a))
|
|
((symbol? p)
|
|
(if (memq p a)
|
|
(match:syntax-err
|
|
pattern
|
|
"duplicate variable in pattern"))
|
|
(k p (cons p a)))
|
|
((and (pair? p)
|
|
(eq? 'quote (car p)))
|
|
(k p a))
|
|
((and (pair? p) (eq? '? (car p)))
|
|
(cond ((not (null? (cddr p)))
|
|
(bound `(and (? ,(cadr p))
|
|
,@(cddr p))
|
|
a
|
|
k))
|
|
((or (not (symbol?
|
|
(cadr p)))
|
|
(memq (cadr p) a))
|
|
(let ((g (gentemp)))
|
|
(set! pred-bodies
|
|
(cons `(,g ,(cadr p))
|
|
pred-bodies))
|
|
(k `(? ,g) a)))
|
|
(else (k p a))))
|
|
((and (pair? p) (eq? '= (car p)))
|
|
(cond ((or (not (symbol?
|
|
(cadr p)))
|
|
(memq (cadr p) a))
|
|
(let ((g (gentemp)))
|
|
(set! pred-bodies
|
|
(cons `(,g ,(cadr p))
|
|
pred-bodies))
|
|
(bound `(= ,g ,(caddr p))
|
|
a
|
|
k)))
|
|
(else
|
|
(bound (caddr p)
|
|
a
|
|
(lambda (p2 a)
|
|
(k `(= ,(cadr p)
|
|
,p2)
|
|
a))))))
|
|
((and (pair? p) (eq? 'and (car p)))
|
|
(bound*
|
|
(cdr p)
|
|
a
|
|
(lambda (p a)
|
|
(k `(and ,@p) a))))
|
|
((and (pair? p) (eq? 'or (car p)))
|
|
(bound (cadr p)
|
|
a
|
|
(lambda (first-p first-a)
|
|
(let or* ((plist (cddr p))
|
|
(k (lambda (plist)
|
|
(k `(or ,first-p
|
|
,@plist)
|
|
first-a))))
|
|
(if (null? plist)
|
|
(k plist)
|
|
(bound (car plist)
|
|
a
|
|
(lambda (car-p
|
|
car-a)
|
|
(if (not (permutation
|
|
car-a
|
|
first-a))
|
|
(match:syntax-err
|
|
pattern
|
|
"variables of or-pattern differ in"))
|
|
(or* (cdr plist)
|
|
(lambda (cdr-p)
|
|
(k (cons car-p
|
|
cdr-p)))))))))))
|
|
((and (pair? p) (eq? 'not (car p)))
|
|
(cond ((not (null? (cddr p)))
|
|
(bound `(not (or ,@(cdr p)))
|
|
a
|
|
k))
|
|
(else
|
|
(bound (cadr p)
|
|
a
|
|
(lambda (p2 a2)
|
|
(if (not (permutation
|
|
a
|
|
a2))
|
|
(match:syntax-err
|
|
p
|
|
"no variables allowed in"))
|
|
(k `(not ,p2)
|
|
a))))))
|
|
((and (pair? p)
|
|
(pair? (cdr p))
|
|
(dot-dot-k? (cadr p)))
|
|
(bound (car p)
|
|
a
|
|
(lambda (q b)
|
|
(let ((bvars (find-prefix
|
|
b
|
|
a)))
|
|
(k `(,q
|
|
,(cadr p)
|
|
,bvars
|
|
,(gentemp)
|
|
,(gentemp)
|
|
,(map (lambda (_)
|
|
(gentemp))
|
|
bvars))
|
|
b)))))
|
|
((and (pair? p) (eq? '$ (car p)))
|
|
(bound*
|
|
(cddr p)
|
|
a
|
|
(lambda (p1 a)
|
|
(k `($ ,(cadr p) ,@p1) a))))
|
|
((and (pair? p)
|
|
(eq? 'set! (car p)))
|
|
(if (memq (cadr p) a)
|
|
(k p a)
|
|
(k p (cons (cadr p) a))))
|
|
((and (pair? p)
|
|
(eq? 'get! (car p)))
|
|
(if (memq (cadr p) a)
|
|
(k p a)
|
|
(k p (cons (cadr p) a))))
|
|
((pair? p)
|
|
(bound (car p)
|
|
a
|
|
(lambda (car-p a)
|
|
(bound (cdr p)
|
|
a
|
|
(lambda (cdr-p a)
|
|
(k (cons car-p
|
|
cdr-p)
|
|
a))))))
|
|
((vector? p)
|
|
(boundv
|
|
(vector->list p)
|
|
a
|
|
(lambda (pl a)
|
|
(k (list->vector pl) a))))
|
|
(else (k p a)))))
|
|
(boundv
|
|
(lambda (plist a k)
|
|
(let ((g115 (lambda () (k plist a))))
|
|
(if (pair? plist)
|
|
(if (and (pair? (cdr plist))
|
|
(dot-dot-k? (cadr plist))
|
|
(null? (cddr plist)))
|
|
((lambda () (bound plist a k)))
|
|
(if (null? plist)
|
|
(g115)
|
|
((lambda (x y)
|
|
(bound x
|
|
a
|
|
(lambda (car-p a)
|
|
(boundv
|
|
y
|
|
a
|
|
(lambda (cdr-p a)
|
|
(k (cons car-p cdr-p)
|
|
a))))))
|
|
(car plist)
|
|
(cdr plist))))
|
|
(if (null? plist)
|
|
(g115)
|
|
(match:error plist))))))
|
|
(bound*
|
|
(lambda (plist a k)
|
|
(if (null? plist)
|
|
(k plist a)
|
|
(bound (car plist)
|
|
a
|
|
(lambda (car-p a)
|
|
(bound*
|
|
(cdr plist)
|
|
a
|
|
(lambda (cdr-p a)
|
|
(k (cons car-p cdr-p) a))))))))
|
|
(find-prefix
|
|
(lambda (b a)
|
|
(if (eq? b a)
|
|
'()
|
|
(cons (car b) (find-prefix (cdr b) a)))))
|
|
(permutation
|
|
(lambda (p1 p2)
|
|
(and (= (length p1) (length p2))
|
|
(match:andmap
|
|
(lambda (x1) (memq x1 p2))
|
|
p1)))))
|
|
(bound pattern
|
|
'()
|
|
(lambda (p a)
|
|
(list p (reverse a) pred-bodies))))))
|
|
(inline-let
|
|
(lambda (let-exp)
|
|
(letrec ((occ (lambda (x e)
|
|
(let loop ((e e))
|
|
(cond ((pair? e)
|
|
(+ (loop (car e)) (loop (cdr e))))
|
|
((eq? x e) 1)
|
|
(else 0)))))
|
|
(subst (lambda (e old new)
|
|
(let loop ((e e))
|
|
(cond ((pair? e)
|
|
(cons (loop (car e)) (loop (cdr e))))
|
|
((eq? old e) new)
|
|
(else e)))))
|
|
(const?
|
|
(lambda (sexp)
|
|
(or (symbol? sexp)
|
|
(boolean? sexp)
|
|
(string? sexp)
|
|
(char? sexp)
|
|
(number? sexp)
|
|
(null? sexp)
|
|
(and (pair? sexp)
|
|
(eq? (car sexp) 'quote)
|
|
(pair? (cdr sexp))
|
|
(symbol? (cadr sexp))
|
|
(null? (cddr sexp))))))
|
|
(isval?
|
|
(lambda (sexp)
|
|
(or (const? sexp)
|
|
(and (pair? sexp)
|
|
(memq (car sexp)
|
|
'(lambda quote
|
|
match-lambda
|
|
match-lambda*))))))
|
|
(small?
|
|
(lambda (sexp)
|
|
(or (const? sexp)
|
|
(and (pair? sexp)
|
|
(eq? (car sexp) 'lambda)
|
|
(pair? (cdr sexp))
|
|
(pair? (cddr sexp))
|
|
(const? (caddr sexp))
|
|
(null? (cdddr sexp)))))))
|
|
(let loop ((b (cadr let-exp))
|
|
(new-b '())
|
|
(e (caddr let-exp)))
|
|
(cond ((null? b)
|
|
(if (null? new-b) e `(let ,(reverse new-b) ,e)))
|
|
((isval? (cadr (car b)))
|
|
(let* ((x (caar b)) (n (occ x e)))
|
|
(cond ((= 0 n) (loop (cdr b) new-b e))
|
|
((or (= 1 n) (small? (cadr (car b))))
|
|
(loop (cdr b)
|
|
new-b
|
|
(subst e x (cadr (car b)))))
|
|
(else
|
|
(loop (cdr b) (cons (car b) new-b) e)))))
|
|
(else (loop (cdr b) (cons (car b) new-b) e)))))))
|
|
(gen (lambda (x sf plist erract length>= eta)
|
|
(if (null? plist)
|
|
(erract x)
|
|
(let* ((v '())
|
|
(val (lambda (x) (cdr (assq x v))))
|
|
(fail (lambda (sf)
|
|
(gen x sf (cdr plist) erract length>= eta)))
|
|
(success
|
|
(lambda (sf)
|
|
(set-car! (cddddr (car plist)) #t)
|
|
(let* ((code (cadr (car plist)))
|
|
(bv (caddr (car plist)))
|
|
(fail-sym (cadddr (car plist))))
|
|
(if fail-sym
|
|
(let ((ap `(,code
|
|
,fail-sym
|
|
,@(map val bv))))
|
|
`(call-with-current-continuation
|
|
(lambda (,fail-sym)
|
|
(let ((,fail-sym
|
|
(lambda ()
|
|
(,fail-sym ,(fail sf)))))
|
|
,ap))))
|
|
`(,code ,@(map val bv)))))))
|
|
(let next ((p (caar plist))
|
|
(e x)
|
|
(sf sf)
|
|
(kf fail)
|
|
(ks success))
|
|
(cond ((eq? '_ p) (ks sf))
|
|
((symbol? p)
|
|
(set! v (cons (cons p e) v))
|
|
(ks sf))
|
|
((null? p) (emit `(null? ,e) sf kf ks))
|
|
((equal? p ''()) (emit `(null? ,e) sf kf ks))
|
|
((string? p) (emit `(equal? ,e ,p) sf kf ks))
|
|
((boolean? p) (emit `(equal? ,e ,p) sf kf ks))
|
|
((char? p) (emit `(equal? ,e ,p) sf kf ks))
|
|
((number? p) (emit `(equal? ,e ,p) sf kf ks))
|
|
((and (pair? p) (eq? 'quote (car p)))
|
|
(emit `(equal? ,e ,p) sf kf ks))
|
|
((and (pair? p) (eq? '? (car p)))
|
|
(let ((tst `(,(cadr p) ,e)))
|
|
(emit tst sf kf ks)))
|
|
((and (pair? p) (eq? '= (car p)))
|
|
(next (caddr p) `(,(cadr p) ,e) sf kf ks))
|
|
((and (pair? p) (eq? 'and (car p)))
|
|
(let loop ((p (cdr p)) (sf sf))
|
|
(if (null? p)
|
|
(ks sf)
|
|
(next (car p)
|
|
e
|
|
sf
|
|
kf
|
|
(lambda (sf) (loop (cdr p) sf))))))
|
|
((and (pair? p) (eq? 'or (car p)))
|
|
(let ((or-v v))
|
|
(let loop ((p (cdr p)) (sf sf))
|
|
(if (null? p)
|
|
(kf sf)
|
|
(begin
|
|
(set! v or-v)
|
|
(next (car p)
|
|
e
|
|
sf
|
|
(lambda (sf) (loop (cdr p) sf))
|
|
ks))))))
|
|
((and (pair? p) (eq? 'not (car p)))
|
|
(next (cadr p) e sf ks kf))
|
|
((and (pair? p) (eq? '$ (car p)))
|
|
(let* ((tag (cadr p))
|
|
(fields (cdr p))
|
|
(rlen (length fields))
|
|
(tst `(,(symbol-append tag '?) ,e)))
|
|
(emit tst
|
|
sf
|
|
kf
|
|
(let rloop ((n 1))
|
|
(lambda (sf)
|
|
(if (= n rlen)
|
|
(ks sf)
|
|
(next (list-ref fields n)
|
|
`(,(symbol-append tag '- n)
|
|
,e)
|
|
sf
|
|
kf
|
|
(rloop (+ 1 n)))))))))
|
|
((and (pair? p) (eq? 'set! (car p)))
|
|
(set! v (cons (cons (cadr p) (setter e p)) v))
|
|
(ks sf))
|
|
((and (pair? p) (eq? 'get! (car p)))
|
|
(set! v (cons (cons (cadr p) (getter e p)) v))
|
|
(ks sf))
|
|
((and (pair? p)
|
|
(pair? (cdr p))
|
|
(dot-dot-k? (cadr p)))
|
|
(emit `(list? ,e)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
(let* ((k (dot-dot-k? (cadr p)))
|
|
(ks (lambda (sf)
|
|
(let ((bound (list-ref
|
|
p
|
|
2)))
|
|
(cond ((eq? (car p) '_)
|
|
(ks sf))
|
|
((null? bound)
|
|
(let* ((ptst (next (car p)
|
|
eta
|
|
sf
|
|
(lambda (sf)
|
|
#f)
|
|
(lambda (sf)
|
|
#t)))
|
|
(tst (if (and (pair? ptst)
|
|
(symbol?
|
|
(car ptst))
|
|
(pair? (cdr ptst))
|
|
(eq? eta
|
|
(cadr ptst))
|
|
(null? (cddr ptst)))
|
|
(car ptst)
|
|
`(lambda (,eta)
|
|
,ptst))))
|
|
(assm `(match:andmap
|
|
,tst
|
|
,e)
|
|
(kf sf)
|
|
(ks sf))))
|
|
((and (symbol?
|
|
(car p))
|
|
(equal?
|
|
(list (car p))
|
|
bound))
|
|
(next (car p)
|
|
e
|
|
sf
|
|
kf
|
|
ks))
|
|
(else
|
|
(let* ((gloop (list-ref
|
|
p
|
|
3))
|
|
(ge (list-ref
|
|
p
|
|
4))
|
|
(fresh (list-ref
|
|
p
|
|
5))
|
|
(p1 (next (car p)
|
|
`(car ,ge)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
`(,gloop
|
|
(cdr ,ge)
|
|
,@(map (lambda (b
|
|
f)
|
|
`(cons ,(val b)
|
|
,f))
|
|
bound
|
|
fresh))))))
|
|
(set! v
|
|
(append
|
|
(map cons
|
|
bound
|
|
(map (lambda (x)
|
|
`(reverse
|
|
,x))
|
|
fresh))
|
|
v))
|
|
`(let ,gloop
|
|
((,ge ,e)
|
|
,@(map (lambda (x)
|
|
`(,x
|
|
'()))
|
|
fresh))
|
|
(if (null? ,ge)
|
|
,(ks sf)
|
|
,p1)))))))))
|
|
(case k
|
|
((0) (ks sf))
|
|
((1) (emit `(pair? ,e) sf kf ks))
|
|
(else
|
|
(emit `((,length>= ,k) ,e)
|
|
sf
|
|
kf
|
|
ks)))))))
|
|
((pair? p)
|
|
(emit `(pair? ,e)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
(next (car p)
|
|
(add-a e)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
(next (cdr p)
|
|
(add-d e)
|
|
sf
|
|
kf
|
|
ks))))))
|
|
((and (vector? p)
|
|
(>= (vector-length p) 6)
|
|
(dot-dot-k?
|
|
(vector-ref p (- (vector-length p) 5))))
|
|
(let* ((vlen (- (vector-length p) 6))
|
|
(k (dot-dot-k?
|
|
(vector-ref p (+ vlen 1))))
|
|
(minlen (+ vlen k))
|
|
(bound (vector-ref p (+ vlen 2))))
|
|
(emit `(vector? ,e)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
(assm `(>= (vector-length ,e) ,minlen)
|
|
(kf sf)
|
|
((let vloop ((n 0))
|
|
(lambda (sf)
|
|
(cond ((not (= n vlen))
|
|
(next (vector-ref
|
|
p
|
|
n)
|
|
`(vector-ref
|
|
,e
|
|
,n)
|
|
sf
|
|
kf
|
|
(vloop (+ 1
|
|
n))))
|
|
((eq? (vector-ref
|
|
p
|
|
vlen)
|
|
'_)
|
|
(ks sf))
|
|
(else
|
|
(let* ((gloop (vector-ref
|
|
p
|
|
(+ vlen
|
|
3)))
|
|
(ind (vector-ref
|
|
p
|
|
(+ vlen
|
|
4)))
|
|
(fresh (vector-ref
|
|
p
|
|
(+ vlen
|
|
5)))
|
|
(p1 (next (vector-ref
|
|
p
|
|
vlen)
|
|
`(vector-ref
|
|
,e
|
|
,ind)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
`(,gloop
|
|
(- ,ind
|
|
1)
|
|
,@(map (lambda (b
|
|
f)
|
|
`(cons ,(val b)
|
|
,f))
|
|
bound
|
|
fresh))))))
|
|
(set! v
|
|
(append
|
|
(map cons
|
|
bound
|
|
fresh)
|
|
v))
|
|
`(let ,gloop
|
|
((,ind
|
|
(- (vector-length
|
|
,e)
|
|
1))
|
|
,@(map (lambda (x)
|
|
`(,x
|
|
'()))
|
|
fresh))
|
|
(if (> ,minlen
|
|
,ind)
|
|
,(ks sf)
|
|
,p1)))))))
|
|
sf))))))
|
|
((vector? p)
|
|
(let ((vlen (vector-length p)))
|
|
(emit `(vector? ,e)
|
|
sf
|
|
kf
|
|
(lambda (sf)
|
|
(emit `(equal?
|
|
(vector-length ,e)
|
|
,vlen)
|
|
sf
|
|
kf
|
|
(let vloop ((n 0))
|
|
(lambda (sf)
|
|
(if (= n vlen)
|
|
(ks sf)
|
|
(next (vector-ref p n)
|
|
`(vector-ref ,e ,n)
|
|
sf
|
|
kf
|
|
(vloop (+ 1
|
|
n)))))))))))
|
|
(else
|
|
(display "FATAL ERROR IN PATTERN MATCHER")
|
|
(newline)
|
|
(error #f "THIS NEVER HAPPENS"))))))))
|
|
(emit (lambda (tst sf kf ks)
|
|
(cond ((in tst sf) (ks sf))
|
|
((in `(not ,tst) sf) (kf sf))
|
|
(else
|
|
(let* ((e (cadr tst))
|
|
(implied
|
|
(cond ((eq? (car tst) 'equal?)
|
|
(let ((p (caddr tst)))
|
|
(cond ((string? p) `((string? ,e)))
|
|
((boolean? p)
|
|
`((boolean? ,e)))
|
|
((char? p) `((char? ,e)))
|
|
((number? p) `((number? ,e)))
|
|
((and (pair? p)
|
|
(eq? 'quote (car p)))
|
|
`((symbol? ,e)))
|
|
(else '()))))
|
|
((eq? (car tst) 'null?) `((list? ,e)))
|
|
((vec-structure? tst) `((vector? ,e)))
|
|
(else '())))
|
|
(not-imp
|
|
(case (car tst)
|
|
((list?) `((not (null? ,e))))
|
|
(else '())))
|
|
(s (ks (cons tst (append implied sf))))
|
|
(k (kf (cons `(not ,tst)
|
|
(append not-imp sf)))))
|
|
(assm tst k s))))))
|
|
(assm (lambda (tst f s)
|
|
(cond ((equal? s f) s)
|
|
((and (eq? s #t) (eq? f #f)) tst)
|
|
((and (eq? (car tst) 'pair?)
|
|
(memq match:error-control '(unspecified fail))
|
|
(memq (car f) '(cond match:error))
|
|
(guarantees s (cadr tst)))
|
|
s)
|
|
((and (pair? s)
|
|
(eq? (car s) 'if)
|
|
(equal? (cadddr s) f))
|
|
(if (eq? (car (cadr s)) 'and)
|
|
`(if (and ,tst ,@(cdr (cadr s))) ,(caddr s) ,f)
|
|
`(if (and ,tst ,(cadr s)) ,(caddr s) ,f)))
|
|
((and (pair? s)
|
|
(equal? (car s) 'call-with-current-continuation)
|
|
(pair? (cdr s))
|
|
(pair? (cadr s))
|
|
(equal? (caadr s) 'lambda)
|
|
(pair? (cdadr s))
|
|
(pair? (cadadr s))
|
|
(null? (cdr (cadadr s)))
|
|
(pair? (cddadr s))
|
|
(pair? (car (cddadr s)))
|
|
(equal? (caar (cddadr s)) 'let)
|
|
(pair? (cdar (cddadr s)))
|
|
(pair? (cadar (cddadr s)))
|
|
(pair? (caadar (cddadr s)))
|
|
(pair? (cdr (caadar (cddadr s))))
|
|
(pair? (cadr (caadar (cddadr s))))
|
|
(equal? (caadr (caadar (cddadr s))) 'lambda)
|
|
(pair? (cdadr (caadar (cddadr s))))
|
|
(null? (cadadr (caadar (cddadr s))))
|
|
(pair? (cddadr (caadar (cddadr s))))
|
|
(pair? (car (cddadr (caadar (cddadr s)))))
|
|
(pair? (cdar (cddadr (caadar (cddadr s)))))
|
|
(null? (cddar (cddadr (caadar (cddadr s)))))
|
|
(null? (cdr (cddadr (caadar (cddadr s)))))
|
|
(null? (cddr (caadar (cddadr s))))
|
|
(null? (cdadar (cddadr s)))
|
|
(pair? (cddar (cddadr s)))
|
|
(null? (cdddar (cddadr s)))
|
|
(null? (cdr (cddadr s)))
|
|
(null? (cddr s))
|
|
(equal? f (cadar (cddadr (caadar (cddadr s))))))
|
|
(let ((k (car (cadadr s)))
|
|
(fail (car (caadar (cddadr s))))
|
|
(s2 (caddar (cddadr s))))
|
|
`(call-with-current-continuation
|
|
(lambda (,k)
|
|
(let ((,fail (lambda () (,k ,f))))
|
|
,(assm tst `(,fail) s2))))))
|
|
((and #f
|
|
(pair? s)
|
|
(equal? (car s) 'let)
|
|
(pair? (cdr s))
|
|
(pair? (cadr s))
|
|
(pair? (caadr s))
|
|
(pair? (cdaadr s))
|
|
(pair? (car (cdaadr s)))
|
|
(equal? (caar (cdaadr s)) 'lambda)
|
|
(pair? (cdar (cdaadr s)))
|
|
(null? (cadar (cdaadr s)))
|
|
(pair? (cddar (cdaadr s)))
|
|
(null? (cdddar (cdaadr s)))
|
|
(null? (cdr (cdaadr s)))
|
|
(null? (cdadr s))
|
|
(pair? (cddr s))
|
|
(null? (cdddr s))
|
|
(equal? (caddar (cdaadr s)) f))
|
|
(let ((fail (caaadr s)) (s2 (caddr s)))
|
|
`(let ((,fail (lambda () ,f)))
|
|
,(assm tst `(,fail) s2))))
|
|
(else `(if ,tst ,s ,f)))))
|
|
(guarantees
|
|
(lambda (code x)
|
|
(let ((a (add-a x)) (d (add-d x)))
|
|
(let loop ((code code))
|
|
(cond ((not (pair? code)) #f)
|
|
((memq (car code) '(cond match:error)) #t)
|
|
((or (equal? code a) (equal? code d)) #t)
|
|
((eq? (car code) 'if)
|
|
(or (loop (cadr code))
|
|
(and (loop (caddr code)) (loop (cadddr code)))))
|
|
((eq? (car code) 'lambda) #f)
|
|
((and (eq? (car code) 'let) (symbol? (cadr code)))
|
|
#f)
|
|
(else (or (loop (car code)) (loop (cdr code)))))))))
|
|
(in (lambda (e l)
|
|
(or (member e l)
|
|
(and (eq? (car e) 'list?)
|
|
(or (member `(null? ,(cadr e)) l)
|
|
(member `(pair? ,(cadr e)) l)))
|
|
(and (eq? (car e) 'not)
|
|
(let* ((srch (cadr e))
|
|
(const-class (equal-test? srch)))
|
|
(cond (const-class
|
|
(let mem ((l l))
|
|
(if (null? l)
|
|
#f
|
|
(let ((x (car l)))
|
|
(or (and (equal? (cadr x) (cadr srch))
|
|
(disjoint? x)
|
|
(not (equal?
|
|
const-class
|
|
(car x))))
|
|
(equal?
|
|
x
|
|
`(not (,const-class
|
|
,(cadr srch))))
|
|
(and (equal? (cadr x) (cadr srch))
|
|
(equal-test? x)
|
|
(not (equal?
|
|
(caddr srch)
|
|
(caddr x))))
|
|
(mem (cdr l)))))))
|
|
((disjoint? srch)
|
|
(let mem ((l l))
|
|
(if (null? l)
|
|
#f
|
|
(let ((x (car l)))
|
|
(or (and (equal? (cadr x) (cadr srch))
|
|
(disjoint? x)
|
|
(not (equal?
|
|
(car x)
|
|
(car srch))))
|
|
(mem (cdr l)))))))
|
|
((eq? (car srch) 'list?)
|
|
(let mem ((l l))
|
|
(if (null? l)
|
|
#f
|
|
(let ((x (car l)))
|
|
(or (and (equal? (cadr x) (cadr srch))
|
|
(disjoint? x)
|
|
(not (memq (car x)
|
|
'(list? pair?
|
|
null?))))
|
|
(mem (cdr l)))))))
|
|
((vec-structure? srch)
|
|
(let mem ((l l))
|
|
(if (null? l)
|
|
#f
|
|
(let ((x (car l)))
|
|
(or (and (equal? (cadr x) (cadr srch))
|
|
(or (disjoint? x)
|
|
(vec-structure? x))
|
|
(not (equal?
|
|
(car x)
|
|
'vector?))
|
|
(not (equal?
|
|
(car x)
|
|
(car srch))))
|
|
(equal?
|
|
x
|
|
`(not (vector? ,(cadr srch))))
|
|
(mem (cdr l)))))))
|
|
(else #f)))))))
|
|
(equal-test?
|
|
(lambda (tst)
|
|
(and (eq? (car tst) 'equal?)
|
|
(let ((p (caddr tst)))
|
|
(cond ((string? p) 'string?)
|
|
((boolean? p) 'boolean?)
|
|
((char? p) 'char?)
|
|
((number? p) 'number?)
|
|
((and (pair? p)
|
|
(pair? (cdr p))
|
|
(null? (cddr p))
|
|
(eq? 'quote (car p))
|
|
(symbol? (cadr p)))
|
|
'symbol?)
|
|
(else #f))))))
|
|
(disjoint?
|
|
(lambda (tst)
|
|
(memq (car tst) match:disjoint-predicates)))
|
|
(vec-structure?
|
|
(lambda (tst)
|
|
(memq (car tst) match:vector-structures)))
|
|
(add-a (lambda (a)
|
|
(let ((new (and (pair? a) (assq (car a) c---rs))))
|
|
(if new (cons (cadr new) (cdr a)) `(car ,a)))))
|
|
(add-d (lambda (a)
|
|
(let ((new (and (pair? a) (assq (car a) c---rs))))
|
|
(if new (cons (cddr new) (cdr a)) `(cdr ,a)))))
|
|
(c---rs
|
|
'((car caar . cdar)
|
|
(cdr cadr . cddr)
|
|
(caar caaar . cdaar)
|
|
(cadr caadr . cdadr)
|
|
(cdar cadar . cddar)
|
|
(cddr caddr . cdddr)
|
|
(caaar caaaar . cdaaar)
|
|
(caadr caaadr . cdaadr)
|
|
(cadar caadar . cdadar)
|
|
(caddr caaddr . cdaddr)
|
|
(cdaar cadaar . cddaar)
|
|
(cdadr cadadr . cddadr)
|
|
(cddar caddar . cdddar)
|
|
(cdddr cadddr . cddddr)))
|
|
(setter
|
|
(lambda (e p)
|
|
(let ((mk-setter
|
|
(lambda (s) (symbol-append 'set- s '!))))
|
|
(cond ((not (pair? e))
|
|
(match:syntax-err p "unnested set! pattern"))
|
|
((eq? (car e) 'vector-ref)
|
|
`(let ((x ,(cadr e)))
|
|
(lambda (y) (vector-set! x ,(caddr e) y))))
|
|
((eq? (car e) 'unbox)
|
|
`(let ((x ,(cadr e))) (lambda (y) (set-box! x y))))
|
|
((eq? (car e) 'car)
|
|
`(let ((x ,(cadr e))) (lambda (y) (set-car! x y))))
|
|
((eq? (car e) 'cdr)
|
|
`(let ((x ,(cadr e))) (lambda (y) (set-cdr! x y))))
|
|
((let ((a (assq (car e) get-c---rs)))
|
|
(and a
|
|
`(let ((x (,(cadr a) ,(cadr e))))
|
|
(lambda (y) (,(mk-setter (cddr a)) x y))))))
|
|
(else
|
|
`(let ((x ,(cadr e)))
|
|
(lambda (y) (,(mk-setter (car e)) x y))))))))
|
|
(getter
|
|
(lambda (e p)
|
|
(cond ((not (pair? e))
|
|
(match:syntax-err p "unnested get! pattern"))
|
|
((eq? (car e) 'vector-ref)
|
|
`(let ((x ,(cadr e)))
|
|
(lambda () (vector-ref x ,(caddr e)))))
|
|
((eq? (car e) 'unbox)
|
|
`(let ((x ,(cadr e))) (lambda () (unbox x))))
|
|
((eq? (car e) 'car)
|
|
`(let ((x ,(cadr e))) (lambda () (car x))))
|
|
((eq? (car e) 'cdr)
|
|
`(let ((x ,(cadr e))) (lambda () (cdr x))))
|
|
((let ((a (assq (car e) get-c---rs)))
|
|
(and a
|
|
`(let ((x (,(cadr a) ,(cadr e))))
|
|
(lambda () (,(cddr a) x))))))
|
|
(else
|
|
`(let ((x ,(cadr e))) (lambda () (,(car e) x)))))))
|
|
(get-c---rs
|
|
'((caar car . car)
|
|
(cadr cdr . car)
|
|
(cdar car . cdr)
|
|
(cddr cdr . cdr)
|
|
(caaar caar . car)
|
|
(caadr cadr . car)
|
|
(cadar cdar . car)
|
|
(caddr cddr . car)
|
|
(cdaar caar . cdr)
|
|
(cdadr cadr . cdr)
|
|
(cddar cdar . cdr)
|
|
(cdddr cddr . cdr)
|
|
(caaaar caaar . car)
|
|
(caaadr caadr . car)
|
|
(caadar cadar . car)
|
|
(caaddr caddr . car)
|
|
(cadaar cdaar . car)
|
|
(cadadr cdadr . car)
|
|
(caddar cddar . car)
|
|
(cadddr cdddr . car)
|
|
(cdaaar caaar . cdr)
|
|
(cdaadr caadr . cdr)
|
|
(cdadar cadar . cdr)
|
|
(cdaddr caddr . cdr)
|
|
(cddaar cdaar . cdr)
|
|
(cddadr cdadr . cdr)
|
|
(cdddar cddar . cdr)
|
|
(cddddr cdddr . cdr)))
|
|
(symbol-append
|
|
(lambda l
|
|
(string->symbol
|
|
(apply string-append
|
|
(map (lambda (x)
|
|
(cond ((symbol? x) (symbol->string x))
|
|
((number? x) (number->string x))
|
|
(else x)))
|
|
l)))))
|
|
(rac (lambda (l)
|
|
(if (null? (cdr l)) (car l) (rac (cdr l)))))
|
|
(rdc (lambda (l)
|
|
(if (null? (cdr l))
|
|
'()
|
|
(cons (car l) (rdc (cdr l)))))))
|
|
(list genmatch genletrec gendefine pattern-var?)))
|
|
(defmacro
|
|
match
|
|
args
|
|
(cond ((and (list? args)
|
|
(<= 1 (length args))
|
|
(match:andmap
|
|
(lambda (y) (and (list? y) (<= 2 (length y))))
|
|
(cdr args)))
|
|
(let* ((exp (car args))
|
|
(clauses (cdr args))
|
|
(e (if (symbol? exp) exp (gentemp))))
|
|
(if (symbol? exp)
|
|
((car match:expanders) e clauses `(match ,@args))
|
|
`(let ((,e ,exp))
|
|
,((car match:expanders) e clauses `(match ,@args))))))
|
|
(else
|
|
(match:syntax-err
|
|
`(match ,@args)
|
|
"syntax error in"))))
|
|
(defmacro
|
|
match-lambda
|
|
args
|
|
(if (and (list? args)
|
|
(match:andmap
|
|
(lambda (g126)
|
|
(if (and (pair? g126) (list? (cdr g126)))
|
|
(pair? (cdr g126))
|
|
#f))
|
|
args))
|
|
((lambda ()
|
|
(let ((e (gentemp)))
|
|
`(lambda (,e) (match ,e ,@args)))))
|
|
((lambda ()
|
|
(match:syntax-err
|
|
`(match-lambda ,@args)
|
|
"syntax error in")))))
|
|
(defmacro
|
|
match-lambda*
|
|
args
|
|
(if (and (list? args)
|
|
(match:andmap
|
|
(lambda (g134)
|
|
(if (and (pair? g134) (list? (cdr g134)))
|
|
(pair? (cdr g134))
|
|
#f))
|
|
args))
|
|
((lambda ()
|
|
(let ((e (gentemp)))
|
|
`(lambda ,e (match ,e ,@args)))))
|
|
((lambda ()
|
|
(match:syntax-err
|
|
`(match-lambda* ,@args)
|
|
"syntax error in")))))
|
|
(defmacro
|
|
match-let
|
|
args
|
|
(let ((g158 (lambda (pat exp body)
|
|
`(match ,exp (,pat ,@body))))
|
|
(g154 (lambda (pat exp body)
|
|
(let ((g (map (lambda (x) (gentemp)) pat))
|
|
(vpattern (list->vector pat)))
|
|
`(let ,(map list g exp)
|
|
(match (vector ,@g) (,vpattern ,@body))))))
|
|
(g146 (lambda ()
|
|
(match:syntax-err
|
|
`(match-let ,@args)
|
|
"syntax error in")))
|
|
(g145 (lambda (p1 e1 p2 e2 body)
|
|
(let ((g1 (gentemp)) (g2 (gentemp)))
|
|
`(let ((,g1 ,e1) (,g2 ,e2))
|
|
(match (cons ,g1 ,g2) ((,p1 unquote p2) ,@body))))))
|
|
(g136 (cadddr match:expanders)))
|
|
(if (pair? args)
|
|
(if (symbol? (car args))
|
|
(if (and (pair? (cdr args)) (list? (cadr args)))
|
|
(let g161 ((g162 (cadr args)) (g160 '()) (g159 '()))
|
|
(if (null? g162)
|
|
(if (and (list? (cddr args)) (pair? (cddr args)))
|
|
((lambda (name pat exp body)
|
|
(if (match:andmap (cadddr match:expanders) pat)
|
|
`(let ,@args)
|
|
`(letrec ((,name (match-lambda* (,pat ,@body))))
|
|
(,name ,@exp))))
|
|
(car args)
|
|
(reverse g159)
|
|
(reverse g160)
|
|
(cddr args))
|
|
(g146))
|
|
(if (and (pair? (car g162))
|
|
(pair? (cdar g162))
|
|
(null? (cddar g162)))
|
|
(g161 (cdr g162)
|
|
(cons (cadar g162) g160)
|
|
(cons (caar g162) g159))
|
|
(g146))))
|
|
(g146))
|
|
(if (list? (car args))
|
|
(if (match:andmap
|
|
(lambda (g167)
|
|
(if (and (pair? g167)
|
|
(g136 (car g167))
|
|
(pair? (cdr g167)))
|
|
(null? (cddr g167))
|
|
#f))
|
|
(car args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
((lambda () `(let ,@args)))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(g146)
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146)))))
|
|
(if (and (pair? (car args))
|
|
(pair? (caar args))
|
|
(pair? (cdaar args))
|
|
(null? (cddaar args)))
|
|
(if (null? (cdar args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g158 (caaar args) (cadaar args) (cdr args))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(g146)
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146)))))
|
|
(if (and (pair? (cdar args))
|
|
(pair? (cadar args))
|
|
(pair? (cdadar args))
|
|
(null? (cdr (cdadar args)))
|
|
(null? (cddar args)))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g145 (caaar args)
|
|
(cadaar args)
|
|
(caadar args)
|
|
(car (cdadar args))
|
|
(cdr args))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(g146)
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146)))))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g154 (reverse g147) (reverse g148) (cdr args))
|
|
(g146))
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146))))))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g154 (reverse g147) (reverse g148) (cdr args))
|
|
(g146))
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146))))))
|
|
(if (pair? (car args))
|
|
(if (and (pair? (caar args))
|
|
(pair? (cdaar args))
|
|
(null? (cddaar args)))
|
|
(if (null? (cdar args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g158 (caaar args) (cadaar args) (cdr args))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(g146)
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146)))))
|
|
(if (and (pair? (cdar args))
|
|
(pair? (cadar args))
|
|
(pair? (cdadar args))
|
|
(null? (cdr (cdadar args)))
|
|
(null? (cddar args)))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g145 (caaar args)
|
|
(cadaar args)
|
|
(caadar args)
|
|
(car (cdadar args))
|
|
(cdr args))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(g146)
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146)))))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g154 (reverse g147) (reverse g148) (cdr args))
|
|
(g146))
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146))))))
|
|
(let g149 ((g150 (car args)) (g148 '()) (g147 '()))
|
|
(if (null? g150)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g154 (reverse g147) (reverse g148) (cdr args))
|
|
(g146))
|
|
(if (and (pair? (car g150))
|
|
(pair? (cdar g150))
|
|
(null? (cddar g150)))
|
|
(g149 (cdr g150)
|
|
(cons (cadar g150) g148)
|
|
(cons (caar g150) g147))
|
|
(g146)))))
|
|
(g146))))
|
|
(g146))))
|
|
(defmacro
|
|
match-let*
|
|
args
|
|
(let ((g176 (lambda ()
|
|
(match:syntax-err
|
|
`(match-let* ,@args)
|
|
"syntax error in"))))
|
|
(if (pair? args)
|
|
(if (null? (car args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
((lambda (body) `(let* ,@args)) (cdr args))
|
|
(g176))
|
|
(if (and (pair? (car args))
|
|
(pair? (caar args))
|
|
(pair? (cdaar args))
|
|
(null? (cddaar args))
|
|
(list? (cdar args))
|
|
(list? (cdr args))
|
|
(pair? (cdr args)))
|
|
((lambda (pat exp rest body)
|
|
(if ((cadddr match:expanders) pat)
|
|
`(let ((,pat ,exp)) (match-let* ,rest ,@body))
|
|
`(match ,exp (,pat (match-let* ,rest ,@body)))))
|
|
(caaar args)
|
|
(cadaar args)
|
|
(cdar args)
|
|
(cdr args))
|
|
(g176)))
|
|
(g176))))
|
|
(defmacro
|
|
match-letrec
|
|
args
|
|
(let ((g200 (cadddr match:expanders))
|
|
(g199 (lambda (p1 e1 p2 e2 body)
|
|
`(match-letrec
|
|
(((,p1 unquote p2) (cons ,e1 ,e2)))
|
|
,@body)))
|
|
(g195 (lambda ()
|
|
(match:syntax-err
|
|
`(match-letrec ,@args)
|
|
"syntax error in")))
|
|
(g194 (lambda (pat exp body)
|
|
`(match-letrec
|
|
((,(list->vector pat) (vector ,@exp)))
|
|
,@body)))
|
|
(g186 (lambda (pat exp body)
|
|
((cadr match:expanders)
|
|
pat
|
|
exp
|
|
body
|
|
`(match-letrec ((,pat ,exp)) ,@body)))))
|
|
(if (pair? args)
|
|
(if (list? (car args))
|
|
(if (match:andmap
|
|
(lambda (g206)
|
|
(if (and (pair? g206)
|
|
(g200 (car g206))
|
|
(pair? (cdr g206)))
|
|
(null? (cddr g206))
|
|
#f))
|
|
(car args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
((lambda () `(letrec ,@args)))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(g195)
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195)))))
|
|
(if (and (pair? (car args))
|
|
(pair? (caar args))
|
|
(pair? (cdaar args))
|
|
(null? (cddaar args)))
|
|
(if (null? (cdar args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g186 (caaar args) (cadaar args) (cdr args))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(g195)
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195)))))
|
|
(if (and (pair? (cdar args))
|
|
(pair? (cadar args))
|
|
(pair? (cdadar args))
|
|
(null? (cdr (cdadar args)))
|
|
(null? (cddar args)))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g199 (caaar args)
|
|
(cadaar args)
|
|
(caadar args)
|
|
(car (cdadar args))
|
|
(cdr args))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(g195)
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195)))))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g194 (reverse g187) (reverse g188) (cdr args))
|
|
(g195))
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195))))))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g194 (reverse g187) (reverse g188) (cdr args))
|
|
(g195))
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195))))))
|
|
(if (pair? (car args))
|
|
(if (and (pair? (caar args))
|
|
(pair? (cdaar args))
|
|
(null? (cddaar args)))
|
|
(if (null? (cdar args))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g186 (caaar args) (cadaar args) (cdr args))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(g195)
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195)))))
|
|
(if (and (pair? (cdar args))
|
|
(pair? (cadar args))
|
|
(pair? (cdadar args))
|
|
(null? (cdr (cdadar args)))
|
|
(null? (cddar args)))
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g199 (caaar args)
|
|
(cadaar args)
|
|
(caadar args)
|
|
(car (cdadar args))
|
|
(cdr args))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(g195)
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195)))))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g194 (reverse g187) (reverse g188) (cdr args))
|
|
(g195))
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195))))))
|
|
(let g189 ((g190 (car args)) (g188 '()) (g187 '()))
|
|
(if (null? g190)
|
|
(if (and (list? (cdr args)) (pair? (cdr args)))
|
|
(g194 (reverse g187) (reverse g188) (cdr args))
|
|
(g195))
|
|
(if (and (pair? (car g190))
|
|
(pair? (cdar g190))
|
|
(null? (cddar g190)))
|
|
(g189 (cdr g190)
|
|
(cons (cadar g190) g188)
|
|
(cons (caar g190) g187))
|
|
(g195)))))
|
|
(g195)))
|
|
(g195))))
|
|
(defmacro
|
|
match-define
|
|
args
|
|
(let ((g210 (cadddr match:expanders))
|
|
(g209 (lambda ()
|
|
(match:syntax-err
|
|
`(match-define ,@args)
|
|
"syntax error in"))))
|
|
(if (pair? args)
|
|
(if (g210 (car args))
|
|
(if (and (pair? (cdr args)) (null? (cddr args)))
|
|
((lambda () `(begin (define ,@args))))
|
|
(g209))
|
|
(if (and (pair? (cdr args)) (null? (cddr args)))
|
|
((lambda (pat exp)
|
|
((caddr match:expanders)
|
|
pat
|
|
exp
|
|
`(match-define ,@args)))
|
|
(car args)
|
|
(cadr args))
|
|
(g209)))
|
|
(g209))))
|
|
(define match:runtime-structures #f)
|
|
(define match:set-runtime-structures
|
|
(lambda (v) (set! match:runtime-structures v)))
|
|
(define match:primitive-vector? vector?)
|
|
(defmacro
|
|
defstruct
|
|
args
|
|
(let ((field?
|
|
(lambda (x)
|
|
(if (symbol? x)
|
|
((lambda () #t))
|
|
(if (and (pair? x)
|
|
(symbol? (car x))
|
|
(pair? (cdr x))
|
|
(symbol? (cadr x))
|
|
(null? (cddr x)))
|
|
((lambda () #t))
|
|
((lambda () #f))))))
|
|
(selector-name
|
|
(lambda (x)
|
|
(if (symbol? x)
|
|
((lambda () x))
|
|
(if (and (pair? x)
|
|
(symbol? (car x))
|
|
(pair? (cdr x))
|
|
(null? (cddr x)))
|
|
((lambda (s) s) (car x))
|
|
(match:error x)))))
|
|
(mutator-name
|
|
(lambda (x)
|
|
(if (symbol? x)
|
|
((lambda () #f))
|
|
(if (and (pair? x)
|
|
(pair? (cdr x))
|
|
(symbol? (cadr x))
|
|
(null? (cddr x)))
|
|
((lambda (s) s) (cadr x))
|
|
(match:error x)))))
|
|
(filter-map-with-index
|
|
(lambda (f l)
|
|
(letrec ((mapi (lambda (l i)
|
|
(cond ((null? l) '())
|
|
((f (car l) i)
|
|
=>
|
|
(lambda (x)
|
|
(cons x (mapi (cdr l) (+ 1 i)))))
|
|
(else (mapi (cdr l) (+ 1 i)))))))
|
|
(mapi l 1)))))
|
|
(let ((g227 (lambda ()
|
|
(match:syntax-err
|
|
`(defstruct ,@args)
|
|
"syntax error in"))))
|
|
(if (and (pair? args)
|
|
(symbol? (car args))
|
|
(pair? (cdr args))
|
|
(symbol? (cadr args))
|
|
(pair? (cddr args))
|
|
(symbol? (caddr args))
|
|
(list? (cdddr args)))
|
|
(let g229 ((g230 (cdddr args)) (g228 '()))
|
|
(if (null? g230)
|
|
((lambda (name constructor predicate fields)
|
|
(let* ((selectors (map selector-name fields))
|
|
(mutators (map mutator-name fields))
|
|
(tag (if match:runtime-structures
|
|
(gentemp)
|
|
`',(match:make-structure-tag name)))
|
|
(vectorp
|
|
(cond ((eq? match:structure-control 'disjoint)
|
|
'match:primitive-vector?)
|
|
((eq? match:structure-control 'vector)
|
|
'vector?))))
|
|
(cond ((eq? match:structure-control 'disjoint)
|
|
(if (eq? vector? match:primitive-vector?)
|
|
(set! vector?
|
|
(lambda (v)
|
|
(and (match:primitive-vector? v)
|
|
(or (zero? (vector-length v))
|
|
(not (symbol? (vector-ref v 0)))
|
|
(not (match:structure?
|
|
(vector-ref v 0))))))))
|
|
(if (not (memq predicate match:disjoint-predicates))
|
|
(set! match:disjoint-predicates
|
|
(cons predicate match:disjoint-predicates))))
|
|
((eq? match:structure-control 'vector)
|
|
(if (not (memq predicate match:vector-structures))
|
|
(set! match:vector-structures
|
|
(cons predicate match:vector-structures))))
|
|
(else
|
|
(match:syntax-err
|
|
'(vector disjoint)
|
|
"invalid value for match:structure-control, legal values are")))
|
|
`(begin
|
|
,@(if match:runtime-structures
|
|
`((define ,tag (match:make-structure-tag ',name)))
|
|
'())
|
|
(define ,constructor
|
|
(lambda ,selectors (vector ,tag ,@selectors)))
|
|
(define ,predicate
|
|
(lambda (obj)
|
|
(and (,vectorp obj)
|
|
(= (vector-length obj) ,(+ 1 (length selectors)))
|
|
(eq? (vector-ref obj 0) ,tag))))
|
|
,@(filter-map-with-index
|
|
(lambda (n i)
|
|
`(define ,n (lambda (obj) (vector-ref obj ,i))))
|
|
selectors)
|
|
,@(filter-map-with-index
|
|
(lambda (n i)
|
|
(and n
|
|
`(define ,n
|
|
(lambda (obj newval)
|
|
(vector-set! obj ,i newval)))))
|
|
mutators))))
|
|
(car args)
|
|
(cadr args)
|
|
(caddr args)
|
|
(reverse g228))
|
|
(if (field? (car g230))
|
|
(g229 (cdr g230) (cons (car g230) g228))
|
|
(g227))))
|
|
(g227)))))
|
|
(defmacro
|
|
define-structure
|
|
args
|
|
(let ((g242 (lambda ()
|
|
(match:syntax-err
|
|
`(define-structure ,@args)
|
|
"syntax error in"))))
|
|
(if (and (pair? args)
|
|
(pair? (car args))
|
|
(list? (cdar args)))
|
|
(if (null? (cdr args))
|
|
((lambda (name id1)
|
|
`(define-structure (,name ,@id1) ()))
|
|
(caar args)
|
|
(cdar args))
|
|
(if (and (pair? (cdr args)) (list? (cadr args)))
|
|
(let g239 ((g240 (cadr args)) (g238 '()) (g237 '()))
|
|
(if (null? g240)
|
|
(if (null? (cddr args))
|
|
((lambda (name id1 id2 val)
|
|
(let ((mk-id (lambda (id)
|
|
(if (and (pair? id)
|
|
(equal? (car id) '@)
|
|
(pair? (cdr id))
|
|
(symbol? (cadr id))
|
|
(null? (cddr id)))
|
|
((lambda (x) x) (cadr id))
|
|
((lambda () `(! ,id)))))))
|
|
`(define-const-structure
|
|
(,name ,@(map mk-id id1))
|
|
,(map (lambda (id v) `(,(mk-id id) ,v)) id2 val))))
|
|
(caar args)
|
|
(cdar args)
|
|
(reverse g237)
|
|
(reverse g238))
|
|
(g242))
|
|
(if (and (pair? (car g240))
|
|
(pair? (cdar g240))
|
|
(null? (cddar g240)))
|
|
(g239 (cdr g240)
|
|
(cons (cadar g240) g238)
|
|
(cons (caar g240) g237))
|
|
(g242))))
|
|
(g242)))
|
|
(g242))))
|
|
(defmacro
|
|
define-const-structure
|
|
args
|
|
(let ((field?
|
|
(lambda (id)
|
|
(if (symbol? id)
|
|
((lambda () #t))
|
|
(if (and (pair? id)
|
|
(equal? (car id) '!)
|
|
(pair? (cdr id))
|
|
(symbol? (cadr id))
|
|
(null? (cddr id)))
|
|
((lambda () #t))
|
|
((lambda () #f))))))
|
|
(field-name
|
|
(lambda (x) (if (symbol? x) x (cadr x))))
|
|
(has-mutator? (lambda (x) (not (symbol? x))))
|
|
(filter-map-with-index
|
|
(lambda (f l)
|
|
(letrec ((mapi (lambda (l i)
|
|
(cond ((null? l) '())
|
|
((f (car l) i)
|
|
=>
|
|
(lambda (x)
|
|
(cons x (mapi (cdr l) (+ 1 i)))))
|
|
(else (mapi (cdr l) (+ 1 i)))))))
|
|
(mapi l 1))))
|
|
(symbol-append
|
|
(lambda l
|
|
(string->symbol
|
|
(apply string-append
|
|
(map (lambda (x)
|
|
(cond ((symbol? x) (symbol->string x))
|
|
((number? x) (number->string x))
|
|
(else x)))
|
|
l))))))
|
|
(let ((g266 (lambda ()
|
|
(match:syntax-err
|
|
`(define-const-structure ,@args)
|
|
"syntax error in"))))
|
|
(if (and (pair? args)
|
|
(pair? (car args))
|
|
(list? (cdar args)))
|
|
(if (null? (cdr args))
|
|
((lambda (name id1)
|
|
`(define-const-structure (,name ,@id1) ()))
|
|
(caar args)
|
|
(cdar args))
|
|
(if (symbol? (caar args))
|
|
(let g259 ((g260 (cdar args)) (g258 '()))
|
|
(if (null? g260)
|
|
(if (and (pair? (cdr args)) (list? (cadr args)))
|
|
(let g263 ((g264 (cadr args)) (g262 '()) (g261 '()))
|
|
(if (null? g264)
|
|
(if (null? (cddr args))
|
|
((lambda (name id1 id2 val)
|
|
(let* ((id1id2 (append id1 id2))
|
|
(raw-constructor
|
|
(symbol-append 'make-raw- name))
|
|
(constructor (symbol-append 'make- name))
|
|
(predicate (symbol-append name '?)))
|
|
`(begin
|
|
(defstruct
|
|
,name
|
|
,raw-constructor
|
|
,predicate
|
|
,@(filter-map-with-index
|
|
(lambda (arg i)
|
|
(if (has-mutator? arg)
|
|
`(,(symbol-append name '- i)
|
|
,(symbol-append
|
|
'set-
|
|
name
|
|
'-
|
|
i
|
|
'!))
|
|
(symbol-append name '- i)))
|
|
id1id2))
|
|
,(let* ((make-fresh
|
|
(lambda (x)
|
|
(if (eq? '_ x) (gentemp) x)))
|
|
(names1
|
|
(map make-fresh
|
|
(map field-name id1)))
|
|
(names2
|
|
(map make-fresh
|
|
(map field-name id2))))
|
|
`(define ,constructor
|
|
(lambda ,names1
|
|
(let* ,(map list names2 val)
|
|
(,raw-constructor
|
|
,@names1
|
|
,@names2)))))
|
|
,@(filter-map-with-index
|
|
(lambda (field i)
|
|
(if (eq? (field-name field) '_)
|
|
#f
|
|
`(define (unquote
|
|
(symbol-append
|
|
name
|
|
'-
|
|
(field-name field)))
|
|
,(symbol-append name '- i))))
|
|
id1id2)
|
|
,@(filter-map-with-index
|
|
(lambda (field i)
|
|
(if (or (eq? (field-name field) '_)
|
|
(not (has-mutator? field)))
|
|
#f
|
|
`(define (unquote
|
|
(symbol-append
|
|
'set-
|
|
name
|
|
'-
|
|
(field-name field)
|
|
'!))
|
|
,(symbol-append
|
|
'set-
|
|
name
|
|
'-
|
|
i
|
|
'!))))
|
|
id1id2))))
|
|
(caar args)
|
|
(reverse g258)
|
|
(reverse g261)
|
|
(reverse g262))
|
|
(g266))
|
|
(if (and (pair? (car g264))
|
|
(field? (caar g264))
|
|
(pair? (cdar g264))
|
|
(null? (cddar g264)))
|
|
(g263 (cdr g264)
|
|
(cons (cadar g264) g262)
|
|
(cons (caar g264) g261))
|
|
(g266))))
|
|
(g266))
|
|
(if (field? (car g260))
|
|
(g259 (cdr g260) (cons (car g260) g258))
|
|
(g266))))
|
|
(g266)))
|
|
(g266)))))
|
|
(define home-directory
|
|
(or (getenv "HOME")
|
|
(error "environment variable HOME is not defined")))
|
|
(defmacro recur args `(let ,@args))
|
|
(defmacro
|
|
rec
|
|
args
|
|
(match args
|
|
(((? symbol? x) v) `(letrec ((,x ,v)) ,x))))
|
|
(defmacro
|
|
parameterize
|
|
args
|
|
(match args ((bindings exp ...) `(begin ,@exp))))
|
|
(define gensym gentemp)
|
|
(define expand-once macroexpand-1)
|
|
(defmacro check-increment-counter args #f)
|
|
(define symbol-append
|
|
(lambda l
|
|
(string->symbol
|
|
(apply string-append
|
|
(map (lambda (x) (format #f "~a" x)) l)))))
|
|
(define gensym gentemp)
|
|
(define andmap
|
|
(lambda (f . lists)
|
|
(cond ((null? (car lists)) (and))
|
|
((null? (cdr (car lists)))
|
|
(apply f (map car lists)))
|
|
(else
|
|
(and (apply f (map car lists))
|
|
(apply andmap f (map cdr lists)))))))
|
|
(define true-object? (lambda (x) (eq? #t x)))
|
|
(define false-object? (lambda (x) (eq? #f x)))
|
|
(define void (lambda () (cond (#f #f))))
|
|
(defmacro
|
|
when
|
|
args
|
|
(match args
|
|
((tst body __1)
|
|
`(if ,tst (begin ,@body (void)) (void)))))
|
|
(defmacro
|
|
unless
|
|
args
|
|
(match args
|
|
((tst body __1)
|
|
`(if ,tst (void) (begin ,@body (void))))))
|
|
(define should-never-reach
|
|
(lambda (form)
|
|
(slib:error "fell off end of " form)))
|
|
(define make-cvector make-vector)
|
|
(define cvector vector)
|
|
(define cvector-length vector-length)
|
|
(define cvector-ref vector-ref)
|
|
(define cvector->list vector->list)
|
|
(define list->cvector list->vector)
|
|
(define-const-structure (record _))
|
|
(defmacro
|
|
record
|
|
args
|
|
(match args
|
|
((((? symbol? id) exp) ...)
|
|
`(make-record
|
|
(list ,@(map (lambda (i x) `(cons ',i ,x)) id exp))))
|
|
(_ (slib:error "syntax error at " `(record ,@args)))))
|
|
(defmacro
|
|
field
|
|
args
|
|
(match args
|
|
(((? symbol? id) exp)
|
|
`(match ,exp
|
|
(($ record x)
|
|
(match (assq ',id x)
|
|
(#f
|
|
(slib:error
|
|
"no field "
|
|
,id
|
|
'in
|
|
(cons 'record (map car x))))
|
|
((_ . x) x)))
|
|
(_ (slib:error "not a record: " '(field ,id _)))))
|
|
(_ (slib:error "syntax error at " `(field ,@args)))))
|
|
(define-const-structure (module _))
|
|
(defmacro
|
|
module
|
|
args
|
|
(match args
|
|
(((i ...) defs ...)
|
|
`(let ()
|
|
,@defs
|
|
(make-module
|
|
(record ,@(map (lambda (x) (list x x)) i)))))
|
|
(_ (slib:error "syntax error at " `(module ,@args)))))
|
|
(defmacro
|
|
import
|
|
args
|
|
(match args
|
|
((((mod defs ...) ...) body __1)
|
|
(let* ((m (map (lambda (_) (gentemp)) mod))
|
|
(newdefs
|
|
(let loop ((mod-names m) (l-defs defs))
|
|
(if (null? mod-names)
|
|
'()
|
|
(append
|
|
(let ((m (car mod-names)))
|
|
(map (match-lambda
|
|
((? symbol? x) `(,x (field ,x ,m)))
|
|
(((? symbol? i) (? symbol? e))
|
|
`(,i (field ,e ,m)))
|
|
(x (slib:error "ill-formed definition: " x)))
|
|
(car l-defs)))
|
|
(loop (cdr mod-names) (cdr l-defs)))))))
|
|
`(let (unquote
|
|
(map (lambda (m mod)
|
|
`(,m (match ,mod (($ module x) x))))
|
|
m
|
|
mod))
|
|
(let ,newdefs body ...))))))
|
|
(define raise
|
|
(lambda vals
|
|
(slib:error "Unhandled exception " vals)))
|
|
(defmacro
|
|
fluid-let
|
|
args
|
|
(match args
|
|
((((x val) ...) body __1)
|
|
(let ((old-x (map (lambda (_) (gentemp)) x))
|
|
(swap-x (map (lambda (_) (gentemp)) x))
|
|
(swap (gentemp)))
|
|
`(let ,(map list old-x val)
|
|
(let ((,swap
|
|
(lambda ()
|
|
(let ,(map list swap-x old-x)
|
|
,@(map (lambda (old x) `(set! ,old ,x)) old-x x)
|
|
,@(map (lambda (x swap) `(set! ,x ,swap))
|
|
x
|
|
swap-x)))))
|
|
(dynamic-wind ,swap (lambda () ,@body) ,swap)))))
|
|
(_ (slib:error
|
|
"syntax error at "
|
|
`(fluid-let ,@args)))))
|
|
(defmacro
|
|
handle
|
|
args
|
|
(match args
|
|
((e h)
|
|
(let ((k (gentemp)) (exn (gentemp)))
|
|
`((call-with-current-continuation
|
|
(lambda (k)
|
|
(fluid-let
|
|
((raise (lambda ,exn (k (lambda () (apply ,h ,exn))))))
|
|
(let ((v ,e)) (lambda () v))))))))
|
|
(_ (slib:error "syntax error in " `(handle ,@args)))))
|
|
(defmacro
|
|
:
|
|
args
|
|
(match args ((typeexp exp) exp)))
|
|
(defmacro
|
|
module:
|
|
args
|
|
(match args
|
|
((((i type) ...) defs ...)
|
|
`(let ()
|
|
,@defs
|
|
(make-module
|
|
(record
|
|
,@(map (lambda (i type) `(,i (: ,type ,i))) i type)))))))
|
|
(defmacro
|
|
define:
|
|
args
|
|
(match args
|
|
((name type exp) `(define ,name (: ,type ,exp)))))
|
|
(define st:failure
|
|
(lambda (chk fmt . args)
|
|
(slib:error
|
|
(apply format
|
|
#f
|
|
(string-append "~a : " fmt)
|
|
chk
|
|
args))))
|
|
(defmacro
|
|
check-bound
|
|
args
|
|
(match args
|
|
((var) var)
|
|
(x (st:failure `(check-bound ,@x) "syntax-error"))))
|
|
(defmacro
|
|
clash
|
|
args
|
|
(match args
|
|
((name info ...) name)
|
|
(x (st:failure `(clash ,@x) "syntax error"))))
|
|
(defmacro
|
|
check-lambda
|
|
args
|
|
(match args
|
|
(((id info ...) (? symbol? args) body __1)
|
|
`(lambda ,args
|
|
(check-increment-counter ,id)
|
|
,@body))
|
|
(((id info ...) args body __1)
|
|
(let* ((n 0)
|
|
(chk (let loop ((a args) (nargs 0))
|
|
(cond ((pair? a) (loop (cdr a) (+ 1 nargs)))
|
|
((null? a)
|
|
(set! n nargs)
|
|
`(= ,nargs (length args)))
|
|
(else
|
|
(set! n nargs)
|
|
`(<= ,nargs (length args))))))
|
|
(incr (if (number? id)
|
|
`(check-increment-counter ,id)
|
|
#f)))
|
|
`(let ((lam (lambda ,args ,@body)))
|
|
(lambda args
|
|
,incr
|
|
(if ,chk
|
|
(apply lam args)
|
|
,(if (eq? '= (car chk))
|
|
`(st:failure
|
|
'(check-lambda ,id ,@info)
|
|
"requires ~a arguments, passed: ~a"
|
|
,n
|
|
args)
|
|
`(st:failure
|
|
'(check-lambda ,id ,@info)
|
|
"requires >= ~a arguments, passed: ~a"
|
|
,n
|
|
args)))))))
|
|
(x (st:failure `(check-lambda ,@x) "syntax error"))))
|
|
(defmacro
|
|
check-ap
|
|
args
|
|
(match args
|
|
(((id info ...) (? symbol? f) args ...)
|
|
`(begin
|
|
(check-increment-counter ,id)
|
|
(if (procedure? ,f)
|
|
(,f ,@args)
|
|
(st:failure
|
|
'(check-ap ,id ,@info)
|
|
"not a procedure: ~a"
|
|
,f))))
|
|
(((id info ...) f args ...)
|
|
`((lambda (proc . args)
|
|
(check-increment-counter ,id)
|
|
(if (procedure? proc)
|
|
(apply proc args)
|
|
(st:failure
|
|
'(check-ap ,id ,@info)
|
|
"not a procedure: ~a"
|
|
proc)))
|
|
,f
|
|
,@args))
|
|
(x (st:failure `(check-ap ,@x) "syntax error"))))
|
|
(defmacro
|
|
check-field
|
|
args
|
|
(match args
|
|
(((id info ...) (? symbol? f) exp)
|
|
`(match ,exp
|
|
(($ record x)
|
|
(match (assq ',f x)
|
|
(#f
|
|
(st:failure
|
|
'(check-field ,id ,@info)
|
|
"no ~a field in (record ~a)"
|
|
',f
|
|
(map car x)))
|
|
((_ . x) x)))
|
|
(v (st:failure
|
|
'(check-field ,id ,@info)
|
|
"not a record: ~a"
|
|
v))))
|
|
(x (st:failure `(check-field ,@x) "syntax error"))))
|
|
(defmacro
|
|
check-match
|
|
args
|
|
(match args
|
|
(((id info ...) exp (and clause (pat _ __1)) ...)
|
|
(letrec ((last (lambda (pl)
|
|
(if (null? (cdr pl)) (car pl) (last (cdr pl))))))
|
|
(if (match (last pat)
|
|
((? symbol?) #t)
|
|
(('and subp ...) (andmap symbol? subp))
|
|
(_ #f))
|
|
`(begin
|
|
(check-increment-counter ,id)
|
|
(match ,exp ,@clause))
|
|
`(begin
|
|
(check-increment-counter ,id)
|
|
(match ,exp
|
|
,@clause
|
|
(x (st:failure
|
|
'(check-match ,id ,@info)
|
|
"no matching clause for ~a"
|
|
x)))))))
|
|
(x (st:failure `(check-match ,@x) "syntax error"))))
|
|
(defmacro
|
|
check-:
|
|
args
|
|
(match args
|
|
(((id info ...) typeexp exp)
|
|
`(st:failure
|
|
'(check-: ,id ,@info)
|
|
"static type annotation reached"))
|
|
(x (st:failure `(check-: ,@x) "syntax error"))))
|
|
(defmacro
|
|
make-check-typed
|
|
args
|
|
(match args
|
|
((prim)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (null? a)
|
|
(,prim)
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim '_)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (= 1 (length a))
|
|
(,prim (car a))
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim type1)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (and (= 1 (length a)) (,type1 (car a)))
|
|
(,prim (car a))
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim '_ '_)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (= 2 (length a))
|
|
(,prim (car a) (cadr a))
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim '_ type2)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (and (= 2 (length a)) (,type2 (cadr a)))
|
|
(,prim (car a) (cadr a))
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim type1 '_)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (and (= 2 (length a)) (,type1 (car a)))
|
|
(,prim (car a) (cadr a))
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim type1 type2)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (and (= 2 (length a))
|
|
(,type1 (car a))
|
|
(,type2 (cadr a)))
|
|
(,prim (car a) (cadr a))
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))
|
|
((prim types ...)
|
|
(let ((nargs (length types))
|
|
(chkprim (symbol-append 'check- prim))
|
|
(types (map (match-lambda ('_ '(lambda (_) #t)) (x x))
|
|
types)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (and (= ,nargs (length a))
|
|
(andmap
|
|
(lambda (f a) (f a))
|
|
(list ,@types)
|
|
a))
|
|
(apply ,prim a)
|
|
(st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a)))))))))
|
|
(defmacro
|
|
make-check-selector
|
|
args
|
|
(match args
|
|
((prim pat)
|
|
(let ((chkprim (symbol-append 'check- prim)))
|
|
(list 'defmacro
|
|
chkprim
|
|
'id
|
|
(list 'quasiquote
|
|
`(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(match a
|
|
((,pat) x)
|
|
(_ (st:failure
|
|
(cons ',chkprim '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a))))))))))
|
|
(make-check-typed number? _)
|
|
(make-check-typed null? _)
|
|
(make-check-typed char? _)
|
|
(make-check-typed symbol? _)
|
|
(make-check-typed string? _)
|
|
(make-check-typed vector? _)
|
|
(make-check-typed box? _)
|
|
(make-check-typed pair? _)
|
|
(make-check-typed procedure? _)
|
|
(make-check-typed eof-object? _)
|
|
(make-check-typed input-port? _)
|
|
(make-check-typed output-port? _)
|
|
(make-check-typed true-object? _)
|
|
(make-check-typed false-object? _)
|
|
(make-check-typed boolean? _)
|
|
(make-check-typed list? _)
|
|
(make-check-typed not _)
|
|
(make-check-typed eqv? _ _)
|
|
(make-check-typed eq? _ _)
|
|
(make-check-typed equal? _ _)
|
|
(make-check-typed cons _ _)
|
|
(make-check-selector car (x . _))
|
|
(make-check-selector cdr (_ . x))
|
|
(make-check-selector caar ((x . _) . _))
|
|
(make-check-selector cadr (_ x . _))
|
|
(make-check-selector cdar ((_ . x) . _))
|
|
(make-check-selector cddr (_ _ . x))
|
|
(make-check-selector caaar (((x . _) . _) . _))
|
|
(make-check-selector caadr (_ (x . _) . _))
|
|
(make-check-selector cadar ((_ x . _) . _))
|
|
(make-check-selector caddr (_ _ x . _))
|
|
(make-check-selector cdaar (((_ . x) . _) . _))
|
|
(make-check-selector cdadr (_ (_ . x) . _))
|
|
(make-check-selector cddar ((_ _ . x) . _))
|
|
(make-check-selector cdddr (_ _ _ . x))
|
|
(make-check-selector
|
|
caaaar
|
|
((((x . _) . _) . _) . _))
|
|
(make-check-selector
|
|
caaadr
|
|
(_ ((x . _) . _) . _))
|
|
(make-check-selector
|
|
caadar
|
|
((_ (x . _) . _) . _))
|
|
(make-check-selector caaddr (_ _ (x . _) . _))
|
|
(make-check-selector
|
|
cadaar
|
|
(((_ x . _) . _) . _))
|
|
(make-check-selector cadadr (_ (_ x . _) . _))
|
|
(make-check-selector caddar ((_ _ x . _) . _))
|
|
(make-check-selector cadddr (_ _ _ x . _))
|
|
(make-check-selector
|
|
cdaaar
|
|
((((_ . x) . _) . _) . _))
|
|
(make-check-selector
|
|
cdaadr
|
|
(_ ((_ . x) . _) . _))
|
|
(make-check-selector
|
|
cdadar
|
|
((_ (_ . x) . _) . _))
|
|
(make-check-selector cdaddr (_ _ (_ . x) . _))
|
|
(make-check-selector
|
|
cddaar
|
|
(((_ _ . x) . _) . _))
|
|
(make-check-selector cddadr (_ (_ _ . x) . _))
|
|
(make-check-selector cdddar ((_ _ _ . x) . _))
|
|
(make-check-selector cddddr (_ _ _ _ . x))
|
|
(make-check-typed set-car! pair? _)
|
|
(make-check-typed set-cdr! pair? _)
|
|
(defmacro
|
|
check-list
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(apply list a)))
|
|
(make-check-typed length list?)
|
|
(defmacro
|
|
check-append
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(let loop ((b a))
|
|
(match b
|
|
(() #t)
|
|
((l) #t)
|
|
(((? list?) . y) (loop y))
|
|
(_ (st:failure
|
|
(cons 'check-append ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(apply append a)))
|
|
(make-check-typed reverse list?)
|
|
(make-check-typed list-tail list? number?)
|
|
(make-check-typed list-ref list? number?)
|
|
(make-check-typed memq _ list?)
|
|
(make-check-typed memv _ list?)
|
|
(make-check-typed member _ list?)
|
|
(defmacro
|
|
check-assq
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (= 2 (length a))
|
|
(list? (cadr a))
|
|
(andmap pair? (cadr a)))
|
|
(assq (car a) (cadr a))
|
|
(st:failure
|
|
(cons 'check-assq ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-assv
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (= 2 (length a))
|
|
(list? (cadr a))
|
|
(andmap pair? (cadr a)))
|
|
(assv (car a) (cadr a))
|
|
(st:failure
|
|
(cons 'check-assv ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-assoc
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (= 2 (length a))
|
|
(list? (cadr a))
|
|
(andmap pair? (cadr a)))
|
|
(assoc (car a) (cadr a))
|
|
(st:failure
|
|
(cons 'check-assoc ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed symbol->string symbol?)
|
|
(make-check-typed string->symbol string?)
|
|
(make-check-typed complex? _)
|
|
(make-check-typed real? _)
|
|
(make-check-typed rational? _)
|
|
(make-check-typed integer? _)
|
|
(make-check-typed exact? number?)
|
|
(make-check-typed inexact? number?)
|
|
(defmacro
|
|
check-=
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a)) (andmap number? a))
|
|
(apply = a)
|
|
(st:failure
|
|
(cons 'check-= ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-<
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a)) (andmap number? a))
|
|
(apply < a)
|
|
(st:failure
|
|
(cons 'check-< ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check->
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a)) (andmap number? a))
|
|
(apply > a)
|
|
(st:failure
|
|
(cons 'check-> ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-<=
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a)) (andmap number? a))
|
|
(apply <= a)
|
|
(st:failure
|
|
(cons 'check-<= ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check->=
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a)) (andmap number? a))
|
|
(apply >= a)
|
|
(st:failure
|
|
(cons 'check->= ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed zero? number?)
|
|
(make-check-typed positive? number?)
|
|
(make-check-typed negative? number?)
|
|
(make-check-typed odd? number?)
|
|
(make-check-typed even? number?)
|
|
(defmacro
|
|
check-max
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 1 (length a)) (andmap number? a))
|
|
(apply max a)
|
|
(st:failure
|
|
(cons 'check-max ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-min
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 1 (length a)) (andmap number? a))
|
|
(apply min a)
|
|
(st:failure
|
|
(cons 'check-min ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-+
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (andmap number? a)
|
|
(apply + a)
|
|
(st:failure
|
|
(cons 'check-+ ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-*
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (andmap number? a)
|
|
(apply * a)
|
|
(st:failure
|
|
(cons 'check-* ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check--
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 1 (length a)) (andmap number? a))
|
|
(apply - a)
|
|
(st:failure
|
|
(cons 'check-- ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-/
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 1 (length a)) (andmap number? a))
|
|
(apply / a)
|
|
(st:failure
|
|
(cons 'check-/ ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed abs number?)
|
|
(make-check-typed quotient number? number?)
|
|
(make-check-typed remainder number? number?)
|
|
(make-check-typed modulo number? number?)
|
|
(defmacro
|
|
check-gcd
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (andmap number? a)
|
|
(apply gcd a)
|
|
(st:failure
|
|
(cons 'check-gcd ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-lcm
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (andmap number? a)
|
|
(apply lcm a)
|
|
(st:failure
|
|
(cons 'check-lcm ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed numerator number?)
|
|
(make-check-typed denominator number?)
|
|
(make-check-typed floor number?)
|
|
(make-check-typed ceiling number?)
|
|
(make-check-typed truncate number?)
|
|
(make-check-typed round number?)
|
|
(make-check-typed rationalize number? number?)
|
|
(make-check-typed exp number?)
|
|
(make-check-typed log number?)
|
|
(make-check-typed sin number?)
|
|
(make-check-typed cos number?)
|
|
(make-check-typed tan number?)
|
|
(make-check-typed asin number?)
|
|
(make-check-typed acos number?)
|
|
(defmacro
|
|
check-atan
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (andmap number? a)
|
|
(pair? a)
|
|
(>= 2 (length a)))
|
|
(apply atan a)
|
|
(st:failure
|
|
(cons 'check-atan ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed sqrt number?)
|
|
(make-check-typed expt number? number?)
|
|
(make-check-typed
|
|
make-rectangular
|
|
number?
|
|
number?)
|
|
(make-check-typed make-polar number? number?)
|
|
(make-check-typed real-part number?)
|
|
(make-check-typed imag-part number?)
|
|
(make-check-typed magnitude number?)
|
|
(make-check-typed angle number?)
|
|
(make-check-typed exact->inexact number?)
|
|
(make-check-typed inexact->exact number?)
|
|
(defmacro
|
|
check-number->string
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (andmap number? a)
|
|
(pair? a)
|
|
(>= 2 (length a)))
|
|
(apply number->string a)
|
|
(st:failure
|
|
(cons 'check-number->string ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-string->number
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (pair? a)
|
|
(string? (car a))
|
|
(>= 2 (length a))
|
|
(or (null? (cdr a)) (number? (cadr a))))
|
|
(apply string->number a)
|
|
(st:failure
|
|
(cons 'check-string->number ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed char=? char? char?)
|
|
(make-check-typed char<? char? char?)
|
|
(make-check-typed char>? char? char?)
|
|
(make-check-typed char<=? char? char?)
|
|
(make-check-typed char>=? char? char?)
|
|
(make-check-typed char-ci=? char? char?)
|
|
(make-check-typed char-ci<? char? char?)
|
|
(make-check-typed char-ci>? char? char?)
|
|
(make-check-typed char-ci<=? char? char?)
|
|
(make-check-typed char-ci>=? char? char?)
|
|
(make-check-typed char-alphabetic? char?)
|
|
(make-check-typed char-numeric? char?)
|
|
(make-check-typed char-whitespace? char?)
|
|
(make-check-typed char-upper-case? char?)
|
|
(make-check-typed char-lower-case? char?)
|
|
(make-check-typed char->integer char?)
|
|
(make-check-typed integer->char number?)
|
|
(make-check-typed char-upcase char?)
|
|
(make-check-typed char-downcase char?)
|
|
(defmacro
|
|
check-make-string
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (pair? a)
|
|
(number? (car a))
|
|
(>= 2 (length a))
|
|
(or (null? (cdr a)) (char? (cadr a))))
|
|
(apply make-string a)
|
|
(st:failure
|
|
(cons 'check-make-string ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-string
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (andmap char? a)
|
|
(apply string a)
|
|
(st:failure
|
|
(cons 'check-string ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed string-length string?)
|
|
(make-check-typed string-ref string? number?)
|
|
(make-check-typed
|
|
string-set!
|
|
string?
|
|
number?
|
|
char?)
|
|
(make-check-typed string=? string? string?)
|
|
(make-check-typed string<? string? string?)
|
|
(make-check-typed string>? string? string?)
|
|
(make-check-typed string<=? string? string?)
|
|
(make-check-typed string>=? string? string?)
|
|
(make-check-typed string-ci=? string? string?)
|
|
(make-check-typed string-ci<? string? string?)
|
|
(make-check-typed string-ci>? string? string?)
|
|
(make-check-typed string-ci<=? string? string?)
|
|
(make-check-typed string-ci>=? string? string?)
|
|
(make-check-typed
|
|
substring
|
|
string?
|
|
number?
|
|
number?)
|
|
(defmacro
|
|
check-string-append
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (andmap string? a)
|
|
(apply string-append a)
|
|
(st:failure
|
|
(cons 'check-string-append ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed string->list string?)
|
|
(defmacro
|
|
check-list->string
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (= 1 (length a))
|
|
(list? (car a))
|
|
(andmap char? (car a)))
|
|
(list->string (car a))
|
|
(st:failure
|
|
(cons 'check-list->string ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed string-copy string?)
|
|
(make-check-typed string-fill! string? char?)
|
|
(make-check-typed make-vector number? _)
|
|
(defmacro
|
|
check-vector
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(apply vector a)))
|
|
(make-check-typed vector-length vector?)
|
|
(make-check-typed vector-ref vector? number?)
|
|
(make-check-typed vector-set! vector? number? _)
|
|
(make-check-typed vector->list vector?)
|
|
(make-check-typed list->vector list?)
|
|
(make-check-typed vector-fill! vector? _)
|
|
(defmacro
|
|
check-apply
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (pair? a)
|
|
(let loop ((arg (cdr a)))
|
|
(match arg
|
|
(((? list?)) (apply apply a))
|
|
((_ . y) (loop y))
|
|
(_ (st:failure
|
|
(cons 'check-apply ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(st:failure
|
|
`(check-apply ,@id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-map
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a))
|
|
(procedure? (car a))
|
|
(andmap list? (cdr a)))
|
|
(apply map a)
|
|
(st:failure
|
|
(cons 'check-map ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-for-each
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (<= 2 (length a))
|
|
(procedure? (car a))
|
|
(andmap list? (cdr a)))
|
|
(apply for-each a)
|
|
(st:failure
|
|
(cons 'check-for-each ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed force procedure?)
|
|
(defmacro
|
|
check-call-with-current-continuation
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (= 1 (length a)) (procedure? (car a)))
|
|
(call-with-current-continuation
|
|
(lambda (k)
|
|
((car a) (check-lambda (continuation) (x) (k x)))))
|
|
(st:failure
|
|
(cons 'check-call-with-current-continuation ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed
|
|
call-with-input-file
|
|
string?
|
|
procedure?)
|
|
(make-check-typed
|
|
call-with-output-file
|
|
string?
|
|
procedure?)
|
|
(make-check-typed input-port? _)
|
|
(make-check-typed output-port? _)
|
|
(make-check-typed current-input-port)
|
|
(make-check-typed current-output-port)
|
|
(make-check-typed
|
|
with-input-from-file
|
|
string?
|
|
procedure?)
|
|
(make-check-typed
|
|
with-output-to-file
|
|
string?
|
|
procedure?)
|
|
(make-check-typed open-input-file string?)
|
|
(make-check-typed open-output-file string?)
|
|
(make-check-typed close-input-port input-port?)
|
|
(make-check-typed close-output-port output-port?)
|
|
(defmacro
|
|
check-read
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (or (null? a)
|
|
(and (= 1 (length a)) (input-port? (car a))))
|
|
(apply read a)
|
|
(st:failure
|
|
(cons 'check-read ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-read-char
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (or (null? a)
|
|
(and (= 1 (length a)) (input-port? (car a))))
|
|
(apply read-char a)
|
|
(st:failure
|
|
(cons 'check-read-char ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-peek-char
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (or (null? a)
|
|
(and (= 1 (length a)) (input-port? (car a))))
|
|
(apply peek-char a)
|
|
(st:failure
|
|
(cons 'check-peek-char ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-char-ready?
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (or (null? a)
|
|
(and (= 1 (length a)) (input-port? (car a))))
|
|
(apply char-ready? a)
|
|
(st:failure
|
|
(cons 'check-char-ready? ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-write
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (pair? a)
|
|
(or (null? (cdr a)) (output-port? (cadr a))))
|
|
(apply write a)
|
|
(st:failure
|
|
(cons 'check-write ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-display
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (pair? a)
|
|
(or (null? (cdr a)) (output-port? (cadr a))))
|
|
(apply display a)
|
|
(st:failure
|
|
(cons 'check-display ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-newline
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (or (null? a) (output-port? (car a)))
|
|
(apply newline a)
|
|
(st:failure
|
|
(cons 'check-newline ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-write-char
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (pair? a)
|
|
(char? (car a))
|
|
(or (null? (cdr a)) (output-port? (cadr a))))
|
|
(apply write-char a)
|
|
(st:failure
|
|
(cons 'check-write-char ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed load string?)
|
|
(make-check-typed transcript-on string?)
|
|
(make-check-typed transcript-off)
|
|
(defmacro
|
|
check-symbol-append
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(apply symbol-append a)))
|
|
(make-check-typed box _)
|
|
(make-check-typed unbox box?)
|
|
(make-check-typed set-box! box? _)
|
|
(make-check-typed void)
|
|
(make-check-typed make-module _)
|
|
(defmacro
|
|
check-match:error
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (pair? a)
|
|
(apply match:error a)
|
|
(st:failure
|
|
(cons 'check-match:error ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed should-never-reach symbol?)
|
|
(defmacro
|
|
check-make-cvector
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(if (and (pair? a)
|
|
(number? (car a))
|
|
(= 2 (length a)))
|
|
(apply make-cvector a)
|
|
(st:failure
|
|
(cons 'check-make-cvector ',id)
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(defmacro
|
|
check-cvector
|
|
id
|
|
`(lambda a
|
|
(check-increment-counter ,(car id))
|
|
(apply cvector a)))
|
|
(make-check-typed cvector-length cvector?)
|
|
(make-check-typed cvector-ref cvector? number?)
|
|
(make-check-typed cvector->list cvector?)
|
|
(make-check-typed list->cvector list?)
|
|
(defmacro
|
|
check-define-const-structure
|
|
args
|
|
(let ((field?
|
|
(lambda (x)
|
|
(or (symbol? x)
|
|
(and (pair? x)
|
|
(equal? (car x) '!)
|
|
(pair? (cdr x))
|
|
(symbol? (cadr x))
|
|
(null? (cddr x))))))
|
|
(arg-name
|
|
(lambda (x) (if (symbol? x) x (cadr x))))
|
|
(with-mutator? (lambda (x) (not (symbol? x)))))
|
|
(match args
|
|
((((? symbol? name) (? field? id1) ...))
|
|
(let ((constructor (symbol-append 'make- name))
|
|
(check-constructor
|
|
(symbol-append 'check-make- name))
|
|
(predicate (symbol-append name '?))
|
|
(access
|
|
(let loop ((l id1))
|
|
(cond ((null? l) '())
|
|
((eq? '_ (arg-name (car l))) (loop (cdr l)))
|
|
(else
|
|
(cons (symbol-append name '- (arg-name (car l)))
|
|
(loop (cdr l)))))))
|
|
(assign
|
|
(let loop ((l id1))
|
|
(cond ((null? l) '())
|
|
((eq? '_ (arg-name (car l))) (loop (cdr l)))
|
|
((not (with-mutator? (car l))) (loop (cdr l)))
|
|
(else
|
|
(cons (symbol-append
|
|
'set-
|
|
name
|
|
'-
|
|
(arg-name (car l))
|
|
'!)
|
|
(loop (cdr l)))))))
|
|
(nargs (length id1)))
|
|
`(begin
|
|
(define-const-structure (,name ,@id1) ())
|
|
(defmacro
|
|
,check-constructor
|
|
id
|
|
(lambda a
|
|
(check-increment-counter (,'unquote (car id)))
|
|
(if (= ,nargs (length a))
|
|
(apply ,constructor a)
|
|
(st:failure
|
|
(cons ',check-constructor '(,'unquote id))
|
|
"invalid arguments: ~a"
|
|
a))))
|
|
(make-check-typed ,predicate _)
|
|
,@(map (lambda (a) `(make-check-typed ,a ,predicate))
|
|
access)
|
|
,@(map (lambda (a) `(make-check-typed ,a ,predicate _))
|
|
assign))))
|
|
(x (st:failure
|
|
`(check-define-const-structure ,@x)
|
|
"syntax error")))))
|
|
(if (equal? '(match 1) (macroexpand-1 '(match 1)))
|
|
(load "/home/wright/scheme/match/match-slib.scm"))
|
|
(define sprintf
|
|
(lambda args (apply format #f args)))
|
|
(define printf
|
|
(lambda args (apply format #t args)))
|
|
(define disaster
|
|
(lambda (context fmt . args)
|
|
(slib:error
|
|
(apply sprintf
|
|
(string-append "in ~a: " fmt)
|
|
context
|
|
args))))
|
|
(define use-error
|
|
(lambda (fmt . args)
|
|
(slib:error (apply sprintf fmt args))))
|
|
(define syntax-err
|
|
(lambda (context fmt . args)
|
|
(newline)
|
|
(if context (pretty-print context))
|
|
(slib:error
|
|
(apply sprintf
|
|
(string-append "in syntax: " fmt)
|
|
args))))
|
|
(define flush-output force-output)
|
|
(define print-context
|
|
(lambda (obj depth)
|
|
(pretty-print
|
|
(recur loop
|
|
((obj obj) (n 0))
|
|
(if (pair? obj)
|
|
(if (< n depth)
|
|
(cons (loop (car obj) (+ 1 n))
|
|
(loop (cdr obj) n))
|
|
'(...))
|
|
obj)))))
|
|
(define *box-tag* (gensym))
|
|
(define box (lambda (a) (cons *box-tag* a)))
|
|
(define box?
|
|
(lambda (b)
|
|
(and (pair? b) (eq? (car b) *box-tag*))))
|
|
(define unbox cdr)
|
|
(define box-1 cdr)
|
|
(define set-box! set-cdr!)
|
|
(define sort-list sort)
|
|
(define expand-once-if-macro
|
|
(lambda (e)
|
|
(and (macro? (car e)) (macroexpand-1 e))))
|
|
(define ormap
|
|
(lambda (f . lists)
|
|
(if (null? (car lists))
|
|
(or)
|
|
(or (apply f (map car lists))
|
|
(apply ormap f (map cdr lists))))))
|
|
(define call/cc call-with-current-continuation)
|
|
(define (cpu-time) 0)
|
|
(define (pretty-print x) (display x) (newline))
|
|
(define clock-granularity 1.0e-3)
|
|
(define set-vector! vector-set!)
|
|
(define set-string! string-set!)
|
|
(define maplr
|
|
(lambda (f l)
|
|
(match l
|
|
(() '())
|
|
((x . y) (let ((v (f x))) (cons v (maplr f y)))))))
|
|
(define maprl
|
|
(lambda (f l)
|
|
(match l
|
|
(() '())
|
|
((x . y) (let ((v (maprl f y))) (cons (f x) v))))))
|
|
(define foldl
|
|
(lambda (f i l)
|
|
(recur loop
|
|
((l l) (acc i))
|
|
(match l (() acc) ((x . y) (loop y (f x acc)))))))
|
|
(define foldr
|
|
(lambda (f i l)
|
|
(recur loop
|
|
((l l))
|
|
(match l (() i) ((x . y) (f x (loop y)))))))
|
|
(define filter
|
|
(lambda (p l)
|
|
(match l
|
|
(() '())
|
|
((x . y)
|
|
(if (p x) (cons x (filter p y)) (filter p y))))))
|
|
(define filter-map
|
|
(lambda (p l)
|
|
(match l
|
|
(() '())
|
|
((x . y)
|
|
(match (p x)
|
|
(#f (filter-map p y))
|
|
(x (cons x (filter-map p y))))))))
|
|
(define rac
|
|
(lambda (l)
|
|
(match l ((last) last) ((_ . rest) (rac rest)))))
|
|
(define rdc
|
|
(lambda (l)
|
|
(match l
|
|
((_) '())
|
|
((x . rest) (cons x (rdc rest))))))
|
|
(define map-with-n
|
|
(lambda (f l)
|
|
(recur loop
|
|
((l l) (n 0))
|
|
(match l
|
|
(() '())
|
|
((x . y)
|
|
(let ((v (f x n))) (cons v (loop y (+ 1 n)))))))))
|
|
(define readfile
|
|
(lambda (f)
|
|
(with-input-from-file
|
|
f
|
|
(letrec ((rf (lambda ()
|
|
(match (read)
|
|
((? eof-object?) '())
|
|
(sexp (cons sexp (rf)))))))
|
|
rf))))
|
|
(define map2
|
|
(lambda (f a b)
|
|
(match (cons a b)
|
|
((()) '())
|
|
(((ax . ay) bx . by)
|
|
(let ((v (f ax bx))) (cons v (map2 f ay by))))
|
|
(else (error 'map2 "lists differ in length")))))
|
|
(define for-each2
|
|
(lambda (f a b)
|
|
(match (cons a b)
|
|
((()) (void))
|
|
(((ax . ay) bx . by)
|
|
(f ax bx)
|
|
(for-each2 f ay by))
|
|
(else (error 'for-each2 "lists differ in length")))))
|
|
(define andmap2
|
|
(lambda (f a b)
|
|
(match (cons a b)
|
|
((()) (and))
|
|
(((ax) bx) (f ax bx))
|
|
(((ax . ay) bx . by)
|
|
(and (f ax bx) (andmap2 f ay by)))
|
|
(else (error 'andmap2 "lists differ in length")))))
|
|
(define ormap2
|
|
(lambda (f a b)
|
|
(match (cons a b)
|
|
((()) (or))
|
|
(((ax) bx) (f ax bx))
|
|
(((ax . ay) bx . by)
|
|
(or (f ax bx) (ormap2 f ay by)))
|
|
(else (error 'ormap2 "lists differ in length")))))
|
|
(define empty-set '())
|
|
(define empty-set? null?)
|
|
(define set (lambda l (list->set l)))
|
|
(define list->set
|
|
(match-lambda
|
|
(() '())
|
|
((x . y)
|
|
(if (memq x y)
|
|
(list->set y)
|
|
(cons x (list->set y))))))
|
|
(define element-of?
|
|
(lambda (x set) (and (memq x set) #t)))
|
|
(define cardinality length)
|
|
(define set<=
|
|
(lambda (a b)
|
|
(foldr (lambda (a-elt acc) (and acc (memq a-elt b) #t))
|
|
(and)
|
|
a)))
|
|
(define set-eq?
|
|
(lambda (a b)
|
|
(and (= (cardinality a) (cardinality b))
|
|
(set<= a b))))
|
|
(define union2
|
|
(lambda (a b)
|
|
(if (null? b)
|
|
a
|
|
(foldr (lambda (x b) (if (memq x b) b (cons x b)))
|
|
b
|
|
a))))
|
|
(define union (lambda l (foldr union2 '() l)))
|
|
(define setdiff2
|
|
(lambda (a b)
|
|
(if (null? b)
|
|
a
|
|
(foldr (lambda (x c) (if (memq x b) c (cons x c)))
|
|
'()
|
|
a))))
|
|
(define setdiff
|
|
(lambda l
|
|
(if (null? l)
|
|
'()
|
|
(setdiff2 (car l) (foldr union2 '() (cdr l))))))
|
|
(define intersect2
|
|
(lambda (a b)
|
|
(if (null? b)
|
|
a
|
|
(foldr (lambda (x c) (if (memq x b) (cons x c) c))
|
|
'()
|
|
a))))
|
|
(define intersect
|
|
(lambda l
|
|
(if (null? l) '() (foldl intersect2 (car l) l))))
|
|
(define-const-structure (some _))
|
|
(define-const-structure (none))
|
|
(define none (make-none))
|
|
(define some make-some)
|
|
(define-const-structure (and exps))
|
|
(define-const-structure (app exp exps))
|
|
(define-const-structure (begin exps))
|
|
(define-const-structure (const val pred))
|
|
(define-const-structure (if exp1 exp2 exp3))
|
|
(define-const-structure (lam names body))
|
|
(define-const-structure (let binds body))
|
|
(define-const-structure (let* binds body))
|
|
(define-const-structure (letr binds body))
|
|
(define-const-structure (or exps))
|
|
(define-const-structure (prim name))
|
|
(define-const-structure (delay exp))
|
|
(define-const-structure (set! (! name) exp))
|
|
(define-const-structure (var (! name)))
|
|
(define-const-structure (vlam names name body))
|
|
(define-const-structure (match exp mclauses))
|
|
(define-const-structure (record binds))
|
|
(define-const-structure (field name exp))
|
|
(define-const-structure (cast type exp))
|
|
(define-const-structure (body defs exps))
|
|
(define-const-structure (bind name exp))
|
|
(define-const-structure (mclause pat body fail))
|
|
(define-const-structure (pvar name))
|
|
(define-const-structure (pany))
|
|
(define-const-structure (pelse))
|
|
(define-const-structure (pconst name pred))
|
|
(define-const-structure (pobj name pats))
|
|
(define-const-structure (ppred name))
|
|
(define-const-structure (pand pats))
|
|
(define-const-structure (pnot pat))
|
|
(define-const-structure (define name (! exp)))
|
|
(define-const-structure
|
|
(defstruct
|
|
tag
|
|
args
|
|
make
|
|
pred
|
|
get
|
|
set
|
|
getn
|
|
setn
|
|
mutable))
|
|
(define-const-structure (datatype _))
|
|
(define-const-structure
|
|
(variant con pred arg-types))
|
|
(define-structure
|
|
(name name
|
|
ty
|
|
timestamp
|
|
occ
|
|
mutated
|
|
gdef
|
|
primitive
|
|
struct
|
|
pure
|
|
predicate
|
|
variant
|
|
selector))
|
|
(define-structure (type ty exp))
|
|
(define-const-structure (shape _ _))
|
|
(define-const-structure (check _ _))
|
|
(define parse-def
|
|
(lambda (def)
|
|
(let ((parse-name
|
|
(match-lambda
|
|
((? symbol? s)
|
|
(if (keyword? s)
|
|
(syntax-err def "invalid use of keyword ~a" s)
|
|
s))
|
|
(n (syntax-err def "invalid variable at ~a" n)))))
|
|
(match def
|
|
(('extend-syntax ((? symbol? name) . _) . _)
|
|
(printf
|
|
"Note: installing but _not_ checking (extend-syntax (~a) ...)~%"
|
|
name)
|
|
(eval def)
|
|
'())
|
|
(('extend-syntax . _)
|
|
(syntax-err def "invalid syntax"))
|
|
(('defmacro (? symbol? name) . _)
|
|
(printf
|
|
"Note: installing but _not_ checking (defmacro ~a ...)~%"
|
|
name)
|
|
(eval def)
|
|
'())
|
|
(('defmacro . _)
|
|
(syntax-err def "invalid syntax"))
|
|
(('define (? symbol? n) e)
|
|
(list (make-define (parse-name n) (parse-exp e))))
|
|
(('define (n . args) . body)
|
|
(list (make-define
|
|
(parse-name n)
|
|
(parse-exp `(lambda ,args ,@body)))))
|
|
(('define . _) (syntax-err def "at define"))
|
|
(('begin . defs)
|
|
(foldr append '() (smap parse-def defs)))
|
|
(('define-structure (n . args))
|
|
(parse-def `(define-structure (,n ,@args) ())))
|
|
(('define-structure (n . args) inits)
|
|
(let ((m-args (smap (lambda (x) `(! ,x)) args))
|
|
(m-inits
|
|
(smap (match-lambda
|
|
((x e) `((! ,x) ,e))
|
|
(_ (syntax-err
|
|
def
|
|
"invalid structure initializer")))
|
|
inits)))
|
|
(parse-def
|
|
`(define-const-structure (,n ,@m-args) ,m-inits))))
|
|
(('define-const-structure ((? symbol? n) . args))
|
|
(parse-def
|
|
`(define-const-structure (,n ,@args) ())))
|
|
(('define-const-structure
|
|
((? symbol? n) . args)
|
|
())
|
|
(letrec ((smap-with-n
|
|
(lambda (f l)
|
|
(recur loop
|
|
((l l) (n 0))
|
|
(match l
|
|
(() '())
|
|
((x . y)
|
|
(let ((v (f x n)))
|
|
(cons v (loop y (+ 1 n)))))
|
|
(_ (syntax-err l "invalid list"))))))
|
|
(parse-arg
|
|
(lambda (a index)
|
|
(match a
|
|
(('! '_)
|
|
(list none
|
|
none
|
|
(some (symbol-append
|
|
n
|
|
'-
|
|
(+ index 1)))
|
|
(some (symbol-append
|
|
'set-
|
|
n
|
|
'-
|
|
(+ index 1)
|
|
'!))
|
|
#t))
|
|
(('! a)
|
|
(let ((a (parse-name a)))
|
|
(list (some (symbol-append n '- a))
|
|
(some (symbol-append
|
|
'set-
|
|
n
|
|
'-
|
|
a
|
|
'!))
|
|
(some (symbol-append
|
|
n
|
|
'-
|
|
(+ index 1)))
|
|
(some (symbol-append
|
|
'set-
|
|
n
|
|
'-
|
|
(+ index 1)
|
|
'!))
|
|
#t)))
|
|
('_
|
|
(list none
|
|
none
|
|
(some (symbol-append
|
|
n
|
|
'-
|
|
(+ index 1)))
|
|
none
|
|
#f))
|
|
(a (let ((a (parse-name a)))
|
|
(list (some (symbol-append n '- a))
|
|
none
|
|
(some (symbol-append
|
|
n
|
|
'-
|
|
(+ index 1)))
|
|
none
|
|
#f)))))))
|
|
(let* ((arg-info (smap-with-n parse-arg args))
|
|
(get (map car arg-info))
|
|
(set (map cadr arg-info))
|
|
(getn (map caddr arg-info))
|
|
(setn (map cadddr arg-info))
|
|
(mutable
|
|
(map (lambda (x) (car (cddddr x))) arg-info)))
|
|
(list (make-defstruct
|
|
n
|
|
(cons n args)
|
|
(symbol-append 'make- n)
|
|
(symbol-append n '?)
|
|
get
|
|
set
|
|
getn
|
|
setn
|
|
mutable)))))
|
|
(('define-const-structure
|
|
((? symbol? n) . args)
|
|
inits)
|
|
(syntax-err
|
|
def
|
|
"sorry, structure initializers are not supported"))
|
|
(('datatype . d)
|
|
(let* ((parse-variant
|
|
(match-lambda
|
|
(((? symbol? con) ? list? args)
|
|
(let ((n (parse-name con)))
|
|
(make-variant
|
|
(symbol-append 'make- n)
|
|
(symbol-append n '?)
|
|
(cons con args))))
|
|
(_ (syntax-err def "invalid datatype syntax"))))
|
|
(parse-dt
|
|
(match-lambda
|
|
(((? symbol? type) . variants)
|
|
(cons (list (parse-name type))
|
|
(smap parse-variant variants)))
|
|
((((? symbol? type) ? list? targs) . variants)
|
|
(cons (cons (parse-name type)
|
|
(smap parse-name targs))
|
|
(smap parse-variant variants)))
|
|
(_ (syntax-err def "invalid datatype syntax")))))
|
|
(list (make-datatype (smap parse-dt d)))))
|
|
(((? symbol? k) . _)
|
|
(cond ((and (not (keyword? k))
|
|
(expand-once-if-macro def))
|
|
=>
|
|
parse-def)
|
|
(else (list (make-define #f (parse-exp def))))))
|
|
(_ (list (make-define #f (parse-exp def))))))))
|
|
(define keep-match #t)
|
|
(define parse-exp
|
|
(lambda (expression)
|
|
(letrec ((n-primitive (string->symbol "#primitive"))
|
|
(parse-exp
|
|
(match-lambda
|
|
(('quote (? symbol? s)) (make-const s 'symbol?))
|
|
((and m ('quote _)) (parse-exp (quote-tf m)))
|
|
((and m ('quasiquote _))
|
|
(parse-exp (quasiquote-tf m)))
|
|
((and m (? box?)) (parse-exp (quote-tf m)))
|
|
((and m (? vector?)) (parse-exp (quote-tf m)))
|
|
((and m ('cond . _)) (parse-exp (cond-tf m)))
|
|
((and m ('case . _)) (parse-exp (case-tf m)))
|
|
((and m ('do . _)) (parse-exp (do-tf m)))
|
|
((? symbol? s) (make-var (parse-name s)))
|
|
(#t (make-const #t 'true-object?))
|
|
(#f (make-const #f 'false-object?))
|
|
((? null? c) (make-const c 'null?))
|
|
((? number? c) (make-const c 'number?))
|
|
((? char? c) (make-const c 'char?))
|
|
((? string? c) (make-const c 'string?))
|
|
((': ty e1) (make-cast ty (parse-exp e1)))
|
|
((and exp ('record . bind))
|
|
(let ((bindings (smap parse-bind bind)))
|
|
(no-repeats (map bind-name bindings) exp)
|
|
(make-record bindings)))
|
|
((and exp ('field name e1))
|
|
(make-field (parse-name name) (parse-exp e1)))
|
|
((and exp ('match e clause0 . clauses))
|
|
(=> fail)
|
|
(if keep-match
|
|
(let* ((e2 (parse-exp e))
|
|
(parse-clause
|
|
(match-lambda
|
|
((p ('=> (? symbol? failsym)) . body)
|
|
(make-mclause
|
|
(parse-pat p expression)
|
|
(parse-body
|
|
`((let ((,failsym (lambda () (,failsym))))
|
|
,@body)))
|
|
failsym))
|
|
((p . body)
|
|
(make-mclause
|
|
(parse-pat p expression)
|
|
(parse-body body)
|
|
#f))
|
|
(_ (syntax-err exp "invalid match clause")))))
|
|
(make-match
|
|
e2
|
|
(smap parse-clause (cons clause0 clauses))))
|
|
(fail)))
|
|
((and exp ('lambda bind . body))
|
|
(recur loop
|
|
((b bind) (names '()))
|
|
(match b
|
|
((? symbol? n)
|
|
(let ((rest (parse-name n)))
|
|
(no-repeats (cons rest names) exp)
|
|
(make-vlam
|
|
(reverse names)
|
|
rest
|
|
(parse-body body))))
|
|
(()
|
|
(no-repeats names exp)
|
|
(make-lam (reverse names) (parse-body body)))
|
|
((n . x) (loop x (cons (parse-name n) names)))
|
|
(_ (syntax-err
|
|
exp
|
|
"invalid lambda expression")))))
|
|
(('if e1 e2 e3)
|
|
(make-if
|
|
(parse-exp e1)
|
|
(parse-exp e2)
|
|
(parse-exp e3)))
|
|
((and if-expr ('if e1 e2))
|
|
(printf "Note: one-armed if: ")
|
|
(print-context if-expr 2)
|
|
(make-if
|
|
(parse-exp e1)
|
|
(parse-exp e2)
|
|
(parse-exp '(void))))
|
|
(('delay e) (make-delay (parse-exp e)))
|
|
(('set! n e)
|
|
(make-set! (parse-name n) (parse-exp e)))
|
|
(('and . args) (make-and (smap parse-exp args)))
|
|
(('or . args) (make-or (smap parse-exp args)))
|
|
((and exp ('let (? symbol? n) bind . body))
|
|
(let* ((nb (parse-name n))
|
|
(bindings (smap parse-bind bind)))
|
|
(no-repeats (map bind-name bindings) exp)
|
|
(make-app
|
|
(make-letr
|
|
(list (make-bind
|
|
nb
|
|
(make-lam
|
|
(map bind-name bindings)
|
|
(parse-body body))))
|
|
(make-body '() (list (make-var nb))))
|
|
(map bind-exp bindings))))
|
|
((and exp ('let bind . body))
|
|
(let ((bindings (smap parse-bind bind)))
|
|
(no-repeats (map bind-name bindings) exp)
|
|
(make-let bindings (parse-body body))))
|
|
(('let* bind . body)
|
|
(make-let*
|
|
(smap parse-bind bind)
|
|
(parse-body body)))
|
|
((and exp ('letrec bind . body))
|
|
(let ((bindings (smap parse-bind bind)))
|
|
(no-repeats (map bind-name bindings) exp)
|
|
(make-letr bindings (parse-body body))))
|
|
(('begin e1 . rest)
|
|
(make-begin (smap parse-exp (cons e1 rest))))
|
|
(('define . _)
|
|
(syntax-err
|
|
expression
|
|
"invalid context for internal define"))
|
|
(('define-structure . _)
|
|
(syntax-err
|
|
expression
|
|
"invalid context for internal define-structure"))
|
|
(('define-const-structure . _)
|
|
(syntax-err
|
|
expression
|
|
"invalid context for internal define-const-structure"))
|
|
((and m (f . args))
|
|
(cond ((and (eq? f n-primitive)
|
|
(match args
|
|
(((? symbol? p)) (make-prim p))
|
|
(_ #f))))
|
|
((and (symbol? f)
|
|
(not (keyword? f))
|
|
(expand-once-if-macro m))
|
|
=>
|
|
parse-exp)
|
|
(else
|
|
(make-app (parse-exp f) (smap parse-exp args)))))
|
|
(x (syntax-err
|
|
expression
|
|
"invalid expression at ~a"
|
|
x))))
|
|
(parse-name
|
|
(match-lambda
|
|
((? symbol? s)
|
|
(when (keyword? s)
|
|
(syntax-err
|
|
expression
|
|
"invalid use of keyword ~a"
|
|
s))
|
|
s)
|
|
(n (syntax-err
|
|
expression
|
|
"invalid variable at ~a"
|
|
n))))
|
|
(parse-bind
|
|
(match-lambda
|
|
((x e) (make-bind (parse-name x) (parse-exp e)))
|
|
(b (syntax-err expression "invalid binding at ~a" b))))
|
|
(parse-body
|
|
(lambda (body)
|
|
(recur loop
|
|
((b body) (defs '()))
|
|
(match b
|
|
(((and d ('define . _)) . rest)
|
|
(loop rest (append defs (parse-def d))))
|
|
(((and d ('define-structure . _)) . rest)
|
|
(loop rest (append defs (parse-def d))))
|
|
(((and d ('define-const-structure . _)) . rest)
|
|
(loop rest (append defs (parse-def d))))
|
|
((('begin) . rest) (loop rest defs))
|
|
(((and beg ('begin ('define . _) . _)) . rest)
|
|
(loop rest (append defs (parse-def beg))))
|
|
(((and beg ('begin ('define-structure . _) . _))
|
|
.
|
|
rest)
|
|
(loop rest (append defs (parse-def beg))))
|
|
(((and beg
|
|
('begin
|
|
('define-const-structure . _)
|
|
.
|
|
_))
|
|
.
|
|
rest)
|
|
(loop rest (append defs (parse-def beg))))
|
|
((_ . _) (make-body defs (smap parse-exp b)))
|
|
(_ (syntax-err
|
|
expression
|
|
"invalid body at ~a"
|
|
b))))))
|
|
(no-repeats
|
|
(lambda (l exp)
|
|
(match l
|
|
(() #f)
|
|
((_) #f)
|
|
((x . l)
|
|
(if (memq x l)
|
|
(syntax-err exp "name ~a repeated" x)
|
|
(no-repeats l exp)))))))
|
|
(parse-exp expression))))
|
|
(define parse-pat
|
|
(lambda (pat expression)
|
|
(letrec ((parse-pat
|
|
(match-lambda
|
|
(#f (make-ppred 'false-object?))
|
|
(#t (make-ppred 'true-object?))
|
|
(() (make-ppred 'null?))
|
|
((? number? c) (make-pconst c 'number?))
|
|
((? char? c) (make-pconst c 'char?))
|
|
((? string? c) (make-pconst c 'string?))
|
|
(('quote x) (parse-quote x))
|
|
('_ (make-pany))
|
|
('else (make-pelse))
|
|
((? symbol? n) (make-pvar (parse-pname n)))
|
|
(('not . pats)
|
|
(syntax-err
|
|
expression
|
|
"not patterns are not supported"))
|
|
(('or . pats)
|
|
(syntax-err
|
|
expression
|
|
"or patterns are not supported"))
|
|
(('get! . pats)
|
|
(syntax-err
|
|
expression
|
|
"get! patterns are not supported"))
|
|
(('set! . pats)
|
|
(syntax-err
|
|
expression
|
|
"set! patterns are not supported"))
|
|
(('and . pats)
|
|
(let* ((pats (smap parse-pat pats))
|
|
(p (make-flat-pand pats))
|
|
(non-var?
|
|
(match-lambda
|
|
((? pvar?) #f)
|
|
((? pany?) #f)
|
|
(_ #t))))
|
|
(match p
|
|
(($ pand pats)
|
|
(when (< 1 (length (filter non-var? pats)))
|
|
(syntax-err
|
|
expression
|
|
"~a has conflicting subpatterns"
|
|
(ppat p))))
|
|
(_ #f))
|
|
p))
|
|
(('? (? symbol? pred) p)
|
|
(parse-pat `(and (? ,pred) ,p)))
|
|
(('? (? symbol? pred))
|
|
(if (keyword? pred)
|
|
(syntax-err
|
|
expression
|
|
"invalid use of keyword ~a"
|
|
pred)
|
|
(make-ppred pred)))
|
|
(('$ (? symbol? c) . args)
|
|
(if (memq c '(? _ $))
|
|
(syntax-err
|
|
expression
|
|
"invalid use of pattern keyword ~a"
|
|
c)
|
|
(make-pobj
|
|
(symbol-append c '?)
|
|
(smap parse-pat args))))
|
|
((? box? cb)
|
|
(make-pobj 'box? (list (parse-pat (unbox cb)))))
|
|
((x . y)
|
|
(make-pobj
|
|
'pair?
|
|
(list (parse-pat x) (parse-pat y))))
|
|
((? vector? v)
|
|
(make-pobj
|
|
'vector?
|
|
(map parse-pat (vector->list v))))
|
|
(m (syntax-err expression "invalid pattern at ~a" m))))
|
|
(parse-quote
|
|
(match-lambda
|
|
(#f (make-pobj 'false-object? '()))
|
|
(#t (make-pobj 'true-object? '()))
|
|
(() (make-pobj 'null? '()))
|
|
((? number? c) (make-pconst c 'number?))
|
|
((? char? c) (make-pconst c 'char?))
|
|
((? string? c) (make-pconst c 'string?))
|
|
((? symbol? s) (make-pconst s 'symbol?))
|
|
((? box? cb)
|
|
(make-pobj 'box? (list (parse-quote (unbox cb)))))
|
|
((x . y)
|
|
(make-pobj
|
|
'pair?
|
|
(list (parse-quote x) (parse-quote y))))
|
|
((? vector? v)
|
|
(make-pobj
|
|
'vector?
|
|
(map parse-quote (vector->list v))))
|
|
(m (syntax-err expression "invalid pattern at ~a" m))))
|
|
(parse-pname
|
|
(match-lambda
|
|
((? symbol? s)
|
|
(cond ((keyword? s)
|
|
(syntax-err
|
|
expression
|
|
"invalid use of keyword ~a"
|
|
s))
|
|
((memq s '(? _ else $ and or not set! get! ...))
|
|
(syntax-err
|
|
expression
|
|
"invalid use of pattern keyword ~a"
|
|
s))
|
|
(else s)))
|
|
(n (syntax-err
|
|
expression
|
|
"invalid pattern variable at ~a"
|
|
n)))))
|
|
(parse-pat pat))))
|
|
(define smap
|
|
(lambda (f l)
|
|
(match l
|
|
(() '())
|
|
((x . r) (let ((v (f x))) (cons v (smap f r))))
|
|
(_ (syntax-err l "invalid list")))))
|
|
(define primitive
|
|
(lambda (p)
|
|
(list (string->symbol "#primitive") p)))
|
|
(define keyword?
|
|
(lambda (s)
|
|
(or (memq s
|
|
'(=> and
|
|
begin
|
|
case
|
|
cond
|
|
do
|
|
define
|
|
delay
|
|
if
|
|
lambda
|
|
let
|
|
let*
|
|
letrec
|
|
or
|
|
quasiquote
|
|
quote
|
|
set!
|
|
unquote
|
|
unquote-splicing
|
|
define-structure
|
|
define-const-structure
|
|
record
|
|
field
|
|
:
|
|
datatype))
|
|
(and keep-match (eq? s 'match)))))
|
|
(define make-flat-pand
|
|
(lambda (pats)
|
|
(let* ((l (foldr (lambda (p plist)
|
|
(match p
|
|
(($ pand pats) (append pats plist))
|
|
(_ (cons p plist))))
|
|
'()
|
|
pats))
|
|
(concrete?
|
|
(match-lambda
|
|
((? pconst?) #t)
|
|
((? pobj?) #t)
|
|
((? ppred?) #t)
|
|
(_ #f)))
|
|
(sorted
|
|
(append
|
|
(filter concrete? l)
|
|
(filter (lambda (x) (not (concrete? x))) l))))
|
|
(match sorted ((p) p) (_ (make-pand sorted))))))
|
|
(define never-counter 0)
|
|
(define reinit-macros!
|
|
(lambda () (set! never-counter 0)))
|
|
(define cond-tf
|
|
(lambda (cond-expr)
|
|
(recur loop
|
|
((e (cdr cond-expr)))
|
|
(match e
|
|
(()
|
|
(begin
|
|
(set! never-counter (+ 1 never-counter))
|
|
`(,(primitive 'should-never-reach)
|
|
'(cond ,never-counter))))
|
|
((('else b1 . body)) `(begin ,b1 ,@body))
|
|
((('else . _) . _)
|
|
(syntax-err cond-expr "invalid cond expression"))
|
|
(((test '=> proc) . rest)
|
|
(let ((g (gensym)))
|
|
`(let ((,g ,test))
|
|
(if ,g (,proc ,g) ,(loop rest)))))
|
|
(((#t b1 . body)) `(begin ,b1 ,@body))
|
|
(((test) . rest) `(or ,test ,(loop rest)))
|
|
(((test . body) . rest)
|
|
`(if ,test (begin ,@body) ,(loop rest)))
|
|
(_ (syntax-err cond-expr "invalid cond expression"))))))
|
|
(define scheme-cond-tf
|
|
(lambda (cond-expr)
|
|
(recur loop
|
|
((e (cdr cond-expr)))
|
|
(match e
|
|
(() `(,(primitive 'void)))
|
|
((('else b1 . body)) `(begin ,b1 ,@body))
|
|
((('else . _) . _)
|
|
(syntax-err cond-expr "invalid cond expression"))
|
|
(((test '=> proc) . rest)
|
|
(let ((g (gensym)))
|
|
`(let ((,g ,test))
|
|
(if ,g (,proc ,g) ,(loop rest)))))
|
|
(((#t b1 . body)) `(begin ,b1 ,@body))
|
|
(((test) . rest) `(or ,test ,(loop rest)))
|
|
(((test . body) . rest)
|
|
`(if ,test (begin ,@body) ,(loop rest)))
|
|
(_ (syntax-err cond-expr "invalid cond expression"))))))
|
|
(define case-tf
|
|
(lambda (case-expr)
|
|
(recur loop
|
|
((e (cdr case-expr)))
|
|
(match e
|
|
((exp) `(begin ,exp (,(primitive 'void))))
|
|
((exp ('else b1 . body)) `(begin ,b1 ,@body))
|
|
((exp ('else . _) . _)
|
|
(syntax-err case-expr "invalid case expression"))
|
|
(((? symbol? exp)
|
|
((? list? test) b1 . body)
|
|
.
|
|
rest)
|
|
`(if (,(primitive 'memv) ,exp ',test)
|
|
(begin ,b1 ,@body)
|
|
,(loop (cons exp rest))))
|
|
(((? symbol? exp) (test b1 . body) . rest)
|
|
`(if (,(primitive 'memv) ,exp '(,test))
|
|
(begin ,b1 ,@body)
|
|
,(loop (cons exp rest))))
|
|
((exp . rest)
|
|
(if (not (symbol? exp))
|
|
(let ((g (gensym)))
|
|
`(let ((,g ,exp)) ,(loop (cons g rest))))
|
|
(syntax-err case-expr "invalid case expression")))
|
|
(_ (syntax-err case-expr "invalid case expression"))))))
|
|
(define conslimit 8)
|
|
(define quote-tf
|
|
(lambda (exp)
|
|
(letrec ((qloop (match-lambda
|
|
((? box? q)
|
|
`(,(primitive qbox) ,(qloop (unbox q))))
|
|
((? symbol? q) `',q)
|
|
((? null? q) q)
|
|
((? list? q)
|
|
(if (< (length q) conslimit)
|
|
`(,(primitive qcons)
|
|
,(qloop (car q))
|
|
,(qloop (cdr q)))
|
|
`(,(primitive qlist) ,@(map qloop q))))
|
|
((x . y)
|
|
`(,(primitive qcons) ,(qloop x) ,(qloop y)))
|
|
((? vector? q)
|
|
`(,(primitive qvector)
|
|
,@(map qloop (vector->list q))))
|
|
((? boolean? q) q)
|
|
((? number? q) q)
|
|
((? char? q) q)
|
|
((? string? q) q)
|
|
(q (syntax-err
|
|
exp
|
|
"invalid quote expression at ~a"
|
|
q)))))
|
|
(match exp
|
|
(('quote q) (qloop q))
|
|
((? vector? q) (qloop q))
|
|
((? box? q) (qloop q))))))
|
|
(define quasiquote-tf
|
|
(lambda (exp)
|
|
(letrec ((make-cons
|
|
(lambda (x y)
|
|
(cond ((null? y) `(,(primitive 'list) ,x))
|
|
((and (pair? y)
|
|
(equal? (car y) (primitive 'list)))
|
|
(cons (car y) (cons x (cdr y))))
|
|
(else `(,(primitive 'cons) ,x ,y)))))
|
|
(qloop (lambda (e n)
|
|
(match e
|
|
(('quasiquote e)
|
|
(make-cons 'quasiquote (qloop `(,e) (+ 1 n))))
|
|
(('unquote e)
|
|
(if (zero? n)
|
|
e
|
|
(make-cons 'unquote (qloop `(,e) (- n 1)))))
|
|
(('unquote-splicing e)
|
|
(if (zero? n)
|
|
e
|
|
(make-cons
|
|
'unquote-splicing
|
|
(qloop `(,e) (- n 1)))))
|
|
((('unquote-splicing e) . y)
|
|
(=> fail)
|
|
(if (zero? n)
|
|
(if (null? y)
|
|
e
|
|
`(,(primitive 'append) ,e ,(qloop y n)))
|
|
(fail)))
|
|
((? box? q)
|
|
`(,(primitive 'box) ,(qloop (unbox q) n)))
|
|
((? symbol? q)
|
|
(if (memq q
|
|
'(quasiquote unquote unquote-splicing))
|
|
(syntax-err
|
|
exp
|
|
"invalid use of ~a inside quasiquote"
|
|
q)
|
|
`',q))
|
|
((? null? q) q)
|
|
((x . y) (make-cons (qloop x n) (qloop y n)))
|
|
((? vector? q)
|
|
`(,(primitive 'vector)
|
|
,@(map (lambda (z) (qloop z n))
|
|
(vector->list q))))
|
|
((? boolean? q) q)
|
|
((? number? q) q)
|
|
((? char? q) q)
|
|
((? string? q) q)
|
|
(q (syntax-err
|
|
exp
|
|
"invalid quasiquote expression at ~a"
|
|
q))))))
|
|
(match exp (('quasiquote q) (qloop q 0))))))
|
|
(define do-tf
|
|
(lambda (do-expr)
|
|
(recur loop
|
|
((e (cdr do-expr)))
|
|
(match e
|
|
(((? list? vis) (e0 ? list? e1) ? list? c)
|
|
(if (andmap (match-lambda ((_ _ . _) #t) (_ #f)) vis)
|
|
(let* ((var (map car vis))
|
|
(init (map cadr vis))
|
|
(step (map cddr vis))
|
|
(step (map (lambda (v s)
|
|
(match s
|
|
(() v)
|
|
((e) e)
|
|
(_ (syntax-err
|
|
do-expr
|
|
"invalid do expression"))))
|
|
var
|
|
step)))
|
|
(let ((doloop (gensym)))
|
|
(match e1
|
|
(()
|
|
`(let ,doloop
|
|
,(map list var init)
|
|
(if (not ,e0)
|
|
(begin ,@c (,doloop ,@step) (void))
|
|
(void))))
|
|
((body0 ? list? body)
|
|
`(let ,doloop
|
|
,(map list var init)
|
|
(if ,e0
|
|
(begin ,body0 ,@body)
|
|
(begin ,@c (,doloop ,@step)))))
|
|
(_ (syntax-err
|
|
do-expr
|
|
"invalid do expression")))))
|
|
(syntax-err do-expr "invalid do expression")))
|
|
(_ (syntax-err do-expr "invalid do expression"))))))
|
|
(define empty-env '())
|
|
(define lookup
|
|
(lambda (env x)
|
|
(match (assq x env)
|
|
(#f (disaster 'lookup "no binding for ~a" x))
|
|
((_ . b) b))))
|
|
(define lookup?
|
|
(lambda (env x)
|
|
(match (assq x env) (#f #f) ((_ . b) b))))
|
|
(define bound?
|
|
(lambda (env x)
|
|
(match (assq x env) (#f #f) (_ #t))))
|
|
(define extend-env
|
|
(lambda (env x v) (cons (cons x v) env)))
|
|
(define extend-env*
|
|
(lambda (env xs vs)
|
|
(append (map2 cons xs vs) env)))
|
|
(define join-env
|
|
(lambda (env newenv) (append newenv env)))
|
|
(define populated #t)
|
|
(define pseudo #f)
|
|
(define global-error #f)
|
|
(define share #f)
|
|
(define matchst #f)
|
|
(define fullsharing #t)
|
|
(define dump-depths #f)
|
|
(define flags #t)
|
|
(define-structure
|
|
(c depth kind fsym pres args next))
|
|
(define-structure
|
|
(v depth kind name vis split inst))
|
|
(define-structure (ts type n-gen))
|
|
(define-structure (k name order args))
|
|
(define top (box 'top))
|
|
(define bot (box 'bot))
|
|
(define generic? (lambda (d) (< d 0)))
|
|
(define new-type
|
|
(lambda (s d)
|
|
(let ((t (box s)))
|
|
(vector-set!
|
|
types
|
|
d
|
|
(cons t (vector-ref types d)))
|
|
t)))
|
|
(define generate-counter
|
|
(lambda ()
|
|
(let ((n 0)) (lambda () (set! n (+ 1 n)) n))))
|
|
(define var-counter (generate-counter))
|
|
(define make-raw-tvar
|
|
(lambda (d k) (make-v d k var-counter #t #f #f)))
|
|
(define make-tvar
|
|
(lambda (d k) (new-type (make-raw-tvar d k) d)))
|
|
(define ord? (lambda (k) (eq? 'ord k)))
|
|
(define abs? (lambda (k) (eq? 'abs k)))
|
|
(define pre? (lambda (k) (eq? 'pre k)))
|
|
(define ord-depth 2)
|
|
(define depth ord-depth)
|
|
(define types (make-vector 16 '()))
|
|
(define reset-types!
|
|
(lambda ()
|
|
(set! depth ord-depth)
|
|
(set! types (make-vector 16 '()))))
|
|
(define push-level
|
|
(lambda ()
|
|
(set! depth (+ depth 1))
|
|
(when (< (vector-length types) (+ 1 depth))
|
|
(set! types
|
|
(let ((l (vector->list types)))
|
|
(list->vector
|
|
(append l (map (lambda (_) '()) l))))))))
|
|
(define pop-level
|
|
(lambda ()
|
|
(vector-set! types depth '())
|
|
(set! depth (- depth 1))))
|
|
(define v-ord (lambda () (make-tvar depth 'ord)))
|
|
(define v-abs (lambda () (make-tvar depth 'abs)))
|
|
(define v-pre (lambda () (make-tvar depth 'pre)))
|
|
(define tvar v-ord)
|
|
(define out1tvar
|
|
(lambda () (make-tvar (- depth 1) 'ord)))
|
|
(define monotvar
|
|
(lambda () (make-tvar ord-depth 'ord)))
|
|
(define pvar
|
|
(match-lambda
|
|
(($ box (and x ($ v d k _ vis _ _)))
|
|
(unless
|
|
(number? (v-name x))
|
|
(set-v-name! x ((v-name x))))
|
|
(string->symbol
|
|
(sprintf
|
|
"~a~a~a"
|
|
(match k
|
|
('ord
|
|
(if (generic? d)
|
|
(if vis "X" "x")
|
|
(if vis "Z" "z")))
|
|
('abs (if vis "A" "a"))
|
|
('pre (if vis "P" "p")))
|
|
(v-name x)
|
|
(if dump-depths (sprintf ".~a" d) ""))))))
|
|
(define make-tvar-like
|
|
(match-lambda
|
|
(($ box ($ v d k _ _ _ _)) (make-tvar d k))))
|
|
(define ind*
|
|
(lambda (t)
|
|
(match (unbox t)
|
|
((? box? u)
|
|
(let ((v (ind* u))) (set-box! t v) v))
|
|
(_ t))))
|
|
(define type-check?
|
|
(match-lambda
|
|
((abs def inexhaust once _)
|
|
(cond (((if once check-abs1? check-abs?) abs)
|
|
(if (and def (definite? def)) 'def #t))
|
|
(inexhaust 'inexhaust)
|
|
(else #f)))))
|
|
(define type-check1?
|
|
(match-lambda
|
|
((abs def inexhaust _ _)
|
|
(cond ((check-abs1? abs)
|
|
(if (and def (definite? def)) 'def #t))
|
|
(inexhaust 'inexhaust)
|
|
(else #f)))))
|
|
(define check-abs?
|
|
(lambda (vlist)
|
|
(letrec ((seen '())
|
|
(labs? (lambda (t)
|
|
(match t
|
|
(($ box ($ v _ _ _ _ _ inst))
|
|
(and inst
|
|
(not (memq t seen))
|
|
(begin
|
|
(set! seen (cons t seen))
|
|
(ormap (match-lambda ((t . _) (labs? t)))
|
|
inst))))
|
|
(($ box ($ c _ _ _ p _ n))
|
|
(or (labs? p) (labs? n)))
|
|
(($ box (? symbol?)) #t)
|
|
(($ box i) (labs? i))))))
|
|
(ormap labs? vlist))))
|
|
(define check-abs1?
|
|
(lambda (vlist)
|
|
(letrec ((labs1?
|
|
(lambda (t)
|
|
(match t
|
|
(($ box (? v?)) #f)
|
|
(($ box ($ c _ _ _ p _ n))
|
|
(or (labs1? p) (labs1? n)))
|
|
(($ box (? symbol?)) #t)
|
|
(($ box i) (labs1? i))))))
|
|
(ormap labs1? vlist))))
|
|
(define check-sources
|
|
(lambda (info)
|
|
(letrec ((seen '())
|
|
(lsrcs (lambda (t source)
|
|
(match t
|
|
(($ box ($ v _ k _ _ _ inst))
|
|
(union (if (and inst (not (memq t seen)))
|
|
(begin
|
|
(set! seen (cons t seen))
|
|
(foldr union
|
|
empty-set
|
|
(map (match-lambda
|
|
((t . s) (lsrcs t s)))
|
|
inst)))
|
|
empty-set)))
|
|
(($ box ($ c _ _ _ p _ n))
|
|
(union (lsrcs p source) (lsrcs n source)))
|
|
(($ box (? symbol?))
|
|
(if source (set source) empty-set))
|
|
(($ box i) (lsrcs i source))))))
|
|
(match-let
|
|
(((abs _ _ _ _) info))
|
|
(if (eq? #t abs)
|
|
empty-set
|
|
(foldr union
|
|
empty-set
|
|
(map (lambda (t) (lsrcs t #f)) abs)))))))
|
|
(define check-local-sources
|
|
(match-lambda ((_ _ _ _ component) component)))
|
|
(define mk-definite-prim
|
|
(match-lambda
|
|
(($ box ($ c _ _ x p a n))
|
|
(if (eq? (k-name x) '?->)
|
|
(let ((seen '()))
|
|
(recur lprim
|
|
((t (car a)))
|
|
(match t
|
|
(($ box ($ c _ _ x p a n))
|
|
(if (memq t seen)
|
|
'()
|
|
(begin
|
|
(set! seen (cons t seen))
|
|
(match (k-name x)
|
|
('noarg (cons p (lprim n)))
|
|
('arg
|
|
(let ((args (recur argloop
|
|
((a (car a)))
|
|
(match a
|
|
(($ box
|
|
($ c
|
|
_
|
|
_
|
|
_
|
|
p
|
|
_
|
|
n))
|
|
(cons p
|
|
(argloop
|
|
n)))
|
|
(($ box
|
|
($ v
|
|
_
|
|
k
|
|
_
|
|
_
|
|
_
|
|
_))
|
|
(if (ord? k)
|
|
(list a)
|
|
'()))
|
|
(($ box
|
|
(? symbol?))
|
|
'())
|
|
(($ box i)
|
|
(argloop i))))))
|
|
(cons (list p args (lprim (cadr a)))
|
|
(lprim n))))))))
|
|
(($ box ($ v _ k _ _ _ _))
|
|
(if (ord? k) (list t) '()))
|
|
(($ box (? symbol?)) '())
|
|
(($ box i) (lprim i)))))
|
|
(mk-definite-prim n)))
|
|
(($ box (? v?)) '())
|
|
(($ box (? symbol?)) '())
|
|
(($ box i) (mk-definite-prim i))))
|
|
(define mk-definite-app
|
|
(match-lambda
|
|
(($ box ($ c _ _ _ p _ _)) (list p))))
|
|
(define mk-definite-lam
|
|
(match-lambda
|
|
(($ box ($ c _ _ x p a n))
|
|
(if (eq? (k-name x) '?->)
|
|
(let ((seen '()))
|
|
(recur llam
|
|
((t (car a)))
|
|
(match t
|
|
(($ box ($ c _ _ x p a n))
|
|
(if (memq t seen)
|
|
'()
|
|
(begin
|
|
(set! seen (cons t seen))
|
|
(match (k-name x)
|
|
('noarg (cons p (llam n)))
|
|
('arg
|
|
(let ((args (list top)))
|
|
(cons (list p args (llam (cadr a)))
|
|
(llam n))))))))
|
|
(($ box ($ v _ k _ _ _ _))
|
|
(if (ord? k) (list t) '()))
|
|
(($ box (? symbol?)) '())
|
|
(($ box i) (llam i)))))
|
|
(mk-definite-lam n)))
|
|
(($ box (? v?)) '())
|
|
(($ box (? symbol?)) '())
|
|
(($ box i) (mk-definite-lam i))))
|
|
(define definite?
|
|
(lambda (def-info)
|
|
(letrec ((non-empty?
|
|
(lambda (t)
|
|
(let ((seen '()))
|
|
(recur ldef
|
|
((t t))
|
|
(match t
|
|
(($ box ($ c _ _ _ p _ n))
|
|
(or (ldef p) (ldef n)))
|
|
(($ box ($ v d k _ _ _ inst))
|
|
(if (or global-error (abs? k))
|
|
(and inst
|
|
(generic? d)
|
|
(not (memq t seen))
|
|
(begin
|
|
(set! seen (cons t seen))
|
|
(ormap (match-lambda
|
|
((t . _) (ldef t)))
|
|
inst)))
|
|
(generic? d)))
|
|
(($ box 'top) #t)
|
|
(($ box 'bot) #f)
|
|
(($ box i) (ldef i)))))))
|
|
(ok (lambda (l)
|
|
(ormap (match-lambda
|
|
((? box? t) (non-empty? t))
|
|
((p arg rest)
|
|
(and (non-empty? p)
|
|
(ormap non-empty? arg)
|
|
(ok rest))))
|
|
l))))
|
|
(not (ok def-info)))))
|
|
(define close
|
|
(lambda (t-list) (close-type t-list #f)))
|
|
(define closeall
|
|
(lambda (t) (car (close-type (list t) #t))))
|
|
(define for
|
|
(lambda (from to f)
|
|
(cond ((= from to) (f from))
|
|
((< from to)
|
|
(begin (f from) (for (+ from 1) to f)))
|
|
(else #f))))
|
|
(define close-type
|
|
(lambda (t-list all?)
|
|
(let* ((sorted (make-vector (+ depth 1) '()))
|
|
(sort (lambda (t)
|
|
(match t
|
|
(($ box ($ c d _ _ _ _ _))
|
|
(vector-set!
|
|
sorted
|
|
d
|
|
(cons t (vector-ref sorted d))))
|
|
(($ box ($ v d _ _ _ _ _))
|
|
(vector-set!
|
|
sorted
|
|
d
|
|
(cons t (vector-ref sorted d))))
|
|
(_ #f))))
|
|
(prop-d
|
|
(lambda (down)
|
|
(letrec ((pr (match-lambda
|
|
(($ box (and x ($ v d _ _ _ _ _)))
|
|
(when (< down d) (set-v-depth! x down)))
|
|
(($ box (and x ($ c d _ _ p a n)))
|
|
(when (< down d)
|
|
(set-c-depth! x down)
|
|
(pr p)
|
|
(for-each pr a)
|
|
(pr n)))
|
|
(($ box (? symbol?)) #f)
|
|
(z (pr (ind* z))))))
|
|
(match-lambda
|
|
(($ box (and x ($ c d _ _ p a n)))
|
|
(when (<= down d) (pr p) (for-each pr a) (pr n)))
|
|
(_ #f)))))
|
|
(prop-k
|
|
(lambda (t)
|
|
(let ((pk (lambda (kind)
|
|
(rec pr
|
|
(match-lambda
|
|
(($ box (and x ($ v _ k _ _ _ _)))
|
|
(when (kind< kind k) (set-v-kind! x kind)))
|
|
(($ box (and x ($ c _ k _ p a n)))
|
|
(when (kind< kind k)
|
|
(set-c-kind! x kind)
|
|
(pr p)
|
|
(unless populated (for-each pr a))
|
|
(pr n)))
|
|
(($ box (? symbol?)) #f)
|
|
(z (pr (ind* z))))))))
|
|
(match t
|
|
(($ box (and x ($ c _ k _ p a n)))
|
|
(when (not (ord? k))
|
|
(let ((prop (pk k)))
|
|
(prop p)
|
|
(unless populated (for-each prop a))
|
|
(prop n))))
|
|
(_ #f)))))
|
|
(might-be-generalized?
|
|
(match-lambda
|
|
(($ box ($ v d k _ _ _ _))
|
|
(and (<= depth d) (or populated (ord? k) all?)))
|
|
(($ box ($ c d k _ _ _ _))
|
|
(and (<= depth d) (or populated (ord? k) all?)))
|
|
(($ box (? symbol?)) #f)))
|
|
(leaves '())
|
|
(depth-of
|
|
(match-lambda
|
|
(($ box ($ v d _ _ _ _ _)) d)
|
|
(($ box ($ c d _ _ _ _ _)) d)))
|
|
(vector-grow
|
|
(lambda (v)
|
|
(let* ((n (vector-length v))
|
|
(v2 (make-vector (* n 2) '())))
|
|
(recur loop
|
|
((i 0))
|
|
(when (< i n)
|
|
(vector-set! v2 i (vector-ref v i))
|
|
(loop (+ 1 i))))
|
|
v2)))
|
|
(parents (make-vector 64 '()))
|
|
(parent-index 0)
|
|
(parents-of
|
|
(lambda (t)
|
|
(let ((d (depth-of t)))
|
|
(if (< depth d)
|
|
(vector-ref parents (- (- d depth) 1))
|
|
'()))))
|
|
(xtnd-parents!
|
|
(lambda (t parent)
|
|
(match t
|
|
(($ box (and x ($ v d _ _ _ _ _)))
|
|
(when (= d depth)
|
|
(set! parent-index (+ 1 parent-index))
|
|
(set-v-depth! x (+ depth parent-index))
|
|
(when (< (vector-length parents) parent-index)
|
|
(set! parents (vector-grow parents)))
|
|
(set! d (+ depth parent-index)))
|
|
(vector-set!
|
|
parents
|
|
(- (- d depth) 1)
|
|
(cons parent
|
|
(vector-ref parents (- (- d depth) 1)))))
|
|
(($ box (and x ($ c d _ _ _ _ _)))
|
|
(when (= d depth)
|
|
(set! parent-index (+ 1 parent-index))
|
|
(set-c-depth! x (+ depth parent-index))
|
|
(when (< (vector-length parents) parent-index)
|
|
(set! parents (vector-grow parents)))
|
|
(set! d (+ depth parent-index)))
|
|
(vector-set!
|
|
parents
|
|
(- (- d depth) 1)
|
|
(cons parent
|
|
(vector-ref parents (- (- d depth) 1))))))))
|
|
(needs-cleanup '())
|
|
(revtype
|
|
(rec revtype
|
|
(lambda (parent t)
|
|
(let ((t (ind* t)))
|
|
(cond ((not (might-be-generalized? t)) #f)
|
|
((null? (parents-of t))
|
|
(xtnd-parents! t parent)
|
|
(set! needs-cleanup (cons t needs-cleanup))
|
|
(match t
|
|
(($ box (? v?))
|
|
(set! leaves (cons t leaves)))
|
|
(($ box ($ c _ _ _ p a n))
|
|
(let ((rev (lambda (q) (revtype t q))))
|
|
(rev p)
|
|
(for-each rev a)
|
|
(rev n)))))
|
|
((not (memq parent (parents-of t)))
|
|
(xtnd-parents! t parent))
|
|
(else #f))))))
|
|
(generic-index 0)
|
|
(gen (rec gen
|
|
(lambda (t)
|
|
(let ((t (ind* t)))
|
|
(when (might-be-generalized? t)
|
|
(set! generic-index (- generic-index 1))
|
|
(let ((parents (parents-of t)))
|
|
(match t
|
|
(($ box (and x ($ v _ k _ _ _ _)))
|
|
(set-v-depth! x generic-index)
|
|
(when (and populated
|
|
(or global-error
|
|
(abs? k)
|
|
(pre? k))
|
|
(not all?))
|
|
(set-v-inst! x '())))
|
|
(($ box (? c? x))
|
|
(set-c-depth! x generic-index)))
|
|
(for-each gen parents)))))))
|
|
(cleanup
|
|
(match-lambda
|
|
(($ box (and x ($ v d _ _ _ _ _)))
|
|
(unless (< d 0) (set-v-depth! x (- depth 1))))
|
|
(($ box (and x ($ c d _ _ _ _ _)))
|
|
(unless (< d 0) (set-c-depth! x (- depth 1))))))
|
|
(gen2 (rec gen
|
|
(lambda (t)
|
|
(let ((t (ind* t)))
|
|
(when (might-be-generalized? t)
|
|
(set! generic-index (- generic-index 1))
|
|
(match t
|
|
(($ box (and x ($ v _ k _ _ _ _)))
|
|
(set-v-depth! x generic-index)
|
|
(when (and populated
|
|
(or global-error
|
|
(abs? k)
|
|
(pre? k))
|
|
(not all?))
|
|
(set-v-inst! x '())))
|
|
(($ box (and x ($ c _ _ _ p a n)))
|
|
(set-c-depth! x generic-index)
|
|
(gen p)
|
|
(for-each gen a)
|
|
(gen n))))))))
|
|
(upd (lambda (t)
|
|
(let ((d (depth-of t)))
|
|
(when (< 0 d)
|
|
(vector-set!
|
|
types
|
|
d
|
|
(cons t (vector-ref types d))))))))
|
|
(for-each sort (vector-ref types depth))
|
|
(for 0
|
|
(- depth 1)
|
|
(lambda (i)
|
|
(for-each (prop-d i) (vector-ref sorted i))))
|
|
(for-each prop-k (vector-ref types depth))
|
|
(vector-set! types depth '())
|
|
(if fullsharing
|
|
(begin
|
|
(for-each (lambda (t) (revtype t t)) t-list)
|
|
(for-each gen leaves)
|
|
(for-each cleanup needs-cleanup))
|
|
(for-each gen2 t-list))
|
|
(for 0
|
|
depth
|
|
(lambda (i) (for-each upd (vector-ref sorted i))))
|
|
(if (null? t-list)
|
|
'()
|
|
(match-let*
|
|
((n-gen (- generic-index))
|
|
((t-list n-gen)
|
|
(if (and pseudo flags (not all?))
|
|
(pseudo t-list n-gen)
|
|
(list t-list n-gen))))
|
|
(visible t-list n-gen)
|
|
(map (lambda (t) (make-ts t n-gen)) t-list))))))
|
|
(define visible-time 0)
|
|
(define visible
|
|
(lambda (t-list n-gen)
|
|
(let* ((before (cpu-time))
|
|
(valences (make-vector n-gen '()))
|
|
(namer (generate-counter))
|
|
(lvis (rec lvis
|
|
(lambda (t pos rcd)
|
|
(match t
|
|
(($ box ($ c d _ x p a n))
|
|
(when (and (generic? d)
|
|
(not (element-of?
|
|
pos
|
|
(vector-ref
|
|
valences
|
|
(- (- d) 1)))))
|
|
(let ((u (union (vector-ref
|
|
valences
|
|
(- (- d) 1))
|
|
(set pos))))
|
|
(vector-set! valences (- (- d) 1) u))
|
|
(lvis p pos rcd)
|
|
(match (k-name x)
|
|
('?->
|
|
(lvis (car a) (not pos) #f)
|
|
(lvis (cadr a) pos #f))
|
|
('record (lvis (car a) pos #t))
|
|
(_ (for-each
|
|
(lambda (x) (lvis x pos #f))
|
|
a)))
|
|
(lvis n pos rcd)))
|
|
(($ box (and x ($ v d k _ _ _ _)))
|
|
(when (and (generic? d)
|
|
(not (element-of?
|
|
pos
|
|
(vector-ref
|
|
valences
|
|
(- (- d) 1)))))
|
|
(let ((u (union (vector-ref
|
|
valences
|
|
(- (- d) 1))
|
|
(set pos))))
|
|
(vector-set! valences (- (- d) 1) u)
|
|
(set-v-name! x namer)
|
|
(cond ((abs? k) #f)
|
|
((= 2 (cardinality u))
|
|
(set-v-split! x #t)
|
|
(set-v-vis! x #t))
|
|
((eq? pos rcd) (set-v-vis! x #t))
|
|
(else (set-v-vis! x #f))))))
|
|
(($ box (? symbol?)) #f)
|
|
(($ box i) (lvis i pos rcd)))))))
|
|
(for-each (lambda (t) (lvis t #t #f)) t-list)
|
|
(set! visible-time
|
|
(+ visible-time (- (cpu-time) before))))))
|
|
(define visible?
|
|
(match-lambda
|
|
(($ box ($ v _ k _ vis _ _))
|
|
(or (pre? k) (and vis (not (abs? k)))))
|
|
(($ box 'top) #t)
|
|
(($ box 'bot) #f)
|
|
(($ box i) (visible? i))))
|
|
(define instantiate
|
|
(lambda (ts syntax)
|
|
(match ts
|
|
(($ ts t n-gen)
|
|
(let* ((absv '())
|
|
(seen (make-vector n-gen #f))
|
|
(t2 (recur linst
|
|
((t t))
|
|
(match t
|
|
(($ box (and y ($ v d k _ _ _ inst)))
|
|
(cond ((not (generic? d)) t)
|
|
((vector-ref seen (- (- d) 1)))
|
|
(else
|
|
(let ((u (make-tvar depth k)))
|
|
(vector-set! seen (- (- d) 1) u)
|
|
(when inst
|
|
(set-v-inst!
|
|
y
|
|
(cons (cons u syntax)
|
|
inst)))
|
|
(when (or (abs? k) (pre? k))
|
|
(set! absv (cons u absv)))
|
|
u))))
|
|
(($ box ($ c d _ x p a n))
|
|
(cond ((not (generic? d)) t)
|
|
((vector-ref seen (- (- d) 1)))
|
|
(else
|
|
(let ((u (new-type
|
|
'**fix**
|
|
depth)))
|
|
(vector-set! seen (- (- d) 1) u)
|
|
(set-box!
|
|
u
|
|
(make-c
|
|
depth
|
|
'ord
|
|
x
|
|
(if flags (linst p) top)
|
|
(map linst a)
|
|
(linst n)))
|
|
u))))
|
|
(($ box (? symbol?)) t)
|
|
(($ box i) (linst i))))))
|
|
(list t2 absv))))))
|
|
(define pseudo-subtype
|
|
(lambda (t-list n-gen)
|
|
(let* ((valences (make-vector n-gen '()))
|
|
(valence-of
|
|
(lambda (d) (vector-ref valences (- (- d) 1))))
|
|
(set-valence
|
|
(lambda (d v)
|
|
(vector-set! valences (- (- d) 1) v)))
|
|
(find (rec find
|
|
(lambda (t pos mutable)
|
|
(match t
|
|
(($ box ($ v d _ _ _ _ _))
|
|
(when (generic? d)
|
|
(cond (mutable
|
|
(set-valence d (set #t #f)))
|
|
((not (element-of?
|
|
pos
|
|
(valence-of d)))
|
|
(set-valence
|
|
d
|
|
(union (valence-of d)
|
|
(set pos))))
|
|
(else #f))))
|
|
(($ box ($ c d _ x p a n))
|
|
(when (generic? d)
|
|
(cond ((= 2 (cardinality (valence-of d)))
|
|
#f)
|
|
(mutable
|
|
(set-valence d (set #t #f))
|
|
(for-each2
|
|
(lambda (t m)
|
|
(find t pos mutable))
|
|
a
|
|
(k-args x))
|
|
(find n pos mutable))
|
|
((not (element-of?
|
|
pos
|
|
(valence-of d)))
|
|
(set-valence
|
|
d
|
|
(union (valence-of d)
|
|
(set pos)))
|
|
(if (eq? '?-> (k-name x))
|
|
(begin
|
|
(find (car a)
|
|
(not pos)
|
|
mutable)
|
|
(find (cadr a) pos mutable))
|
|
(for-each2
|
|
(lambda (t m)
|
|
(find t pos (or m mutable)))
|
|
a
|
|
(k-args x)))
|
|
(find n pos mutable))
|
|
(else #f))))
|
|
(($ box (? symbol?)) #f)
|
|
(($ box i) (find i pos mutable))))))
|
|
(seen (make-vector n-gen #f))
|
|
(new-generic-var
|
|
(lambda ()
|
|
(set! n-gen (+ 1 n-gen))
|
|
(box (make-raw-tvar (- n-gen) 'ord))))
|
|
(copy (rec copy
|
|
(lambda (t)
|
|
(match t
|
|
(($ box ($ v d k _ _ _ _))
|
|
(if (generic? d)
|
|
(or (vector-ref seen (- (- d) 1))
|
|
(let ((u (if (and (abs? k)
|
|
(equal?
|
|
(valence-of d)
|
|
'(#t)))
|
|
(new-generic-var)
|
|
t)))
|
|
(vector-set! seen (- (- d) 1) u)
|
|
u))
|
|
t))
|
|
(($ box ($ c d k x p a n))
|
|
(if (generic? d)
|
|
(or (vector-ref seen (- (- d) 1))
|
|
(let* ((u (box '**fix**))
|
|
(_ (vector-set!
|
|
seen
|
|
(- (- d) 1)
|
|
u))
|
|
(new-p (if (and (eq? (ind* p) top)
|
|
(equal?
|
|
(valence-of d)
|
|
'(#f)))
|
|
(new-generic-var)
|
|
(copy p)))
|
|
(new-a (map copy a))
|
|
(new-n (copy n)))
|
|
(set-box!
|
|
u
|
|
(make-c d 'ord x new-p new-a new-n))
|
|
u))
|
|
t))
|
|
(($ box (? symbol?)) t)
|
|
(($ box i) (copy i))))))
|
|
(t-list
|
|
(map (lambda (t) (find t #t #f) (copy t)) t-list)))
|
|
(list t-list n-gen))))
|
|
(set! pseudo pseudo-subtype)
|
|
(define unify
|
|
(letrec ((uni (lambda (u v)
|
|
(unless
|
|
(eq? u v)
|
|
(match (cons u v)
|
|
((($ box (and us ($ c ud uk ux up ua un)))
|
|
$
|
|
box
|
|
(and vs ($ c vd vk vx vp va vn)))
|
|
(if (eq? ux vx)
|
|
(begin
|
|
(if (< ud vd)
|
|
(begin
|
|
(set-box! v u)
|
|
(when (kind< vk uk) (set-c-kind! us vk)))
|
|
(begin
|
|
(set-box! u v)
|
|
(when (kind< uk vk) (set-c-kind! vs uk))))
|
|
(uni un vn)
|
|
(for-each2 uni ua va)
|
|
(uni up vp))
|
|
(let* ((next (tvar))
|
|
(k (if (kind< uk vk) uk vk)))
|
|
(if (< ud vd)
|
|
(begin
|
|
(when (< vd ud) (set-c-depth! us vd))
|
|
(when (kind< vk uk) (set-c-kind! us vk))
|
|
(set-box! v u))
|
|
(begin
|
|
(when (< ud vd) (set-c-depth! vs ud))
|
|
(when (kind< uk vk) (set-c-kind! vs uk))
|
|
(set-box! u v)))
|
|
(uni (new-type
|
|
(make-c depth k ux up ua next)
|
|
depth)
|
|
vn)
|
|
(uni un
|
|
(new-type
|
|
(make-c depth k vx vp va next)
|
|
depth)))))
|
|
((($ box (and x ($ v ud uk _ _ _ _)))
|
|
$
|
|
box
|
|
($ v vd vk _ _ _ _))
|
|
(set-v-depth! x (min ud vd))
|
|
(set-v-kind! x (if (kind< uk vk) uk vk))
|
|
(set-box! v u))
|
|
((($ box ($ v ud uk _ _ _ _))
|
|
$
|
|
box
|
|
(and x ($ c vd vk _ _ _ _)))
|
|
(when (< ud vd) (set-c-depth! x ud))
|
|
(when (kind< uk vk) (set-c-kind! x uk))
|
|
(set-box! u v))
|
|
((($ box (and x ($ c ud uk _ _ _ _)))
|
|
$
|
|
box
|
|
($ v vd vk _ _ _ _))
|
|
(when (< vd ud) (set-c-depth! x vd))
|
|
(when (kind< vk uk) (set-c-kind! x vk))
|
|
(set-box! v u))
|
|
((($ box ($ v _ _ _ _ _ _)) $ box (? symbol?))
|
|
(set-box! u v))
|
|
((($ box (? symbol?)) $ box ($ v _ _ _ _ _ _))
|
|
(set-box! v u))
|
|
((($ box 'bot) $ box ($ c _ _ _ p _ n))
|
|
(set-box! v u)
|
|
(uni u p)
|
|
(uni u n))
|
|
((($ box ($ c _ _ _ p _ n)) $ box 'bot)
|
|
(set-box! u v)
|
|
(uni v p)
|
|
(uni v n))
|
|
(_ (uni (ind* u) (ind* v))))))))
|
|
uni))
|
|
(define kind<
|
|
(lambda (k1 k2) (and (ord? k2) (not (ord? k1)))))
|
|
(define r+-
|
|
(lambda (flag+ flag- tail+- absent- pos env type)
|
|
(letrec ((absent+ v-ord)
|
|
(tvars '())
|
|
(fvars '())
|
|
(absv '())
|
|
(make-flag
|
|
(lambda (pos)
|
|
(cond ((not flags) top)
|
|
(pos (flag+))
|
|
(else (flag-)))))
|
|
(typevar?
|
|
(lambda (v)
|
|
(and (symbol? v)
|
|
(not (bound? env v))
|
|
(not (memq v
|
|
'(_ bool
|
|
mu
|
|
list
|
|
&list
|
|
&optional
|
|
&rest
|
|
arglist
|
|
+
|
|
not
|
|
rec
|
|
*tidy))))))
|
|
(parse-type
|
|
(lambda (t pos)
|
|
(match t
|
|
(('mu a t)
|
|
(unless
|
|
(typevar? a)
|
|
(raise 'type "invalid type syntax at ~a" t))
|
|
(when (assq a tvars)
|
|
(raise 'type "~a is defined more than once" a))
|
|
(let* ((fix (new-type '**fix** depth))
|
|
(_ (set! tvars (cons (list a fix '()) tvars)))
|
|
(t (parse-type t pos)))
|
|
(when (eq? t fix)
|
|
(raise 'type
|
|
"recursive type is not contractive"))
|
|
(set-box! fix t)
|
|
(ind* t)))
|
|
(('rec (? list? bind) t2)
|
|
(for-each
|
|
(match-lambda
|
|
((a _)
|
|
(unless
|
|
(typevar? a)
|
|
(raise 'type "invalid type syntax at ~a" t))
|
|
(when (assq a tvars)
|
|
(raise 'type
|
|
"~a is defined more than once"
|
|
a))
|
|
(set! tvars
|
|
(cons (list a (new-type '**fix** depth) '())
|
|
tvars)))
|
|
(_ (raise 'type "invalid type syntax at ~a" t)))
|
|
bind)
|
|
(for-each
|
|
(match-lambda
|
|
((a t)
|
|
(match (assq a tvars)
|
|
((_ fix _)
|
|
(let ((t (parse-type t '?)))
|
|
(when (eq? t fix)
|
|
(raise 'type
|
|
"type is not contractive"))
|
|
(set-box! fix t))))))
|
|
bind)
|
|
(parse-type t2 pos))
|
|
('bool (parse-type '(+ false true) pos))
|
|
('s-exp
|
|
(let ((v (gensym)))
|
|
(parse-type
|
|
`(mu ,v
|
|
(+ num
|
|
nil
|
|
false
|
|
true
|
|
char
|
|
sym
|
|
str
|
|
(vec ,v)
|
|
(box ,v)
|
|
(cons ,v ,v)))
|
|
pos)))
|
|
(('list t)
|
|
(let ((u (gensym)))
|
|
(parse-type `(mu ,u (+ nil (cons ,t ,u))) pos)))
|
|
(('arglist t)
|
|
(let ((u (gensym)))
|
|
(parse-type `(mu ,u (+ noarg (arg ,t ,u))) pos)))
|
|
(('+ ? list? union) (parse-union union pos))
|
|
(t (parse-union (list t) pos)))))
|
|
(parse-union
|
|
(lambda (t pos)
|
|
(letrec ((sort-cs
|
|
(lambda (cs)
|
|
(sort-list
|
|
cs
|
|
(lambda (x y) (k< (c-fsym x) (c-fsym y))))))
|
|
(link (lambda (c t)
|
|
(set-c-next! c t)
|
|
(new-type c depth))))
|
|
(recur loop
|
|
((t t) (cs '()))
|
|
(match t
|
|
(()
|
|
(foldr link
|
|
(if pos
|
|
(absent+)
|
|
(let ((v (absent-)))
|
|
(set! absv (cons v absv))
|
|
v))
|
|
(sort-cs cs)))
|
|
(((? box? t)) (foldr link t (sort-cs cs)))
|
|
(('_) (foldr link (tail+-) (sort-cs cs)))
|
|
(((? symbol? a))
|
|
(=> fail)
|
|
(unless (typevar? a) (fail))
|
|
(let* ((cs (sort-cs cs))
|
|
(ks (map c-fsym cs)))
|
|
(foldr link
|
|
(match (assq a tvars)
|
|
((_ f aks)
|
|
(unless
|
|
(equal? ks aks)
|
|
(raise 'type
|
|
"variable ~a is not tidy"
|
|
a))
|
|
f)
|
|
(#f
|
|
(let ((v (tail+-)))
|
|
(set! tvars
|
|
(cons (list a v ks)
|
|
tvars))
|
|
v)))
|
|
cs)))
|
|
((k . rest)
|
|
(loop rest (cons (parse-k k pos) cs))))))))
|
|
(parse-k
|
|
(lambda (k pos)
|
|
(cond ((and (list? k)
|
|
(let ((n (length k)))
|
|
(and (<= 2 n) (eq? '-> (list-ref k (- n 2))))))
|
|
(let* ((rk (reverse k))
|
|
(arg (reverse (cddr rk)))
|
|
(res (car rk)))
|
|
(letrec ((mkargs
|
|
(match-lambda
|
|
(() 'noarg)
|
|
((('&rest x)) x)
|
|
((('&list x))
|
|
(let ((u (gensym)))
|
|
`(mu ,u (+ noarg (arg ,x ,u)))))
|
|
((('&optional x))
|
|
`(+ noarg (arg ,x noarg)))
|
|
((x . y) `(arg ,x ,(mkargs y)))
|
|
(_ (raise 'type
|
|
"invalid type syntax")))))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
(lookup env '?->)
|
|
(make-flag pos)
|
|
(let ((a (parse-type (mkargs arg) (flip pos)))
|
|
(r (parse-type res pos)))
|
|
(list a r))
|
|
'**fix**))))
|
|
(else
|
|
(match k
|
|
((arg '?-> res)
|
|
(make-c
|
|
depth
|
|
'ord
|
|
(lookup env '?->)
|
|
(make-flag pos)
|
|
(let ((a (parse-type arg (flip pos)))
|
|
(r (parse-type res pos)))
|
|
(list a r))
|
|
'**fix**))
|
|
(('record ? list? fields)
|
|
(make-c
|
|
depth
|
|
'ord
|
|
(lookup env 'record)
|
|
(make-flag pos)
|
|
(list (recur loop
|
|
((fields fields))
|
|
(match fields
|
|
(() (if pos bot (v-ord)))
|
|
((((? symbol? f) ftype)
|
|
.
|
|
rest)
|
|
(new-type
|
|
(make-c
|
|
depth
|
|
'ord
|
|
(new-field! f)
|
|
(if pos
|
|
(v-ord)
|
|
(let ((v (v-pre)))
|
|
(set! absv
|
|
(cons v absv))
|
|
v))
|
|
(list (parse-type
|
|
ftype
|
|
pos))
|
|
(loop rest))
|
|
depth)))))
|
|
'**fix**))
|
|
(('not (? k? k))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
k
|
|
(if pos
|
|
(absent+)
|
|
(let ((v (absent-)))
|
|
(set! absv (cons v absv))
|
|
v))
|
|
(map (lambda (x) (tail+-)) (k-args k))
|
|
'**fix**))
|
|
(('not c)
|
|
(unless
|
|
(bound? env c)
|
|
(raise 'type "invalid type syntax at ~a" k))
|
|
(let ((k (lookup env c)))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
k
|
|
(if pos
|
|
(absent+)
|
|
(let ((v (absent-)))
|
|
(set! absv (cons v absv))
|
|
v))
|
|
(map (lambda (x) (tail+-)) (k-args k))
|
|
'**fix**)))
|
|
(('*tidy c (? symbol? f))
|
|
(unless
|
|
(bound? env c)
|
|
(raise 'type "invalid type syntax at ~a" k))
|
|
(let ((k (lookup env c)))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
k
|
|
(match (assq f fvars)
|
|
((_ . f) f)
|
|
(#f
|
|
(let ((v (tail+-)))
|
|
(set! fvars
|
|
(cons (cons f v) fvars))
|
|
v)))
|
|
(map (lambda (x) (parse-type '(+) pos))
|
|
(k-args k))
|
|
'**fix**)))
|
|
(((? k? k) ? list? arg)
|
|
(unless
|
|
(= (length arg) (length (k-args k)))
|
|
(raise 'type
|
|
"~a requires ~a arguments"
|
|
(k-name k)
|
|
(length (k-args k))))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
k
|
|
(make-flag pos)
|
|
(smap (lambda (x) (parse-type x pos)) arg)
|
|
'**fix**))
|
|
((c ? list? arg)
|
|
(unless
|
|
(bound? env c)
|
|
(raise 'type "invalid type syntax at ~a" k))
|
|
(let ((k (lookup env c)))
|
|
(unless
|
|
(= (length arg) (length (k-args k)))
|
|
(raise 'type
|
|
"~a requires ~a arguments"
|
|
c
|
|
(length (k-args k))))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
k
|
|
(make-flag pos)
|
|
(smap (lambda (x) (parse-type x pos)) arg)
|
|
'**fix**)))
|
|
(c (unless
|
|
(bound? env c)
|
|
(raise 'type
|
|
"invalid type syntax at ~a"
|
|
k))
|
|
(let ((k (lookup env c)))
|
|
(unless
|
|
(= 0 (length (k-args k)))
|
|
(raise 'type
|
|
"~a requires ~a arguments"
|
|
c
|
|
(length (k-args k))))
|
|
(make-c
|
|
depth
|
|
'ord
|
|
k
|
|
(make-flag pos)
|
|
'()
|
|
'**fix**))))))))
|
|
(flip (match-lambda ('? '?) (#t #f) (#f #t))))
|
|
(let ((t (parse-type type pos))) (list t absv)))))
|
|
(define v-top (lambda () top))
|
|
(define r+
|
|
(lambda (env t)
|
|
(car (r+- v-top v-ord v-ord v-abs #t env t))))
|
|
(define r-
|
|
(lambda (env t)
|
|
(car (r+- v-top v-ord v-ord v-abs #f env t))))
|
|
(define r++
|
|
(lambda (env t)
|
|
(car (r+- v-top v-ord v-ord v-ord #t env t))))
|
|
(define r+collect
|
|
(lambda (env t)
|
|
(r+- v-top v-ord v-ord v-abs #t env t)))
|
|
(define r-collect
|
|
(lambda (env t)
|
|
(r+- v-top v-ord v-ord v-abs #f env t)))
|
|
(define r (lambda (t) (r+ initial-type-env t)))
|
|
(define r-match
|
|
(lambda (t)
|
|
(close '())
|
|
'(pretty-print `(fixing ,(ptype t)))
|
|
(fix-pat-abs! t)
|
|
(list t (collect-abs t))))
|
|
(define collect-abs
|
|
(lambda (t)
|
|
(let ((seen '()))
|
|
(recur loop
|
|
((t t))
|
|
(match t
|
|
(($ box ($ v _ k _ _ _ _))
|
|
(if (abs? k) (set t) empty-set))
|
|
(($ box ($ c _ _ _ p a n))
|
|
(if (memq t seen)
|
|
empty-set
|
|
(begin
|
|
(set! seen (cons t seen))
|
|
(foldr union
|
|
(union (loop p) (loop n))
|
|
(map loop a)))))
|
|
(($ box (? symbol?)) empty-set)
|
|
(($ box i) (loop i)))))))
|
|
(define fix-pat-abs!
|
|
(lambda (t)
|
|
(let ((seen '()))
|
|
(recur loop
|
|
((t t))
|
|
(match t
|
|
(($ box (and x ($ v d _ _ _ _ _)))
|
|
(when (= d depth) (set-v-kind! x 'abs)))
|
|
(($ box (and c ($ c _ _ _ p a n)))
|
|
(unless
|
|
(memq t seen)
|
|
(set! seen (cons t seen))
|
|
(loop p)
|
|
(when (and matchst flags (eq? (ind* p) top))
|
|
(set-c-pres! c (v-ord)))
|
|
(for-each loop a)
|
|
(loop n)))
|
|
(($ box (? symbol?)) t)
|
|
(($ box i) (loop i)))))))
|
|
(define pat-var-bind
|
|
(lambda (t)
|
|
(let ((seen '()))
|
|
(recur loop
|
|
((t t))
|
|
(match t
|
|
(($ box ($ v d _ _ _ _ _))
|
|
(if (< d depth)
|
|
t
|
|
(match (assq t seen)
|
|
((_ . new) new)
|
|
(#f
|
|
(let* ((new (v-ord)))
|
|
(set! seen (cons (cons t new) seen))
|
|
new)))))
|
|
(($ box ($ c d k x p a n))
|
|
(match (assq t seen)
|
|
((_ . new) new)
|
|
(#f
|
|
(let* ((fix (new-type '**fix** depth))
|
|
(fixbox (box fix))
|
|
(_ (set! seen (cons (cons t fixbox) seen)))
|
|
(new-p (if flags (loop p) top))
|
|
(new-a (map2 (lambda (mutable a)
|
|
(if mutable a (loop a)))
|
|
(k-args x)
|
|
a))
|
|
(new-n (loop n)))
|
|
(if (and (eq? new-p p)
|
|
(eq? new-n n)
|
|
(andmap eq? new-a a))
|
|
(begin (set-box! fixbox t) t)
|
|
(begin
|
|
(set-box!
|
|
fix
|
|
(make-c d k x new-p new-a new-n))
|
|
fix))))))
|
|
(($ box (? symbol?)) t)
|
|
(($ box i) (loop i)))))))
|
|
(define fields '())
|
|
(define new-field!
|
|
(lambda (x)
|
|
(match (assq x fields)
|
|
(#f
|
|
(let ((k (make-k x (+ 1 (length fields)) '(#f))))
|
|
(set! fields (cons (cons x k) fields))
|
|
k))
|
|
((_ . k) k))))
|
|
(define k<
|
|
(lambda (x y) (< (k-order x) (k-order y))))
|
|
(define k-counter 0)
|
|
(define bind-tycon
|
|
(lambda (x args covers fail-thunk)
|
|
(when (memq x
|
|
'(_ bool
|
|
mu
|
|
list
|
|
&list
|
|
&optional
|
|
&rest
|
|
arglist
|
|
+
|
|
not
|
|
rec
|
|
*tidy))
|
|
(fail-thunk "invalid type constructor ~a" x))
|
|
(set! k-counter (+ 1 k-counter))
|
|
(make-k
|
|
(if covers
|
|
(symbol-append x "." (- k-counter 100))
|
|
x)
|
|
k-counter
|
|
args)))
|
|
(define initial-type-env '())
|
|
(define init-types!
|
|
(lambda ()
|
|
(set! k-counter 0)
|
|
(set! var-counter (generate-counter))
|
|
(set! initial-type-env
|
|
(foldl (lambda (l env)
|
|
(extend-env
|
|
env
|
|
(car l)
|
|
(bind-tycon
|
|
(car l)
|
|
(cdr l)
|
|
#f
|
|
(lambda x (apply disaster 'init x)))))
|
|
empty-env
|
|
initial-type-info))
|
|
(set! k-counter 100)
|
|
(reset-types!)))
|
|
(define reinit-types!
|
|
(lambda ()
|
|
(set! var-counter (generate-counter))
|
|
(set! k-counter 100)
|
|
(set! fields '())
|
|
(set-cons-mutability! #t)
|
|
(reset-types!)))
|
|
(define deftype
|
|
(lambda (tag mutability)
|
|
(set! initial-type-env
|
|
(extend-env
|
|
initial-type-env
|
|
tag
|
|
(make-k
|
|
tag
|
|
(+ 1 (length initial-type-env))
|
|
mutability)))))
|
|
(define initial-type-info
|
|
'((?-> #f #f)
|
|
(arg #f #f)
|
|
(noarg)
|
|
(num)
|
|
(nil)
|
|
(false)
|
|
(true)
|
|
(char)
|
|
(sym)
|
|
(str)
|
|
(void)
|
|
(iport)
|
|
(oport)
|
|
(eof)
|
|
(vec #t)
|
|
(box #t)
|
|
(cons #t #t)
|
|
(cvec #f)
|
|
(promise #t)
|
|
(record #f)
|
|
(module #f)))
|
|
(define cons-is-mutable #f)
|
|
(define set-cons-mutability!
|
|
(lambda (m)
|
|
(set! cons-is-mutable m)
|
|
(set-k-args!
|
|
(lookup initial-type-env 'cons)
|
|
(list m m))))
|
|
(define tidy?
|
|
(lambda (t)
|
|
(let ((seen '()))
|
|
(recur loop
|
|
((t t) (label '()))
|
|
(match t
|
|
(($ box (? v?))
|
|
(match (assq t seen)
|
|
(#f (set! seen (cons (cons t label) seen)) #t)
|
|
((_ . l2) (equal? label l2))))
|
|
(($ box ($ c _ _ x _ a n))
|
|
(match (assq t seen)
|
|
((_ . l2) (equal? label l2))
|
|
(#f
|
|
(set! seen (cons (cons t label) seen))
|
|
(and (loop n (sort-list (cons x label) k<))
|
|
(andmap (lambda (t) (loop t '())) a)))))
|
|
(($ box (? symbol?)) #t)
|
|
(($ box i) (loop i label)))))))
|
|
(define tidy
|
|
(match-lambda
|
|
(($ ts t _)
|
|
(tidy-print t print-union assemble-union #f))
|
|
(t (tidy-print t print-union assemble-union #f))))
|
|
(define ptype
|
|
(match-lambda
|
|
(($ ts t _)
|
|
(tidy-print
|
|
t
|
|
print-raw-union
|
|
assemble-raw-union
|
|
#t))
|
|
(t (tidy-print
|
|
t
|
|
print-raw-union
|
|
assemble-raw-union
|
|
#t))))
|
|
(define tidy-print
|
|
(lambda (t print assemble top)
|
|
(let* ((share (shared-unions t top))
|
|
(bindings
|
|
(map-with-n
|
|
(lambda (t n)
|
|
(list t
|
|
(box #f)
|
|
(box #f)
|
|
(symbol-append "Y" (+ 1 n))))
|
|
share))
|
|
(body (print t (print-binding bindings)))
|
|
(let-bindings
|
|
(filter-map
|
|
(match-lambda
|
|
((_ _ ($ box #f) _) #f)
|
|
((_ ($ box t) ($ box x) _) (list x t)))
|
|
bindings)))
|
|
(assemble let-bindings body))))
|
|
(define print-binding
|
|
(lambda (bindings)
|
|
(lambda (ty share-wrapper var-wrapper render)
|
|
(match (assq ty bindings)
|
|
(#f (render))
|
|
((_ box-tprint box-name nprint)
|
|
(var-wrapper
|
|
(or (unbox box-name)
|
|
(begin
|
|
(set-box! box-name nprint)
|
|
(set-box! box-tprint (share-wrapper (render)))
|
|
nprint))))))))
|
|
(define shared-unions
|
|
(lambda (t all)
|
|
(let ((seen '()))
|
|
(recur loop
|
|
((t t) (top #t))
|
|
(match t
|
|
(($ box (? v?)) #f)
|
|
(($ box ($ c _ _ _ _ a n))
|
|
(match (and top (assq t seen))
|
|
(#f
|
|
(set! seen (cons (cons t (box 1)) seen))
|
|
(for-each (lambda (x) (loop x #t)) a)
|
|
(loop n all))
|
|
((_ . b) (set-box! b (+ 1 (unbox b))))))
|
|
(($ box (? symbol?)) #f)
|
|
(($ box i) (loop i top))))
|
|
(reverse
|
|
(filter-map
|
|
(match-lambda ((_ $ box 1) #f) ((t . _) t))
|
|
seen)))))
|
|
(define print-raw-union
|
|
(lambda (t print-share)
|
|
(recur loop
|
|
((t t))
|
|
(match t
|
|
(($ box ($ v _ _ _ _ split _))
|
|
(if (and share split)
|
|
(string->symbol (sprintf "~a#" (pvar t)))
|
|
(pvar t)))
|
|
(($ box ($ c d k x p a n))
|
|
(print-share
|
|
t
|
|
(lambda (x) x)
|
|
(lambda (x) x)
|
|
(lambda ()
|
|
(let* ((name (if (abs? k)
|
|
(symbol-append '~ (k-name x))
|
|
(k-name x)))
|
|
(name (if dump-depths
|
|
(symbol-append d '! name)
|
|
name))
|
|
(pr-x `(,name ,@(maplr loop (cons p a)))))
|
|
(cons pr-x (loop n))))))
|
|
(($ box 'top) '+)
|
|
(($ box 'bot) '-)
|
|
(($ box i) (loop i))))))
|
|
(define assemble-raw-union
|
|
(lambda (bindings body)
|
|
(if (null? bindings) body `(rec ,bindings ,body))))
|
|
(define print-union
|
|
(lambda (t print-share)
|
|
(add-+ (recur loop
|
|
((t t) (tailvis (visible? (tailvar t))))
|
|
(match t
|
|
(($ box (? v?))
|
|
(if (visible? t) (list (pvar t)) '()))
|
|
(($ box ($ c _ _ x p a n))
|
|
(print-share
|
|
t
|
|
add-+
|
|
list
|
|
(lambda ()
|
|
(cond ((visible? p)
|
|
(let* ((split-flag
|
|
(and share
|
|
(match (ind* p)
|
|
(($ box
|
|
($ v
|
|
_
|
|
_
|
|
_
|
|
_
|
|
split
|
|
_))
|
|
split)
|
|
(_ #f))))
|
|
(kname (if split-flag
|
|
(string->symbol
|
|
(sprintf
|
|
"~a#~a"
|
|
(k-name x)
|
|
(pvar p)))
|
|
(k-name x))))
|
|
(cons (cond ((null? a) kname)
|
|
((eq? '?-> (k-name x))
|
|
(let ((arg (add-+ (loop (car a)
|
|
(visible?
|
|
(tailvar
|
|
(car a))))))
|
|
(res (add-+ (loop (cadr a)
|
|
(visible?
|
|
(tailvar
|
|
(cadr a)))))))
|
|
(decode-arrow
|
|
kname
|
|
(lambda ()
|
|
(if split-flag
|
|
(string->symbol
|
|
(sprintf
|
|
"->#~a"
|
|
(pvar p)))
|
|
'->))
|
|
arg
|
|
res)))
|
|
((eq? 'record (k-name x))
|
|
`(,kname
|
|
,@(loop (car a) #f)))
|
|
(else
|
|
`(,kname
|
|
,@(maplr (lambda (x)
|
|
(add-+ (loop x
|
|
(visible?
|
|
(tailvar
|
|
x)))))
|
|
a))))
|
|
(loop n tailvis))))
|
|
((not tailvis) (loop n tailvis))
|
|
(else
|
|
(cons `(not ,(k-name x))
|
|
(loop n tailvis)))))))
|
|
(($ box 'bot) '())
|
|
(($ box i) (loop i tailvis)))))))
|
|
(define assemble-union
|
|
(lambda (bindings body)
|
|
(subst-small-type
|
|
(map clean-binding bindings)
|
|
body)))
|
|
(define add-+
|
|
(match-lambda
|
|
(() 'empty)
|
|
((t) t)
|
|
(x (cons '+ x))))
|
|
(define tailvar
|
|
(lambda (t)
|
|
(match t
|
|
(($ box (? v?)) t)
|
|
(($ box ($ c _ _ _ _ _ n)) (tailvar n))
|
|
(($ box 'bot) t)
|
|
(($ box i) (tailvar i)))))
|
|
(define decode-arrow
|
|
(lambda (kname thunk-> arg res)
|
|
(let ((args (recur loop
|
|
((l arg))
|
|
(match l
|
|
('noarg '())
|
|
(('arg a b) `(,a ,@(loop b)))
|
|
(('+ ('arg a b) 'noarg . _)
|
|
`((&optional ,a) ,@(loop b)))
|
|
(('+ 'noarg ('arg a b) . _)
|
|
`((&optional ,a) ,@(loop b)))
|
|
((? symbol? z)
|
|
(if (rectypevar? z) `(,z) `((&rest ,z))))
|
|
(('+ 'noarg z) (loop z))
|
|
(('+ ('arg a b) z)
|
|
(loop `(+ (arg ,a ,b) noarg ,z)))))))
|
|
`(,@args ,(thunk->) ,res))))
|
|
(define rectypevar?
|
|
(lambda (s)
|
|
(memq (string-ref (symbol->string s) 0) '(#\Y))))
|
|
(define typevar?
|
|
(lambda (s)
|
|
(memq (string-ref (symbol->string s) 0)
|
|
'(#\X #\Z))))
|
|
(define clean-binding
|
|
(lambda (binding)
|
|
(match binding
|
|
((u ('+ 'nil ('cons a v)))
|
|
(if (and (equal? u v) (not (memq* u a)))
|
|
(list u `(list ,a))
|
|
binding))
|
|
((u ('+ ('cons a v) 'nil))
|
|
(if (and (equal? u v) (not (memq* u a)))
|
|
(list u `(list ,a))
|
|
binding))
|
|
((u ('+ 'nil ('cons a v) (? symbol? z)))
|
|
(if (and (equal? u v) (not (memq* u a)) (typevar? z))
|
|
(list u `(list* ,a ,z))
|
|
binding))
|
|
((u ('+ ('cons a v) 'nil (? symbol? z)))
|
|
(if (and (equal? u v) (not (memq* u a)) (typevar? z))
|
|
(list u `(list* ,a ,z))
|
|
binding))
|
|
((u ('+ 'noarg ('arg a v)))
|
|
(if (and (equal? u v) (not (memq* u a)))
|
|
(list u `(&list ,a))
|
|
binding))
|
|
((u ('+ ('arg a v) 'noarg))
|
|
(if (and (equal? u v) (not (memq* u a)))
|
|
(list u `(&list ,a))
|
|
binding))
|
|
(x x))))
|
|
(define memq*
|
|
(lambda (v t)
|
|
(recur loop
|
|
((t t))
|
|
(match t
|
|
((x . y) (or (loop x) (loop y)))
|
|
(_ (eq? v t))))))
|
|
(define subst-type
|
|
(lambda (new old t)
|
|
(match new
|
|
(('list elem) (subst-list elem old t))
|
|
(_ (subst* new old t)))))
|
|
(define subst-list
|
|
(lambda (elem old t)
|
|
(match t
|
|
((? symbol?) (if (eq? old t) `(list ,elem) t))
|
|
(('+ 'nil ('cons a (? symbol? b)))
|
|
(if (and (eq? b old) (equal? elem a))
|
|
`(list ,elem)
|
|
`(+ nil (cons ,(subst-list elem old a) ,b))))
|
|
(('+ ('cons a (? symbol? b)) 'nil)
|
|
(if (and (eq? b old) (equal? elem a))
|
|
`(list ,elem)
|
|
`(+ nil (cons ,(subst-list elem old a) ,b))))
|
|
((a . b)
|
|
(cons (subst-list elem old a)
|
|
(subst-list elem old b)))
|
|
(z z))))
|
|
(define subst*
|
|
(lambda (new old t)
|
|
(cond ((eq? old t) new)
|
|
((pair? t)
|
|
(cons (subst* new old (car t))
|
|
(subst* new old (cdr t))))
|
|
(else t))))
|
|
(define subst-small-type
|
|
(lambda (bindings body)
|
|
(recur loop
|
|
((bindings bindings) (newb '()) (body body))
|
|
(match bindings
|
|
(()
|
|
(let ((newb (filter
|
|
(match-lambda
|
|
((name type) (not (equal? name type))))
|
|
newb)))
|
|
(if (null? newb)
|
|
body
|
|
`(rec ,(reverse newb) ,body))))
|
|
(((and b (name type)) . rest)
|
|
(if (and (not (memq* name type)) (small-type? type))
|
|
(loop (subst-type type name rest)
|
|
(subst-type type name newb)
|
|
(subst-type type name body))
|
|
(loop rest (cons b newb) body)))))))
|
|
(define small-type?
|
|
(lambda (t)
|
|
(>= 8
|
|
(recur loop
|
|
((t t))
|
|
(match t
|
|
('+ 0)
|
|
((? symbol? s) 1)
|
|
((? number? n) 0)
|
|
((x . y) (+ (loop x) (loop y)))
|
|
(() 0))))))
|
|
(define qop
|
|
(lambda (s)
|
|
(string->symbol (string-append "# " s))))
|
|
(define qcons (qop "cons"))
|
|
(define qbox (qop "box"))
|
|
(define qlist (qop "list"))
|
|
(define qvector (qop "vector"))
|
|
(define initial-info
|
|
`((not (a -> bool))
|
|
(eqv? (a a -> bool))
|
|
(eq? (a a -> bool))
|
|
(equal? (a a -> bool))
|
|
(cons (a b -> (cons a b)) (ic))
|
|
(car ((cons a b) -> a) (s (x . _)))
|
|
(cdr ((cons b a) -> a) (s (_ . x)))
|
|
(caar ((cons (cons a b) c) -> a)
|
|
(s ((x . _) . _)))
|
|
(cadr ((cons c (cons a b)) -> a) (s (_ x . _)))
|
|
(cdar ((cons (cons b a) c) -> a)
|
|
(s ((_ . x) . _)))
|
|
(cddr ((cons c (cons b a)) -> a) (s (_ _ . x)))
|
|
(caaar ((cons (cons (cons a b) c) d) -> a)
|
|
(s (((x . _) . _) . _)))
|
|
(caadr ((cons d (cons (cons a b) c)) -> a)
|
|
(s (_ (x . _) . _)))
|
|
(cadar ((cons (cons c (cons a b)) d) -> a)
|
|
(s ((_ x . _) . _)))
|
|
(caddr ((cons d (cons c (cons a b))) -> a)
|
|
(s (_ _ x . _)))
|
|
(cdaar ((cons (cons (cons b a) c) d) -> a)
|
|
(s (((_ . x) . _) . _)))
|
|
(cdadr ((cons d (cons (cons b a) c)) -> a)
|
|
(s (_ (_ . x) . _)))
|
|
(cddar ((cons (cons c (cons b a)) d) -> a)
|
|
(s ((_ _ . x) . _)))
|
|
(cdddr ((cons d (cons c (cons b a))) -> a)
|
|
(s (_ _ _ . x)))
|
|
(caaaar
|
|
((cons (cons (cons (cons a b) c) d) e) -> a)
|
|
(s ((((x . _) . _) . _) . _)))
|
|
(caaadr
|
|
((cons e (cons (cons (cons a b) c) d)) -> a)
|
|
(s (_ ((x . _) . _) . _)))
|
|
(caadar
|
|
((cons (cons d (cons (cons a b) c)) e) -> a)
|
|
(s ((_ (x . _) . _) . _)))
|
|
(caaddr
|
|
((cons e (cons d (cons (cons a b) c))) -> a)
|
|
(s (_ _ (x . _) . _)))
|
|
(cadaar
|
|
((cons (cons (cons c (cons a b)) d) e) -> a)
|
|
(s (((_ x . _) . _) . _)))
|
|
(cadadr
|
|
((cons e (cons (cons c (cons a b)) d)) -> a)
|
|
(s (_ (_ x . _) . _)))
|
|
(caddar
|
|
((cons (cons d (cons c (cons a b))) e) -> a)
|
|
(s ((_ _ x . _) . _)))
|
|
(cadddr
|
|
((cons e (cons d (cons c (cons a b)))) -> a)
|
|
(s (_ _ _ x . _)))
|
|
(cdaaar
|
|
((cons (cons (cons (cons b a) c) d) e) -> a)
|
|
(s ((((_ . x) . _) . _) . _)))
|
|
(cdaadr
|
|
((cons e (cons (cons (cons b a) c) d)) -> a)
|
|
(s (_ ((_ . x) . _) . _)))
|
|
(cdadar
|
|
((cons (cons d (cons (cons b a) c)) e) -> a)
|
|
(s ((_ (_ . x) . _) . _)))
|
|
(cdaddr
|
|
((cons e (cons d (cons (cons b a) c))) -> a)
|
|
(s (_ _ (_ . x) . _)))
|
|
(cddaar
|
|
((cons (cons (cons c (cons b a)) d) e) -> a)
|
|
(s (((_ _ . x) . _) . _)))
|
|
(cddadr
|
|
((cons e (cons (cons c (cons b a)) d)) -> a)
|
|
(s (_ (_ _ . x) . _)))
|
|
(cdddar
|
|
((cons (cons d (cons c (cons b a))) e) -> a)
|
|
(s ((_ _ _ . x) . _)))
|
|
(cddddr
|
|
((cons e (cons d (cons c (cons b a)))) -> a)
|
|
(s (_ _ _ _ . x)))
|
|
(set-car! ((cons a b) a -> void))
|
|
(set-cdr! ((cons a b) b -> void))
|
|
(list ((&list a) -> (list a)) (ic))
|
|
(length ((list a) -> num))
|
|
(append ((&list (list a)) -> (list a)) (ic) (d))
|
|
(reverse ((list a) -> (list a)) (ic))
|
|
(list-tail ((list a) num -> (list a)) (c))
|
|
(list-ref ((list a) num -> a) (c))
|
|
(memq (a (list a) -> (+ false (cons a (list a)))))
|
|
(memv (a (list a) -> (+ false (cons a (list a)))))
|
|
(member
|
|
(a (list a) -> (+ false (cons a (list a)))))
|
|
(assq (a (list (cons a c)) -> (+ false (cons a c))))
|
|
(assv (a (list (cons a c)) -> (+ false (cons a c))))
|
|
(assoc (a (list (cons a c)) -> (+ false (cons a c))))
|
|
(symbol->string (sym -> str))
|
|
(string->symbol (str -> sym))
|
|
(complex? (a -> bool))
|
|
(real? (a -> bool))
|
|
(rational? (a -> bool))
|
|
(integer? (a -> bool))
|
|
(exact? (num -> bool))
|
|
(inexact? (num -> bool))
|
|
(= (num num (&list num) -> bool))
|
|
(< (num num (&list num) -> bool))
|
|
(> (num num (&list num) -> bool))
|
|
(<= (num num (&list num) -> bool))
|
|
(>= (num num (&list num) -> bool))
|
|
(zero? (num -> bool))
|
|
(positive? (num -> bool))
|
|
(negative? (num -> bool))
|
|
(odd? (num -> bool))
|
|
(even? (num -> bool))
|
|
(max (num (&list num) -> num))
|
|
(min (num (&list num) -> num))
|
|
(+ ((&list num) -> num))
|
|
(* ((&list num) -> num))
|
|
(- (num (&list num) -> num))
|
|
(/ (num (&list num) -> num))
|
|
(abs (num -> num))
|
|
(quotient (num num -> num))
|
|
(remainder (num num -> num))
|
|
(modulo (num num -> num))
|
|
(gcd ((&list num) -> num))
|
|
(lcm ((&list num) -> num))
|
|
(numerator (num -> num))
|
|
(denominator (num -> num))
|
|
(floor (num -> num))
|
|
(ceiling (num -> num))
|
|
(truncate (num -> num))
|
|
(round (num -> num))
|
|
(rationalize (num num -> num))
|
|
(exp (num -> num))
|
|
(log (num -> num))
|
|
(sin (num -> num))
|
|
(cos (num -> num))
|
|
(tan (num -> num))
|
|
(asin (num -> num))
|
|
(acos (num -> num))
|
|
(atan (num (&optional num) -> num))
|
|
(sqrt (num -> num))
|
|
(expt (num num -> num))
|
|
(make-rectangular (num num -> num))
|
|
(make-polar (num num -> num))
|
|
(real-part (num -> num))
|
|
(imag-part (num -> num))
|
|
(magnitude (num -> num))
|
|
(angle (num -> num))
|
|
(exact->inexact (num -> num))
|
|
(inexact->exact (num -> num))
|
|
(number->string (num (&optional num) -> str))
|
|
(string->number (str (&optional num) -> num))
|
|
(char=? (char char -> bool))
|
|
(char<? (char char -> bool))
|
|
(char>? (char char -> bool))
|
|
(char<=? (char char -> bool))
|
|
(char>=? (char char -> bool))
|
|
(char-ci=? (char char -> bool))
|
|
(char-ci<? (char char -> bool))
|
|
(char-ci>? (char char -> bool))
|
|
(char-ci<=? (char char -> bool))
|
|
(char-ci>=? (char char -> bool))
|
|
(char-alphabetic? (char -> bool))
|
|
(char-numeric? (char -> bool))
|
|
(char-whitespace? (char -> bool))
|
|
(char-upper-case? (char -> bool))
|
|
(char-lower-case? (char -> bool))
|
|
(char->integer (char -> num))
|
|
(integer->char (num -> char))
|
|
(char-upcase (char -> char))
|
|
(char-downcase (char -> char))
|
|
(make-string (num (&optional char) -> str))
|
|
(string ((&list char) -> str))
|
|
(string-length (str -> num))
|
|
(string-ref (str num -> char))
|
|
(string-set! (str num char -> void))
|
|
(string=? (str str -> bool))
|
|
(string<? (str str -> bool))
|
|
(string>? (str str -> bool))
|
|
(string<=? (str str -> bool))
|
|
(string>=? (str str -> bool))
|
|
(string-ci=? (str str -> bool))
|
|
(string-ci<? (str str -> bool))
|
|
(string-ci>? (str str -> bool))
|
|
(string-ci<=? (str str -> bool))
|
|
(string-ci>=? (str str -> bool))
|
|
(substring (str num num -> str))
|
|
(string-append ((&list str) -> str))
|
|
(string->list (str -> (list char)) (ic))
|
|
(list->string ((list char) -> str))
|
|
(string-copy (str -> str))
|
|
(string-fill! (str char -> void))
|
|
(make-vector (num a -> (vec a)) (i))
|
|
(vector ((&list a) -> (vec a)) (i))
|
|
(vector-length ((vec a) -> num))
|
|
(vector-ref ((vec a) num -> a))
|
|
(vector-set! ((vec a) num a -> void))
|
|
(vector->list ((vec a) -> (list a)) (ic))
|
|
(list->vector ((list a) -> (vec a)) (i))
|
|
(vector-fill! ((vec a) a -> void))
|
|
(apply (((&list a) -> b) (list a) -> b) (i) (d))
|
|
(map ((a -> b) (list a) -> (list b)) (i) (d))
|
|
(for-each ((a -> b) (list a) -> void) (i) (d))
|
|
(force ((promise a) -> a) (i))
|
|
(call-with-current-continuation
|
|
(((a -> b) -> a) -> a)
|
|
(i))
|
|
(call-with-input-file
|
|
(str (iport -> a) -> a)
|
|
(i))
|
|
(call-with-output-file
|
|
(str (oport -> a) -> a)
|
|
(i))
|
|
(input-port? (a -> bool))
|
|
(output-port? (a -> bool))
|
|
(current-input-port (-> iport))
|
|
(current-output-port (-> oport))
|
|
(with-input-from-file (str (-> a) -> a) (i))
|
|
(with-output-to-file (str (-> a) -> a) (i))
|
|
(open-input-file (str -> iport))
|
|
(open-output-file (str -> oport))
|
|
(close-input-port (iport -> void))
|
|
(close-output-port (oport -> void))
|
|
(read ((&optional iport)
|
|
->
|
|
(+ eof
|
|
num
|
|
nil
|
|
false
|
|
true
|
|
char
|
|
sym
|
|
str
|
|
(box (mu sexp
|
|
(+ num
|
|
nil
|
|
false
|
|
true
|
|
char
|
|
sym
|
|
str
|
|
(vec sexp)
|
|
(cons sexp sexp)
|
|
(box sexp))))
|
|
(cons sexp sexp)
|
|
(vec sexp)))
|
|
(i))
|
|
(read-char
|
|
((&optional iport) -> (+ char eof))
|
|
(i))
|
|
(peek-char
|
|
((&optional iport) -> (+ char eof))
|
|
(i))
|
|
(char-ready? ((&optional iport) -> bool) (i))
|
|
(write (a (&optional oport) -> void) (i))
|
|
(display (a (&optional oport) -> void) (i))
|
|
(newline ((&optional oport) -> void) (i))
|
|
(write-char (char (&optional oport) -> void) (i))
|
|
(load (str -> void))
|
|
(transcript-on (str -> void))
|
|
(transcript-off (-> void))
|
|
(symbol-append ((&rest a) -> sym))
|
|
(box (a -> (box a)) (i))
|
|
(unbox ((box a) -> a) (s boxx))
|
|
(set-box! ((box a) a -> void))
|
|
(void (-> void))
|
|
(make-module (a -> (module a)))
|
|
(raise ((&rest a) -> b))
|
|
(match:error (a (&rest b) -> c))
|
|
(should-never-reach (a -> b))
|
|
(make-cvector (num a -> (cvec a)))
|
|
(cvector ((&list a) -> (cvec a)))
|
|
(cvector-length ((cvec a) -> num))
|
|
(cvector-ref ((cvec a) num -> a))
|
|
(cvector->list ((cvec a) -> (list a)) (ic))
|
|
(list->cvector ((list a) -> (cvec a)))
|
|
(,qcons (a b -> (cons a b)) (ic) (n))
|
|
(,qvector ((&list a) -> (vec a)) (i) (n))
|
|
(,qbox (a -> (box a)) (i) (n))
|
|
(,qlist ((&list a) -> (list a)) (ic) (n))
|
|
(number? ((+ num x) -> bool) (p (num)))
|
|
(null? ((+ nil x) -> bool) (p (nil)))
|
|
(char? ((+ char x) -> bool) (p (char)))
|
|
(symbol? ((+ sym x) -> bool) (p (sym)))
|
|
(string? ((+ str x) -> bool) (p (str)))
|
|
(vector? ((+ (vec a) x) -> bool) (p (vec a)))
|
|
(cvector? ((+ (cvec a) x) -> bool) (p (cvec a)))
|
|
(box? ((+ (box a) x) -> bool) (p (box a)))
|
|
(pair? ((+ (cons a b) x) -> bool) (p (cons a b)))
|
|
(procedure?
|
|
((+ ((&rest a) -> b) x) -> bool)
|
|
(p (?-> a b)))
|
|
(eof-object? ((+ eof x) -> bool) (p (eof)))
|
|
(input-port? ((+ iport x) -> bool) (p (iport)))
|
|
(output-port? ((+ oport x) -> bool) (p (oport)))
|
|
(true-object? ((+ true x) -> bool) (p (true)))
|
|
(false-object? ((+ false x) -> bool) (p (false)))
|
|
(module?
|
|
((+ (module a) x) -> bool)
|
|
(p (module a)))
|
|
(boolean? ((+ true false x) -> bool) (p #t))
|
|
(list? ((mu u (+ nil (cons y u) x)) -> bool)
|
|
(p #t))))
|
|
(define initial-env '())
|
|
(define init-env!
|
|
(lambda ()
|
|
(set! initial-env
|
|
(foldr init-prim empty-env initial-info))))
|
|
(define init-prim
|
|
(lambda (l env)
|
|
(letrec ((build-selector
|
|
(match-lambda
|
|
('x (lambda (x) x))
|
|
('_ (lambda (x) (make-pany)))
|
|
('boxx
|
|
(let ((c (lookup env 'box?)))
|
|
(lambda (x) (make-pobj c (list x)))))
|
|
((x . y)
|
|
(let ((c (lookup env 'pair?))
|
|
(lx (build-selector x))
|
|
(ly (build-selector y)))
|
|
(lambda (x) (make-pobj c (list (lx x) (ly x)))))))))
|
|
(match l
|
|
((name type . attr)
|
|
(let* ((pure (cond ((assq 'i attr) #f)
|
|
((assq 'ic attr) 'cons)
|
|
(else #t)))
|
|
(def (assq 'd attr))
|
|
(check (assq 'c attr))
|
|
(nocheck (assq 'n attr))
|
|
(pred (match (assq 'p attr)
|
|
(#f #f)
|
|
((_ #t) #t)
|
|
((_ (tag . args))
|
|
(cons (lookup initial-type-env tag) args))))
|
|
(sel (match (assq 's attr)
|
|
(#f #f)
|
|
((_ s) (build-selector s))))
|
|
(env1 (extend-env
|
|
env
|
|
name
|
|
(make-name
|
|
name
|
|
(closeall (r+ initial-type-env type))
|
|
#f
|
|
0
|
|
#f
|
|
#f
|
|
(cond (nocheck 'nocheck)
|
|
(check 'check)
|
|
(def 'imprecise)
|
|
(else #t))
|
|
#f
|
|
pure
|
|
pred
|
|
#f
|
|
sel)))
|
|
(env2 (extend-env
|
|
env1
|
|
(symbol-append 'check- name)
|
|
(make-name
|
|
(symbol-append 'check- name)
|
|
(closeall (r++ initial-type-env type))
|
|
#f
|
|
0
|
|
#f
|
|
#f
|
|
#t
|
|
#f
|
|
pure
|
|
pred
|
|
#f
|
|
sel))))
|
|
env2))))))
|
|
(define defprim
|
|
(lambda (name type mode)
|
|
(handle
|
|
(r+ initial-type-env type)
|
|
(match-lambda*
|
|
(('type . args) (apply syntax-err type args))
|
|
(x (apply raise x))))
|
|
(let* ((attr (match mode
|
|
('impure '((i)))
|
|
('pure '())
|
|
('pure-if-cons-is '((ic)))
|
|
('mutates-cons
|
|
(set! cons-mutators (cons name cons-mutators))
|
|
'())
|
|
(x (use-error
|
|
"invalid attribute ~a for st:defprim"
|
|
x))))
|
|
(info `(,name ,type ,@attr)))
|
|
(unless
|
|
(equal? info (assq name initial-info))
|
|
(set! initial-info (cons info initial-info))
|
|
(set! initial-env (init-prim info initial-env))))))
|
|
(init-types!)
|
|
(init-env!)
|
|
(define %not (lookup initial-env 'not))
|
|
(define %list (lookup initial-env 'list))
|
|
(define %cons (lookup initial-env 'cons))
|
|
(define %should-never-reach
|
|
(lookup initial-env 'should-never-reach))
|
|
(define %false-object?
|
|
(lookup initial-env 'false-object?))
|
|
(define %eq? (lookup initial-env 'eq?))
|
|
(define %eqv? (lookup initial-env 'eqv?))
|
|
(define %equal? (lookup initial-env 'equal?))
|
|
(define %null? (lookup initial-env 'null?))
|
|
(define %vector? (lookup initial-env 'vector?))
|
|
(define %cvector? (lookup initial-env 'cvector?))
|
|
(define %list? (lookup initial-env 'list?))
|
|
(define %boolean? (lookup initial-env 'boolean?))
|
|
(define %procedure?
|
|
(lookup initial-env 'procedure?))
|
|
(define n-unbound 0)
|
|
(define bind-defs
|
|
(lambda (defs env0 tenv0 old-unbound timestamp)
|
|
(letrec ((cons-mutable #f)
|
|
(unbound '())
|
|
(use-var
|
|
(lambda (x env context mk-node)
|
|
(match (lookup? env x)
|
|
(#f
|
|
(let* ((b (bind-var x)) (n (mk-node b)))
|
|
(set-name-timestamp! b context)
|
|
(set! unbound (cons n unbound))
|
|
n))
|
|
(b (when (and (name-primitive b)
|
|
(memq x cons-mutators))
|
|
(set! cons-mutable #t))
|
|
(set-name-occ! b (+ 1 (name-occ b)))
|
|
(mk-node b)))))
|
|
(bind-var
|
|
(lambda (x)
|
|
(make-name
|
|
x
|
|
#f
|
|
timestamp
|
|
0
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f)))
|
|
(bind (lambda (e env tenv context)
|
|
(let ((bind-cur (lambda (x) (bind x env tenv context))))
|
|
(match e
|
|
(($ var x) (use-var x env context make-var))
|
|
(($ prim x)
|
|
(use-var x initial-env context make-var))
|
|
(($ const c pred)
|
|
(use-var
|
|
pred
|
|
initial-env
|
|
context
|
|
(lambda (p) (make-const c p))))
|
|
(($ lam args e2)
|
|
(let* ((b-args (map bind-var args))
|
|
(newenv (extend-env* env args b-args)))
|
|
(make-lam
|
|
b-args
|
|
(bind e2 newenv tenv context))))
|
|
(($ vlam args rest e2)
|
|
(let* ((b-args (map bind-var args))
|
|
(b-rest (bind-var rest))
|
|
(newenv
|
|
(extend-env*
|
|
env
|
|
(cons rest args)
|
|
(cons b-rest b-args))))
|
|
(make-vlam
|
|
b-args
|
|
b-rest
|
|
(bind e2 newenv tenv context))))
|
|
(($ match e1 clauses)
|
|
(make-match
|
|
(bind-cur e1)
|
|
(map (lambda (x)
|
|
(bind-mclause x env tenv context))
|
|
clauses)))
|
|
(($ app e1 args)
|
|
(make-app (bind-cur e1) (map bind-cur args)))
|
|
(($ begin exps) (make-begin (map bind-cur exps)))
|
|
(($ and exps) (make-and (map bind-cur exps)))
|
|
(($ or exps) (make-or (map bind-cur exps)))
|
|
(($ if test then els)
|
|
(make-if
|
|
(bind-cur test)
|
|
(bind-cur then)
|
|
(bind-cur els)))
|
|
(($ delay e2) (make-delay (bind-cur e2)))
|
|
(($ set! x e2)
|
|
(use-var
|
|
x
|
|
env
|
|
context
|
|
(lambda (b)
|
|
(when (name-struct b)
|
|
(syntax-err
|
|
(pexpr e)
|
|
"define-structure identifier ~a may not be assigned"
|
|
x))
|
|
(when (name-primitive b)
|
|
(syntax-err
|
|
(pexpr e)
|
|
"(set! ~a ...) requires (define ~a ...)"
|
|
x
|
|
x))
|
|
(when (and (not (name-mutated b))
|
|
(not (= (name-timestamp b)
|
|
timestamp)))
|
|
(syntax-err
|
|
(pexpr e)
|
|
"(set! ~a ...) missing from compilation unit defining ~a"
|
|
x
|
|
x))
|
|
(set-name-mutated! b #t)
|
|
(make-set! b (bind-cur e2)))))
|
|
(($ let args e2)
|
|
(let* ((b-args
|
|
(map (match-lambda
|
|
(($ bind x e)
|
|
(make-bind
|
|
(bind-var x)
|
|
(bind-cur e))))
|
|
args))
|
|
(newenv
|
|
(extend-env*
|
|
env
|
|
(map bind-name args)
|
|
(map bind-name b-args))))
|
|
(make-let
|
|
b-args
|
|
(bind e2 newenv tenv context))))
|
|
(($ let* args e2)
|
|
(recur loop
|
|
((args args) (b-args '()) (env env))
|
|
(match args
|
|
((($ bind x e) . rest)
|
|
(let ((b (bind-var x)))
|
|
(loop rest
|
|
(cons (make-bind
|
|
b
|
|
(bind e
|
|
env
|
|
tenv
|
|
context))
|
|
b-args)
|
|
(extend-env env x b))))
|
|
(()
|
|
(make-let*
|
|
(reverse b-args)
|
|
(bind e2 env tenv context))))))
|
|
(($ letr args e2)
|
|
(let* ((b-args
|
|
(map (match-lambda
|
|
(($ bind x e)
|
|
(make-bind (bind-var x) e)))
|
|
args))
|
|
(newenv
|
|
(extend-env*
|
|
env
|
|
(map bind-name args)
|
|
(map bind-name b-args)))
|
|
(b-args
|
|
(map (match-lambda
|
|
(($ bind b e)
|
|
(let* ((n (name-occ b))
|
|
(e2 (bind e
|
|
newenv
|
|
tenv
|
|
context)))
|
|
(set-name-occ! b n)
|
|
(make-bind b e2))))
|
|
b-args)))
|
|
(make-letr
|
|
b-args
|
|
(bind e2 newenv tenv context))))
|
|
(($ body defs exps)
|
|
(match-let*
|
|
(((defs newenv newtenv)
|
|
(bind-defn defs env tenv #f)))
|
|
(make-body
|
|
defs
|
|
(map (lambda (x)
|
|
(bind x newenv newtenv context))
|
|
exps))))
|
|
(($ record args)
|
|
(make-record
|
|
(map (match-lambda
|
|
(($ bind x e)
|
|
(new-field! x)
|
|
(make-bind x (bind-cur e))))
|
|
args)))
|
|
(($ field x e2)
|
|
(new-field! x)
|
|
(make-field x (bind-cur e2)))
|
|
(($ cast ty e2)
|
|
(match-let
|
|
(((t absv)
|
|
(handle
|
|
(r+collect
|
|
tenv
|
|
(match ty
|
|
(('rec bind ty2)
|
|
`(rec ,bind (,ty2 -> ,ty2)))
|
|
(_ `(,ty -> ,ty))))
|
|
(match-lambda*
|
|
(('type . args)
|
|
(apply syntax-err ty args))
|
|
(x (apply raise x))))))
|
|
(make-cast
|
|
(list ty t absv)
|
|
(bind-cur e2))))))))
|
|
(bind-mclause
|
|
(lambda (clause env tenv context)
|
|
(match-let*
|
|
((($ mclause pattern body failsym) clause)
|
|
(patenv empty-env)
|
|
(bp (recur loop
|
|
((p pattern))
|
|
(match p
|
|
(($ pvar x)
|
|
(when (bound? patenv x)
|
|
(syntax-err
|
|
(ppat pattern)
|
|
"pattern variable ~a repeated"
|
|
x))
|
|
(let ((b (bind-var x)))
|
|
(set! patenv (extend-env patenv x b))
|
|
(make-pvar b)))
|
|
(($ pobj c args)
|
|
(use-var
|
|
c
|
|
env
|
|
context
|
|
(lambda (b)
|
|
(cond ((boolean? (name-predicate b))
|
|
(syntax-err
|
|
(ppat pattern)
|
|
"~a is not a predicate"
|
|
c))
|
|
((and (not (eq? b %vector?))
|
|
(not (eq? b %cvector?))
|
|
(not (= (length
|
|
(cdr (name-predicate
|
|
b)))
|
|
(length args))))
|
|
(syntax-err
|
|
(ppat pattern)
|
|
"~a requires ~a sub-patterns"
|
|
c
|
|
(length
|
|
(cdr (name-predicate
|
|
b)))))
|
|
(else
|
|
(make-pobj
|
|
b
|
|
(map loop args)))))))
|
|
(($ pand pats)
|
|
(make-pand (map loop pats)))
|
|
(($ pnot pat) (make-pnot (loop pat)))
|
|
(($ ppred pred)
|
|
(use-var
|
|
pred
|
|
env
|
|
context
|
|
(lambda (b)
|
|
(unless
|
|
(name-predicate b)
|
|
(syntax-err
|
|
(ppat pattern)
|
|
"~a is not a predicate"
|
|
pred))
|
|
(make-ppred b))))
|
|
(($ pany) p)
|
|
(($ pelse) p)
|
|
(($ pconst c pred)
|
|
(use-var
|
|
pred
|
|
initial-env
|
|
context
|
|
(lambda (p) (make-pconst c p))))))))
|
|
(if failsym
|
|
(let ((b (bind-var failsym)))
|
|
(when (bound? patenv failsym)
|
|
(syntax-err
|
|
(ppat pattern)
|
|
"fail symbol ~a repeated"
|
|
failsym))
|
|
(set! patenv (extend-env patenv failsym b))
|
|
(make-mclause
|
|
bp
|
|
(bind body (join-env env patenv) tenv context)
|
|
b))
|
|
(make-mclause
|
|
bp
|
|
(bind body (join-env env patenv) tenv context)
|
|
#f)))))
|
|
(bind-defn
|
|
(lambda (defs env tenv glob)
|
|
(let* ((newenv empty-env)
|
|
(newtenv empty-env)
|
|
(struct-def
|
|
(lambda (x pure)
|
|
(when (or (bound? newenv x)
|
|
(and glob (bound? initial-env x)))
|
|
(syntax-err
|
|
#f
|
|
"~a defined more than once"
|
|
x))
|
|
(let ((b (bind-var x)))
|
|
(set-name-primitive! b #t)
|
|
(set-name-struct! b #t)
|
|
(set-name-pure! b pure)
|
|
(set! newenv (extend-env newenv x b))
|
|
b)))
|
|
(bind1 (match-lambda
|
|
((and z ($ define x e))
|
|
(cond ((not x) z)
|
|
((bound? newenv x)
|
|
(if glob
|
|
(make-define #f (make-set! x e))
|
|
(syntax-err
|
|
#f
|
|
"~a defined more than once"
|
|
x)))
|
|
(else
|
|
(let ((b (bind-var x)))
|
|
(set-name-gdef! b glob)
|
|
(set! newenv
|
|
(extend-env newenv x b))
|
|
(make-define b e)))))
|
|
((and d
|
|
($ defstruct
|
|
tag
|
|
args
|
|
make
|
|
pred
|
|
get
|
|
set
|
|
getn
|
|
setn
|
|
mutable))
|
|
(let* ((make (struct-def
|
|
make
|
|
(map not mutable)))
|
|
(pred (struct-def pred #t))
|
|
(bind-get
|
|
(lambda (name n)
|
|
(match name
|
|
(($ some x)
|
|
(let ((b (struct-def
|
|
x
|
|
#t)))
|
|
(set-name-selector!
|
|
b
|
|
(lambda (x)
|
|
(make-pobj
|
|
pred
|
|
(map-with-n
|
|
(lambda (_ m)
|
|
(if (= m n)
|
|
x
|
|
(make-pany)))
|
|
get))))
|
|
(some b)))
|
|
(none none))))
|
|
(bind-set
|
|
(match-lambda
|
|
(($ some x)
|
|
(some (struct-def x #t)))
|
|
(none none)))
|
|
(get (map-with-n bind-get get))
|
|
(getn (map-with-n bind-get getn))
|
|
(set (map bind-set set))
|
|
(setn (map bind-set setn))
|
|
(_ (when (bound? newtenv tag)
|
|
(syntax-err
|
|
(pdef d)
|
|
"type constructor ~a defined more than once"
|
|
tag)))
|
|
(tc (bind-tycon
|
|
tag
|
|
mutable
|
|
(bound? tenv tag)
|
|
(lambda args
|
|
(apply syntax-err
|
|
(cons (pdef d)
|
|
args))))))
|
|
(set! newtenv (extend-env newtenv tag tc))
|
|
(set-name-predicate!
|
|
pred
|
|
`(,tc ,@(map (lambda (_) (gensym)) get)))
|
|
(make-defstruct
|
|
tc
|
|
args
|
|
make
|
|
pred
|
|
get
|
|
set
|
|
getn
|
|
setn
|
|
mutable)))
|
|
((and d ($ datatype dt))
|
|
(make-datatype
|
|
(maplr (match-lambda
|
|
(((tag . args) . bindings)
|
|
(when (bound? newtenv tag)
|
|
(syntax-err
|
|
(pdef d)
|
|
"type constructor ~a defined more than once"
|
|
tag))
|
|
(let ((tc (bind-tycon
|
|
tag
|
|
(map (lambda (_) #f)
|
|
args)
|
|
(bound? tenv tag)
|
|
(lambda args
|
|
(apply syntax-err
|
|
(cons (pdef d)
|
|
args))))))
|
|
(set! newtenv
|
|
(extend-env newtenv tag tc))
|
|
(cons (cons tc args)
|
|
(maplr (match-lambda
|
|
(($ variant
|
|
con
|
|
pred
|
|
arg-types)
|
|
(let ((make (struct-def
|
|
con
|
|
#t))
|
|
(pred (struct-def
|
|
pred
|
|
#t)))
|
|
(set-name-predicate!
|
|
pred
|
|
(cons tc
|
|
args))
|
|
(set-name-variant!
|
|
pred
|
|
arg-types)
|
|
(make-variant
|
|
make
|
|
pred
|
|
arg-types))))
|
|
bindings)))))
|
|
dt)))))
|
|
(defs2 (maplr bind1 defs))
|
|
(newenv2 (join-env env newenv))
|
|
(newtenv2 (join-env tenv newtenv))
|
|
(bind2 (match-lambda
|
|
((and ($ define (? name? x) ($ var y)))
|
|
(=> fail)
|
|
(if (eq? (name-name x) y)
|
|
(if (bound? initial-env y)
|
|
(make-define
|
|
x
|
|
(make-var (lookup initial-env y)))
|
|
(begin
|
|
(printf
|
|
"Warning: (define ~a ~a) but ~a is not a primitive~%"
|
|
y
|
|
y
|
|
y)
|
|
(fail)))
|
|
(fail)))
|
|
((and ($ define x e2) context)
|
|
(when (and glob
|
|
(name? x)
|
|
(bound?
|
|
initial-env
|
|
(name-name x)))
|
|
(printf
|
|
"Note: (define ~a ...) hides primitive ~a~%"
|
|
(name-name x)
|
|
(name-name x)))
|
|
(make-define
|
|
(or x
|
|
(let ((b (bind-var x)))
|
|
(set-name-gdef! b glob)
|
|
b))
|
|
(bind e2 newenv2 newtenv2 context)))
|
|
(d d))))
|
|
(list (maplr bind2 defs2) newenv2 newtenv2))))
|
|
(bind-old
|
|
(lambda (e env)
|
|
(match e
|
|
(($ var x)
|
|
(match (lookup? env (name-name x))
|
|
(#f (set! unbound (cons e unbound)))
|
|
(b (when (and (name-primitive b)
|
|
(memq x cons-mutators))
|
|
(set! cons-mutable #t))
|
|
(set-name-occ! b (+ 1 (name-occ b)))
|
|
(set-var-name! e b))))
|
|
(($ set! x _)
|
|
(match (lookup? env (name-name x))
|
|
(#f (set! unbound (cons e unbound)))
|
|
(b (when (name-struct b)
|
|
(syntax-err
|
|
(pexpr e)
|
|
"define-structure identifier ~a may not be assigned"
|
|
x))
|
|
(when (name-primitive b)
|
|
(syntax-err
|
|
(pexpr e)
|
|
"(set! ~a ...) requires (define ~a ...)"
|
|
x
|
|
x))
|
|
(when (and (not (name-mutated b))
|
|
(not (= (name-timestamp b)
|
|
timestamp)))
|
|
(syntax-err
|
|
(pexpr e)
|
|
"(set! ~a ...) missing from compilation unit defining ~a"
|
|
x
|
|
x))
|
|
(set-name-mutated! b #t)
|
|
(set-name-occ! b (+ 1 (name-occ b)))
|
|
(set-set!-name! e b))))))))
|
|
(match-let
|
|
(((defs env tenv) (bind-defn defs env0 tenv0 #t)))
|
|
(for-each
|
|
(lambda (x) (bind-old x env))
|
|
old-unbound)
|
|
(set-cons-mutability! cons-mutable)
|
|
(set! n-unbound (length unbound))
|
|
(list defs env tenv unbound)))))
|
|
(define rebind-var
|
|
(lambda (b)
|
|
(make-name
|
|
(name-name b)
|
|
(name-ty b)
|
|
(name-timestamp b)
|
|
(name-occ b)
|
|
(name-mutated b)
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f
|
|
#f)))
|
|
(define warn-unbound
|
|
(lambda (l)
|
|
(let* ((names '())
|
|
(node->name
|
|
(match-lambda
|
|
(($ var x) x)
|
|
(($ set! x _) x)
|
|
(($ pobj x _) x)
|
|
(($ ppred x) x)))
|
|
(warn (lambda (b)
|
|
(unless
|
|
(memq (name-name b) names)
|
|
(set! names (cons (name-name b) names))
|
|
(printf
|
|
"Warning: ~a is unbound in "
|
|
(name-name b))
|
|
(print-context (pexpr (name-timestamp b)) 2)))))
|
|
(for-each (lambda (x) (warn (node->name x))) l))))
|
|
(define name-unbound?
|
|
(lambda (x) (not (number? (name-timestamp x)))))
|
|
(define improve-defs
|
|
(lambda (defs)
|
|
(map (match-lambda
|
|
(($ define x e2) (make-define x (improve e2)))
|
|
(x x))
|
|
defs)))
|
|
(define improve
|
|
(match-lambda
|
|
(($ match e clauses) (improve-match e clauses))
|
|
(($ if tst thn els) (improve-if tst thn els))
|
|
((? var? e) e)
|
|
((? const? e) e)
|
|
(($ lam args e2) (make-lam args (improve e2)))
|
|
(($ vlam args rest e2)
|
|
(make-vlam args rest (improve e2)))
|
|
(($ app (and e1 ($ var x)) args)
|
|
(let ((args (map improve args)))
|
|
(if (and (eq? x %list) (< (length args) conslimit))
|
|
(foldr (lambda (a rest)
|
|
(make-app (make-var %cons) (list a rest)))
|
|
(make-const '() %null?)
|
|
args)
|
|
(make-app e1 args))))
|
|
(($ app e1 args)
|
|
(make-app (improve e1) (map improve args)))
|
|
(($ begin exps) (make-begin (map improve exps)))
|
|
(($ and exps) (make-and (map improve exps)))
|
|
(($ or exps) (make-or (map improve exps)))
|
|
(($ delay e2) (make-delay (improve e2)))
|
|
(($ set! x e2) (make-set! x (improve e2)))
|
|
(($ let args e2)
|
|
(let ((args (map (match-lambda
|
|
(($ bind x e) (make-bind x (improve e))))
|
|
args)))
|
|
(make-let args (improve e2))))
|
|
(($ let* args e2)
|
|
(let ((args (map (match-lambda
|
|
(($ bind x e) (make-bind x (improve e))))
|
|
args)))
|
|
(make-let* args (improve e2))))
|
|
(($ letr args e2)
|
|
(let ((args (map (match-lambda
|
|
(($ bind x e) (make-bind x (improve e))))
|
|
args)))
|
|
(make-letr args (improve e2))))
|
|
(($ body defs exps)
|
|
(let ((defs (improve-defs defs)))
|
|
(make-body defs (map improve exps))))
|
|
(($ record args)
|
|
(make-record
|
|
(map (match-lambda
|
|
(($ bind x e) (make-bind x (improve e))))
|
|
args)))
|
|
(($ field x e2) (make-field x (improve e2)))
|
|
(($ cast ty e2) (make-cast ty (improve e2)))))
|
|
(define improve-if
|
|
(lambda (tst thn els)
|
|
(let ((if->match
|
|
(lambda (x p mk-s thn els)
|
|
(let ((else-pat
|
|
(match els
|
|
(($ app ($ var q) _)
|
|
(if (eq? q %should-never-reach)
|
|
(make-pelse)
|
|
(make-pany)))
|
|
(_ (make-pany)))))
|
|
(make-match
|
|
(make-var x)
|
|
(list (make-mclause
|
|
(mk-s (make-ppred p))
|
|
(make-body '() (list thn))
|
|
#f)
|
|
(make-mclause
|
|
(mk-s else-pat)
|
|
(make-body '() (list els))
|
|
#f)))))))
|
|
(match tst
|
|
(($ app ($ var v) (e))
|
|
(=> fail)
|
|
(if (eq? v %not) (improve-if e els thn) (fail)))
|
|
(($ app ($ var eq) (($ const #f _) val))
|
|
(=> fail)
|
|
(if (or (eq? eq %eq?)
|
|
(eq? eq %eqv?)
|
|
(eq? eq %equal?))
|
|
(improve-if val els thn)
|
|
(fail)))
|
|
(($ app ($ var eq) (val ($ const #f _)))
|
|
(=> fail)
|
|
(if (or (eq? eq %eq?)
|
|
(eq? eq %eqv?)
|
|
(eq? eq %equal?))
|
|
(improve-if val els thn)
|
|
(fail)))
|
|
(($ app ($ var v) (($ var x)))
|
|
(=> fail)
|
|
(if (and (name-predicate v) (not (name-mutated x)))
|
|
(improve (if->match x v (lambda (x) x) thn els))
|
|
(fail)))
|
|
(($ app ($ var v) (($ app ($ var s) (($ var x)))))
|
|
(=> fail)
|
|
(if (and (name-predicate v)
|
|
(name-selector s)
|
|
(not (name-mutated x)))
|
|
(improve
|
|
(if->match x v (name-selector s) thn els))
|
|
(fail)))
|
|
(($ app ($ var v) (($ var x)))
|
|
(=> fail)
|
|
(if (and (name-selector v) (not (name-mutated x)))
|
|
(improve
|
|
(if->match
|
|
x
|
|
%false-object?
|
|
(name-selector v)
|
|
els
|
|
thn))
|
|
(fail)))
|
|
(($ var v)
|
|
(=> fail)
|
|
(if (not (name-mutated v))
|
|
(improve
|
|
(if->match
|
|
v
|
|
%false-object?
|
|
(lambda (x) x)
|
|
els
|
|
thn))
|
|
(fail)))
|
|
(_ (make-if
|
|
(improve tst)
|
|
(improve thn)
|
|
(improve els)))))))
|
|
(define improve-match
|
|
(lambda (e clauses)
|
|
(let ((clauses
|
|
(map (match-lambda
|
|
(($ mclause p body fail)
|
|
(make-mclause p (improve body) fail)))
|
|
clauses)))
|
|
(match e
|
|
(($ var x)
|
|
(if (not (name-mutated x))
|
|
(let ((fix-clause
|
|
(match-lambda
|
|
((and c ($ mclause p e fail))
|
|
(if (not (uses-x? e x))
|
|
c
|
|
(let ((y (rebind-var x)))
|
|
(make-mclause
|
|
(make-flat-pand (list p (make-pvar y)))
|
|
(sub e x y)
|
|
fail)))))))
|
|
(make-match e (map fix-clause clauses)))
|
|
(make-match e clauses)))
|
|
(_ (make-match (improve e) clauses))))))
|
|
(define uses-x?
|
|
(lambda (e x)
|
|
(recur loop
|
|
((e e))
|
|
(match e
|
|
(($ and exps) (ormap loop exps))
|
|
(($ app fun args)
|
|
(or (loop fun) (ormap loop args)))
|
|
(($ begin exps) (ormap loop exps))
|
|
(($ if e1 e2 e3)
|
|
(or (loop e1) (loop e2) (loop e3)))
|
|
(($ lam names body) (loop body))
|
|
(($ let bindings body)
|
|
(or (ormap (match-lambda (($ bind _ b) (loop b)))
|
|
bindings)
|
|
(loop body)))
|
|
(($ let* bindings body)
|
|
(or (ormap (match-lambda (($ bind _ b) (loop b)))
|
|
bindings)
|
|
(loop body)))
|
|
(($ letr bindings body)
|
|
(or (ormap (match-lambda (($ bind _ b) (loop b)))
|
|
bindings)
|
|
(loop body)))
|
|
(($ or exps) (ormap loop exps))
|
|
(($ delay e2) (loop e2))
|
|
(($ set! name exp) (or (eq? x name) (loop exp)))
|
|
(($ var name) (eq? x name))
|
|
(($ vlam names name body) (loop body))
|
|
(($ match exp clauses)
|
|
(or (loop exp)
|
|
(ormap (match-lambda
|
|
(($ mclause p b _) (or (loop p) (loop b))))
|
|
clauses)))
|
|
(($ body defs exps)
|
|
(or (ormap loop defs) (ormap loop exps)))
|
|
(($ record bindings)
|
|
(ormap (match-lambda (($ bind _ b) (loop b)))
|
|
bindings))
|
|
(($ field _ e) (loop e))
|
|
(($ cast _ e) (loop e))
|
|
(($ define _ e) (loop e))
|
|
((? defstruct?) #f)
|
|
((? datatype?) #f)
|
|
(($ pand pats) (ormap loop pats))
|
|
(($ pnot pat) (loop pat))
|
|
(($ pobj c args) (ormap loop args))
|
|
(($ ppred pred) (eq? x pred))
|
|
(_ #f)))))
|
|
(define sub
|
|
(lambda (e x to)
|
|
(let ((dos (lambda (y) (if (eq? x y) to y))))
|
|
(recur sub
|
|
((e e))
|
|
(match e
|
|
(($ define x e) (make-define x (sub e)))
|
|
((? defstruct?) e)
|
|
((? datatype?) e)
|
|
(($ match e clauses)
|
|
(let ((clauses
|
|
(map (match-lambda
|
|
(($ mclause p e fail)
|
|
(make-mclause p (sub e) fail)))
|
|
clauses)))
|
|
(make-match (sub e) clauses)))
|
|
(($ if tst thn els)
|
|
(make-if (sub tst) (sub thn) (sub els)))
|
|
(($ var x) (make-var (dos x)))
|
|
((? const? e) e)
|
|
(($ lam args e2) (make-lam args (sub e2)))
|
|
(($ vlam args rest e2)
|
|
(make-vlam args rest (sub e2)))
|
|
(($ app e1 args)
|
|
(make-app (sub e1) (map sub args)))
|
|
(($ begin exps) (make-begin (map sub exps)))
|
|
(($ and exps) (make-and (map sub exps)))
|
|
(($ or exps) (make-or (map sub exps)))
|
|
(($ delay e2) (make-delay (sub e2)))
|
|
(($ set! x e2) (make-set! (dos x) (sub e2)))
|
|
(($ let args e2)
|
|
(let ((args (map (match-lambda
|
|
(($ bind x e) (make-bind x (sub e))))
|
|
args)))
|
|
(make-let args (sub e2))))
|
|
(($ let* args e2)
|
|
(let ((args (map (match-lambda
|
|
(($ bind x e) (make-bind x (sub e))))
|
|
args)))
|
|
(make-let* args (sub e2))))
|
|
(($ letr args e2)
|
|
(let ((args (map (match-lambda
|
|
(($ bind x e) (make-bind x (sub e))))
|
|
args)))
|
|
(make-letr args (sub e2))))
|
|
(($ body defs exps)
|
|
(make-body (map sub defs) (map sub exps)))
|
|
(($ record args)
|
|
(make-record
|
|
(map (match-lambda
|
|
(($ bind x e) (make-bind x (sub e))))
|
|
args)))
|
|
(($ field x e) (make-field x (sub e)))
|
|
(($ cast ty e) (make-cast ty (sub e))))))))
|
|
(define improve-clauses
|
|
(lambda (clauses)
|
|
(recur loop
|
|
((clauses clauses))
|
|
(match clauses
|
|
(() '())
|
|
((_) clauses)
|
|
(((and m1 ($ mclause p _ fail)) . rest)
|
|
(cons m1
|
|
(if fail
|
|
(loop rest)
|
|
(recur loop2
|
|
((clauses (loop rest)))
|
|
(match clauses
|
|
(() '())
|
|
(((and m ($ mclause p2 body2 fail2))
|
|
.
|
|
r)
|
|
(match (improve-by-pattern p2 p)
|
|
(('stop . p)
|
|
(cons (make-mclause
|
|
p
|
|
body2
|
|
fail2)
|
|
r))
|
|
(('redundant . p)
|
|
(unless
|
|
(null? r)
|
|
(printf
|
|
"Warning: redundant pattern ~a~%"
|
|
(ppat p2)))
|
|
(cons (make-mclause
|
|
p
|
|
body2
|
|
fail2)
|
|
r))
|
|
(('continue . p)
|
|
(cons (make-mclause
|
|
p
|
|
body2
|
|
fail2)
|
|
(loop2 r))))))))))))))
|
|
(define improve-by-pattern
|
|
(lambda (p2 p1)
|
|
(call-with-current-continuation
|
|
(lambda (k)
|
|
(let* ((reject (lambda () (k (cons 'continue p2))))
|
|
(p1covers #t)
|
|
(p2covers #t)
|
|
(p3 (recur m
|
|
((p1 p1) (p2 p2))
|
|
'(printf "(M ~a ~a)~%" (ppat p1) (ppat p2))
|
|
(match (cons p1 p2)
|
|
((($ pand (a . _)) . p2) (m a p2))
|
|
((p1 $ pand (a . b))
|
|
(make-flat-pand (cons (m p1 a) b)))
|
|
((($ pvar _) . _)
|
|
(unless
|
|
(or (pvar? p2) (pany? p2))
|
|
(set! p2covers #f))
|
|
p2)
|
|
((($ pany) . _)
|
|
(unless
|
|
(or (pvar? p2) (pany? p2))
|
|
(set! p2covers #f))
|
|
p2)
|
|
((($ pelse) . _)
|
|
'(unless
|
|
(or (pvar? p2) (pany? p2))
|
|
(set! p2covers #f))
|
|
p2)
|
|
((_ $ pvar _)
|
|
(unless p1covers (reject))
|
|
(set! p1covers #f)
|
|
(make-flat-pand (list p2 (make-pnot p1))))
|
|
((_ $ pany)
|
|
(unless p1covers (reject))
|
|
(set! p1covers #f)
|
|
(make-flat-pand (list p2 (make-pnot p1))))
|
|
((_ $ pelse)
|
|
(unless p1covers (reject))
|
|
(set! p1covers #f)
|
|
(make-flat-pand (list p2 (make-pnot p1))))
|
|
((($ pconst a _) $ pconst b _)
|
|
(unless (equal? a b) (reject))
|
|
p2)
|
|
((($ pobj tag1 a) $ pobj tag2 b)
|
|
(unless (eq? tag1 tag2) (reject))
|
|
(make-pobj tag1 (map2 m a b)))
|
|
((($ ppred tag1) $ ppred tag2)
|
|
(unless (eq? tag1 tag2) (reject))
|
|
p2)
|
|
((($ ppred tag1) $ pobj tag2 _)
|
|
(unless (eq? tag1 tag2) (reject))
|
|
(set! p2covers #f)
|
|
p2)
|
|
((($ ppred tag1) $ pconst c tag2)
|
|
(unless (eq? tag1 tag2) (reject))
|
|
(set! p2covers #f)
|
|
p2)
|
|
(_ (reject))))))
|
|
(cond (p1covers (cons 'redundant p2))
|
|
(p2covers (cons 'stop p3))
|
|
(else (cons 'continue p3))))))))
|
|
(define improve-by-noisily
|
|
(lambda (p2 p1)
|
|
(let ((r (improve-by-pattern p2 p1)))
|
|
(printf
|
|
"~a by ~a returns ~a ~a~%"
|
|
(ppat p2)
|
|
(ppat p1)
|
|
(car r)
|
|
(ppat (cdr r))))))
|
|
(define make-components
|
|
(lambda (d)
|
|
(let* ((structs
|
|
(filter-map
|
|
(match-lambda ((? define?) #f) (x x))
|
|
d))
|
|
(defs (filter-map
|
|
(match-lambda ((? define? x) x) (_ #f))
|
|
d))
|
|
(name-of (match-lambda (($ define x _) x)))
|
|
(ref-of
|
|
(match-lambda
|
|
(($ define _ e) (references e name-gdef))))
|
|
(comp (top-sort defs name-of ref-of)))
|
|
(when #f
|
|
(printf "Components:~%")
|
|
(pretty-print
|
|
(map (lambda (c)
|
|
(map (match-lambda
|
|
(($ define x _) (and x (name-name x))))
|
|
c))
|
|
comp)))
|
|
(append structs comp))))
|
|
(define make-body-components
|
|
(lambda (d)
|
|
(let* ((structs
|
|
(filter-map
|
|
(match-lambda ((? define?) #f) (x x))
|
|
d))
|
|
(defs (filter-map
|
|
(match-lambda ((? define? x) x) (_ #f))
|
|
d))
|
|
(name-of (match-lambda (($ define x _) x)))
|
|
(bound (map name-of defs))
|
|
(ref-of
|
|
(match-lambda
|
|
(($ define _ e)
|
|
(references e (lambda (x) (memq x bound))))))
|
|
(comp (top-sort defs name-of ref-of)))
|
|
(when #f
|
|
(printf "Components:~%")
|
|
(pretty-print
|
|
(map (lambda (c)
|
|
(map (match-lambda
|
|
(($ define x _) (and x (name-name x))))
|
|
c))
|
|
comp)))
|
|
(append structs comp))))
|
|
(define make-letrec-components
|
|
(lambda (bindings)
|
|
(let* ((name-of bind-name)
|
|
(bound (map name-of bindings))
|
|
(ref-of
|
|
(match-lambda
|
|
(($ bind _ e)
|
|
(references e (lambda (x) (memq x bound))))))
|
|
(comp (top-sort bindings name-of ref-of)))
|
|
(when #f
|
|
(printf "Letrec Components:~%")
|
|
(pretty-print
|
|
(map (lambda (c)
|
|
(map (match-lambda (($ bind x _) (pname x))) c))
|
|
comp)))
|
|
comp)))
|
|
(define references
|
|
(lambda (e ref?)
|
|
(recur loop
|
|
((e e))
|
|
(match e
|
|
(($ define x e)
|
|
(if (and x (name-mutated x))
|
|
(union (set x) (loop e))
|
|
(loop e)))
|
|
((? defstruct?) empty-set)
|
|
((? datatype?) empty-set)
|
|
((? const?) empty-set)
|
|
(($ var x) (if (ref? x) (set x) empty-set))
|
|
(($ lam _ e1) (loop e1))
|
|
(($ vlam _ _ e1) (loop e1))
|
|
(($ app e0 args)
|
|
(foldr union2 (loop e0) (map loop args)))
|
|
(($ let b e2)
|
|
(let ((do-bind (match-lambda (($ bind _ e) (loop e)))))
|
|
(foldr union2 (loop e2) (map do-bind b))))
|
|
(($ let* b e2)
|
|
(let ((do-bind (match-lambda (($ bind _ e) (loop e)))))
|
|
(foldr union2 (loop e2) (map do-bind b))))
|
|
(($ letr b e2)
|
|
(let ((do-bind (match-lambda (($ bind _ e) (loop e)))))
|
|
(foldr union2 (loop e2) (map do-bind b))))
|
|
(($ body defs exps)
|
|
(foldr union2
|
|
empty-set
|
|
(map loop (append defs exps))))
|
|
(($ record b)
|
|
(let ((do-bind (match-lambda (($ bind _ e) (loop e)))))
|
|
(foldr union2 empty-set (map do-bind b))))
|
|
(($ field _ e) (loop e))
|
|
(($ cast _ e) (loop e))
|
|
(($ and exps)
|
|
(foldr union2 empty-set (map loop exps)))
|
|
(($ or exps)
|
|
(foldr union2 empty-set (map loop exps)))
|
|
(($ begin exps)
|
|
(foldr union2 empty-set (map loop exps)))
|
|
(($ if test then els)
|
|
(union (loop test) (loop then) (loop els)))
|
|
(($ delay e) (loop e))
|
|
(($ set! x body)
|
|
(union (if (ref? x) (set x) empty-set)
|
|
(loop body)))
|
|
(($ match exp clauses)
|
|
(foldr union2
|
|
(loop exp)
|
|
(map (match-lambda (($ mclause _ exp _) (loop exp)))
|
|
clauses)))))))
|
|
(define top-sort
|
|
(lambda (graph name-of references-of)
|
|
(let* ((adj assq)
|
|
(g (map (lambda (x)
|
|
(list (name-of x)
|
|
(box (references-of x))
|
|
(box #f)
|
|
x))
|
|
graph))
|
|
(gt (let ((gt (map (match-lambda
|
|
((n _ _ name)
|
|
(list n (box empty-set) (box #f) n)))
|
|
g)))
|
|
(for-each
|
|
(match-lambda
|
|
((n nay _ _)
|
|
(for-each
|
|
(lambda (v)
|
|
(match (adj v gt)
|
|
(#f #f)
|
|
((_ b _ _) (set-box! b (cons n (unbox b))))))
|
|
(unbox nay))))
|
|
g)
|
|
gt))
|
|
(visit (lambda (vg)
|
|
(letrec ((visit (lambda (g l)
|
|
(match g
|
|
(#f l)
|
|
((n nay mark name)
|
|
(if (unbox mark)
|
|
l
|
|
(begin
|
|
(set-box! mark #t)
|
|
(cons name
|
|
(foldr (lambda (v l)
|
|
(visit (adj v
|
|
vg)
|
|
l))
|
|
l
|
|
(unbox nay))))))))))
|
|
visit)))
|
|
(visit-gt (visit gt))
|
|
(visit-g (visit g))
|
|
(post (foldr visit-gt '() gt))
|
|
(pre (foldl (lambda (gg l)
|
|
(match (visit-g (adj gg g) '())
|
|
(() l)
|
|
(c (cons c l))))
|
|
'()
|
|
post)))
|
|
(reverse pre))))
|
|
(define genlet #t)
|
|
(define genmatch #t)
|
|
(define letonce #f)
|
|
(define type-defs
|
|
(lambda (d)
|
|
(for-each
|
|
(match-lambda
|
|
((? defstruct? b) (type-structure b))
|
|
((? datatype? b) (type-structure b))
|
|
(c (type-component c #t)))
|
|
(make-components d))
|
|
(close '())))
|
|
(define type-structure
|
|
(match-lambda
|
|
(($ defstruct
|
|
x
|
|
_
|
|
make
|
|
pred
|
|
get
|
|
set
|
|
getn
|
|
setn
|
|
mutable)
|
|
(let* ((vars (map (lambda (_) (gensym)) get))
|
|
(make-get-type
|
|
(lambda (getter v)
|
|
(match getter
|
|
(($ some b)
|
|
(set-name-ty!
|
|
b
|
|
(closeall
|
|
(r+ initial-type-env `((,x ,@vars) -> ,v)))))
|
|
(_ #f))))
|
|
(make-set-type
|
|
(lambda (setter v)
|
|
(match setter
|
|
(($ some b)
|
|
(set-name-ty!
|
|
b
|
|
(closeall
|
|
(r+ initial-type-env `((,x ,@vars) ,v -> void)))))
|
|
(_ #f)))))
|
|
(set-name-ty!
|
|
make
|
|
(closeall
|
|
(r+ initial-type-env `(,@vars -> (,x ,@vars)))))
|
|
(set-name-ty!
|
|
pred
|
|
(closeall
|
|
(r+ initial-type-env
|
|
`((+ (,x ,@vars) y) -> bool))))
|
|
(for-each2 make-get-type get vars)
|
|
(for-each2 make-set-type set vars)
|
|
(for-each2 make-get-type getn vars)
|
|
(for-each2 make-set-type setn vars)))
|
|
(($ datatype dt)
|
|
(for-each
|
|
(match-lambda
|
|
((type . variants)
|
|
(for-each
|
|
(match-lambda
|
|
(($ variant con pred arg-types)
|
|
(set-name-ty!
|
|
con
|
|
(closeall
|
|
(r+ initial-type-env
|
|
`(,@(cdr arg-types) -> ,type))))
|
|
(set-name-ty!
|
|
pred
|
|
(closeall
|
|
(r+ initial-type-env
|
|
`((+ ,(name-predicate pred) x) -> bool))))))
|
|
variants)))
|
|
dt))))
|
|
(define type-component
|
|
(lambda (component top)
|
|
(when verbose
|
|
(let ((cnames
|
|
(filter-map
|
|
(match-lambda (($ define b _) (name-name b)))
|
|
component)))
|
|
(unless
|
|
(null? cnames)
|
|
(printf "Typing ~a~%" cnames))))
|
|
(let* ((f (match-lambda (($ define b e) (make-bind b e))))
|
|
(bindings (map f component))
|
|
(names (map (match-lambda (($ define b _) (pname b)))
|
|
component))
|
|
(f1 (match-lambda
|
|
(($ define b _) (set-name-ty! b (tvar)))))
|
|
(f2 (match-lambda
|
|
((and d ($ define b e))
|
|
(set-define-exp! d (w e names)))))
|
|
(f3 (match-lambda
|
|
(($ define b e) (unify (name-ty b) (typeof e)))))
|
|
(f4 (match-lambda (($ define b _) (name-ty b))))
|
|
(f5 (lambda (d ts)
|
|
(match d (($ define b _) (set-name-ty! b ts))))))
|
|
(push-level)
|
|
(for-each f1 component)
|
|
(for-each f2 component)
|
|
(for-each f3 component)
|
|
(for-each limit-expansive component)
|
|
(for-each
|
|
f5
|
|
component
|
|
(close (map f4 component)))
|
|
(pop-level))))
|
|
(define w
|
|
(lambda (e component)
|
|
(match e
|
|
(($ const _ pred)
|
|
(make-type
|
|
(r+ initial-type-env (name-predicate pred))
|
|
e))
|
|
(($ var x)
|
|
(unless
|
|
(name-ty x)
|
|
(set-name-ty!
|
|
x
|
|
(if (name-mutated x)
|
|
(monotvar)
|
|
(let* ((_1 (push-level))
|
|
(t (closeall (tvar)))
|
|
(_2 (pop-level)))
|
|
t))))
|
|
(if (ts? (name-ty x))
|
|
(match-let*
|
|
((tynode (make-type #f #f))
|
|
((t absv) (instantiate (name-ty x) tynode)))
|
|
(set-type-ty! tynode t)
|
|
(set-type-exp!
|
|
tynode
|
|
(match (name-primitive x)
|
|
('imprecise
|
|
(make-check (list absv #f #f #f component) e))
|
|
('check
|
|
(make-check
|
|
(list (cons top absv) #f #f #f component)
|
|
e))
|
|
('nocheck e)
|
|
(#t
|
|
(make-check
|
|
(list absv (mk-definite-prim t) #f #f component)
|
|
e))
|
|
(#f
|
|
(make-check (list absv #f #f #t component) e))))
|
|
tynode)
|
|
e))
|
|
(($ lam x e1)
|
|
(for-each (lambda (b) (set-name-ty! b (tvar))) x)
|
|
(match-let*
|
|
((body (w e1 component))
|
|
((t absv)
|
|
(r+collect
|
|
initial-type-env
|
|
`(,@(map name-ty x) -> ,(typeof body)))))
|
|
(make-type
|
|
t
|
|
(make-check
|
|
(list absv (mk-definite-lam t) #f #f component)
|
|
(make-lam x body)))))
|
|
(($ vlam x rest e1)
|
|
(for-each (lambda (b) (set-name-ty! b (tvar))) x)
|
|
(match-let*
|
|
((z (tvar))
|
|
(_ (set-name-ty!
|
|
rest
|
|
(r+ initial-type-env `(list ,z))))
|
|
(body (w e1 component))
|
|
((t absv)
|
|
(r+collect
|
|
initial-type-env
|
|
`(,@(map name-ty x) (&list ,z) -> ,(typeof body)))))
|
|
(make-type
|
|
t
|
|
(make-check
|
|
(list absv (mk-definite-lam t) #f #f component)
|
|
(make-vlam x rest body)))))
|
|
(($ app e0 args)
|
|
(match-let*
|
|
((t0 (w e0 component))
|
|
(targs (maplr (lambda (e) (w e component)) args))
|
|
(a* (map (lambda (_) (tvar)) args))
|
|
(b (tvar))
|
|
((t absv)
|
|
(r-collect initial-type-env `(,@a* -> ,b)))
|
|
(definf (mk-definite-app t)))
|
|
(unify (typeof t0) t)
|
|
(for-each2 unify (map typeof targs) a*)
|
|
(if (syntactically-a-procedure? t0)
|
|
(make-type b (make-app t0 targs))
|
|
(make-type
|
|
b
|
|
(make-check
|
|
(list absv definf #f #f component)
|
|
(make-app t0 targs))))))
|
|
(($ let b e2)
|
|
(let* ((do-bind
|
|
(match-lambda
|
|
(($ bind b e)
|
|
(if genlet
|
|
(let* ((_ (push-level))
|
|
(e (w e (list (pname b))))
|
|
(bind (make-bind b e)))
|
|
(limit-expansive bind)
|
|
(set-name-ty! b (car (close (list (typeof e)))))
|
|
(pop-level)
|
|
bind)
|
|
(let ((e (w e component)))
|
|
(set-name-ty! b (typeof e))
|
|
(make-bind b e))))))
|
|
(tb (map do-bind b))
|
|
(body (w e2 component)))
|
|
(make-let tb body)))
|
|
(($ let* b e2)
|
|
(let* ((do-bind
|
|
(match-lambda
|
|
(($ bind b e)
|
|
(if genlet
|
|
(let* ((_ (push-level))
|
|
(e (w e (list (pname b))))
|
|
(bind (make-bind b e)))
|
|
(limit-expansive bind)
|
|
(set-name-ty! b (car (close (list (typeof e)))))
|
|
(pop-level)
|
|
bind)
|
|
(let ((e (w e component)))
|
|
(set-name-ty! b (typeof e))
|
|
(make-bind b e))))))
|
|
(tb (maplr do-bind b))
|
|
(body (w e2 component)))
|
|
(make-let* tb body)))
|
|
(($ letr b e2)
|
|
(let* ((do-comp
|
|
(lambda (b)
|
|
(if genlet
|
|
(let* ((f1 (match-lambda
|
|
(($ bind b _) (set-name-ty! b (tvar)))))
|
|
(names (map (match-lambda
|
|
(($ bind b _) (pname b)))
|
|
b))
|
|
(f2 (match-lambda
|
|
(($ bind b e)
|
|
(make-bind b (w e names)))))
|
|
(f3 (match-lambda
|
|
(($ bind b e)
|
|
(unify (name-ty b) (typeof e))
|
|
(name-ty b))))
|
|
(f4 (lambda (bind ts)
|
|
(match bind
|
|
(($ bind b _)
|
|
(set-name-ty! b ts)))))
|
|
(_1 (push-level))
|
|
(_2 (for-each f1 b))
|
|
(tb (maplr f2 b))
|
|
(_3 (for-each limit-expansive tb))
|
|
(ts-list (close (maplr f3 tb))))
|
|
(pop-level)
|
|
(for-each2 f4 tb ts-list)
|
|
tb)
|
|
(let* ((f1 (match-lambda
|
|
(($ bind b _) (set-name-ty! b (tvar)))))
|
|
(f2 (match-lambda
|
|
(($ bind b e)
|
|
(make-bind b (w e component)))))
|
|
(f3 (match-lambda
|
|
(($ bind b e)
|
|
(unify (name-ty b) (typeof e)))))
|
|
(_1 (for-each f1 b))
|
|
(tb (maplr f2 b)))
|
|
(for-each f3 tb)
|
|
tb))))
|
|
(comps (make-letrec-components b))
|
|
(tb (foldr append '() (maplr do-comp comps))))
|
|
(make-letr tb (w e2 component))))
|
|
(($ body defs exps)
|
|
(for-each
|
|
(match-lambda
|
|
((? defstruct? b) (type-structure b))
|
|
((? datatype? b) (type-structure b))
|
|
(c (type-component c #f)))
|
|
(make-body-components defs))
|
|
(let ((texps (maplr (lambda (x) (w x component)) exps)))
|
|
(make-body defs texps)))
|
|
(($ and exps)
|
|
(let* ((texps (maplr (lambda (x) (w x component)) exps))
|
|
(t (match texps
|
|
(() (r+ initial-type-env 'true))
|
|
((e) (typeof e))
|
|
(_ (let ((a (r+ initial-type-env 'false)))
|
|
(unify (typeof (rac texps)) a)
|
|
a)))))
|
|
(make-type t (make-and texps))))
|
|
(($ or exps)
|
|
(let* ((texps (maplr (lambda (x) (w x component)) exps))
|
|
(t (match texps
|
|
(() (r+ initial-type-env 'false))
|
|
((e) (typeof e))
|
|
(_ (let* ((t-last (typeof (rac texps)))
|
|
(but-last (rdc texps))
|
|
(a (tvar)))
|
|
(for-each
|
|
(lambda (e)
|
|
(unify (typeof e)
|
|
(r+ initial-type-env
|
|
`(+ (not false) ,a))))
|
|
but-last)
|
|
(unify t-last
|
|
(r+ initial-type-env
|
|
`(+ (not false) ,a)))
|
|
t-last)))))
|
|
(make-type t (make-or texps))))
|
|
(($ begin exps)
|
|
(let ((texps (maplr (lambda (x) (w x component)) exps)))
|
|
(make-begin texps)))
|
|
(($ if test then els)
|
|
(let ((ttest (w test component))
|
|
(tthen (w then component))
|
|
(tels (w els component))
|
|
(a (tvar)))
|
|
(unify (typeof tthen) a)
|
|
(unify (typeof tels) a)
|
|
(make-type a (make-if ttest tthen tels))))
|
|
(($ delay e2)
|
|
(let ((texp (w e2 component)))
|
|
(make-type
|
|
(r+ initial-type-env `(promise ,(typeof texp)))
|
|
(make-delay texp))))
|
|
(($ set! x body)
|
|
(unless (name-ty x) (set-name-ty! x (monotvar)))
|
|
(let* ((body (w body component))
|
|
(t (if (ts? (name-ty x))
|
|
(car (instantiate (name-ty x) #f))
|
|
(name-ty x))))
|
|
(unify t (typeof body))
|
|
(make-type
|
|
(r+ initial-type-env 'void)
|
|
(make-set! x body))))
|
|
(($ record bind)
|
|
(let* ((tbind (map (match-lambda
|
|
(($ bind name exp)
|
|
(make-bind name (w exp component))))
|
|
bind))
|
|
(t (r+ initial-type-env
|
|
`(record
|
|
,@(map (match-lambda
|
|
(($ bind name exp)
|
|
(list name (typeof exp))))
|
|
tbind)))))
|
|
(make-type t (make-record tbind))))
|
|
(($ field name exp)
|
|
(match-let*
|
|
((texp (w exp component))
|
|
(a (tvar))
|
|
((t absv)
|
|
(r-collect initial-type-env `(record (,name ,a)))))
|
|
(unify (typeof texp) t)
|
|
(make-type
|
|
a
|
|
(make-check
|
|
(list absv #f #f #f component)
|
|
(make-field name texp)))))
|
|
(($ cast (ty t absv) exp)
|
|
(let ((texp (w exp component)) (a (tvar)))
|
|
(unify (r+ initial-type-env `(,(typeof texp) -> ,a))
|
|
t)
|
|
(make-type
|
|
a
|
|
(make-check
|
|
(list absv #f #f #f component)
|
|
(make-cast (list ty t absv) texp)))))
|
|
(($ match exp clauses)
|
|
(for-each
|
|
(match-lambda
|
|
(($ mclause p _ (? name? fail))
|
|
(set-name-ty!
|
|
fail
|
|
(r+ initial-type-env '(a ?-> b))))
|
|
(_ #f))
|
|
clauses)
|
|
(match-let*
|
|
((iclauses
|
|
(improve-clauses
|
|
(append
|
|
clauses
|
|
(list (make-mclause (make-pelse) #f #f)))))
|
|
((tmatch absv precise)
|
|
(w-match (rdc iclauses) (rac iclauses)))
|
|
(texp (w exp component))
|
|
(_ (unify (typeof texp) tmatch))
|
|
(tclauses
|
|
(maplr (match-lambda
|
|
(($ mclause p e fail)
|
|
(make-mclause p (w e component) fail)))
|
|
clauses))
|
|
(a (tvar)))
|
|
(for-each
|
|
(match-lambda
|
|
(($ mclause _ e _) (unify (typeof e) a)))
|
|
tclauses)
|
|
(make-type
|
|
a
|
|
(make-check
|
|
(list absv #f (not precise) #f component)
|
|
(make-match texp tclauses))))))))
|
|
(define w-match
|
|
(lambda (clauses last)
|
|
(letrec ((bindings '())
|
|
(encode
|
|
(match-lambda
|
|
(($ pand pats) (encode* pats))
|
|
(x (encode* (list x)))))
|
|
(encode*
|
|
(lambda (pats)
|
|
(let* ((concrete?
|
|
(lambda (p)
|
|
(or (pconst? p) (pobj? p) (ppred? p) (pelse? p))))
|
|
(var? (lambda (p) (or (pvar? p) (pany? p))))
|
|
(not-var?
|
|
(lambda (p)
|
|
(and (not (pvar? p)) (not (pany? p)))))
|
|
(t (match (filter concrete? pats)
|
|
((p)
|
|
(r+ initial-type-env
|
|
(match (template p)
|
|
((x) x)
|
|
(x `(+ ,@x)))))
|
|
(()
|
|
(r+ initial-type-env
|
|
`(+ ,@(apply append
|
|
(map template
|
|
(filter
|
|
not-var?
|
|
pats)))
|
|
,@(if (null? (filter var? pats))
|
|
'()
|
|
(list (out1tvar)))))))))
|
|
(for-each
|
|
(match-lambda
|
|
(($ pvar b)
|
|
(set! bindings (cons b bindings))
|
|
(set-name-ty! b (pat-var-bind t))))
|
|
(filter pvar? pats))
|
|
t)))
|
|
(template
|
|
(match-lambda
|
|
((? pelse?) '())
|
|
(($ pconst _ pred) (list (name-predicate pred)))
|
|
((and pat ($ pobj c args))
|
|
(list (cond ((or (eq? %vector? c) (eq? %cvector? c))
|
|
(cons (if (eq? %vector? c) 'vec 'cvec)
|
|
(match (maplr encode args)
|
|
(() (list (out1tvar)))
|
|
((first . rest)
|
|
(list (foldr (lambda (x y)
|
|
(unify x y)
|
|
y)
|
|
first
|
|
rest))))))
|
|
(else
|
|
(cons (car (name-predicate c))
|
|
(maplr encode args))))))
|
|
(($ ppred pred)
|
|
(cond ((eq? pred %boolean?) (list 'true 'false))
|
|
((eq? pred %list?) (list `(list ,(out1tvar))))
|
|
(else
|
|
(list (cons (car (name-predicate pred))
|
|
(maplr (lambda (_) (out1tvar))
|
|
(cdr (name-predicate pred))))))))
|
|
(($ pnot (? pconst?)) '())
|
|
(($ pnot ($ ppred pred))
|
|
(cond ((eq? pred %boolean?) '((not true) (not false)))
|
|
((eq? pred %procedure?) '((not ?->)))
|
|
((eq? pred %list?) '())
|
|
(else `((not ,(car (name-predicate pred)))))))
|
|
(($ pnot ($ pobj pred pats))
|
|
(let ((m (foldr + 0 (map non-triv pats))))
|
|
(case m
|
|
((0) `((not ,(car (name-predicate pred)))))
|
|
((1)
|
|
`((,(car (name-predicate pred))
|
|
,@(map (match-lambda
|
|
(($ pobj pred _)
|
|
`(+ (not ,(car (name-predicate pred)))
|
|
,(out1tvar)))
|
|
(($ ppred pred)
|
|
`(+ (not ,(car (name-predicate pred)))
|
|
,(out1tvar)))
|
|
(_ (out1tvar)))
|
|
pats))))
|
|
(else '()))))))
|
|
(non-triv
|
|
(match-lambda
|
|
((? pvar?) 0)
|
|
((? pany?) 0)
|
|
((? pelse?) 0)
|
|
((? pconst?) 2)
|
|
(($ pobj _ pats) (foldr + 1 (map non-triv pats)))
|
|
(_ 1)))
|
|
(precise
|
|
(match-lambda
|
|
((? pconst?) #f)
|
|
(($ pand pats) (andmap precise pats))
|
|
(($ pnot pat) (precise pat))
|
|
(($ pobj pred pats)
|
|
(let ((m (foldr + 0 (map non-triv pats))))
|
|
(case m
|
|
((0) #t)
|
|
((1) (andmap precise pats))
|
|
(else #f))))
|
|
(($ ppred pred) (not (eq? pred %list?)))
|
|
(_ #t))))
|
|
(push-level)
|
|
(match-let*
|
|
((precise-match
|
|
(and (andmap
|
|
(match-lambda (($ mclause _ _ fail) (not fail)))
|
|
clauses)
|
|
(match last (($ mclause p _ _) (precise p)))))
|
|
(types (maplr (match-lambda (($ mclause p _ _) (encode p)))
|
|
clauses))
|
|
((t absv)
|
|
(r-match
|
|
(foldr (lambda (x y) (unify x y) y) (tvar) types))))
|
|
(unify (out1tvar) t)
|
|
(for-each limit-name bindings)
|
|
(for-each2
|
|
set-name-ty!
|
|
bindings
|
|
(close (map name-ty bindings)))
|
|
(pop-level)
|
|
'(pretty-print
|
|
`(match-input
|
|
,@(map (match-lambda (($ mclause p _ _) (ppat p)))
|
|
clauses)))
|
|
'(pretty-print
|
|
`(match-type
|
|
,(ptype t)
|
|
,@(map (lambda (b) (list (pname b) (ptype (name-ty b))))
|
|
bindings)))
|
|
(list t absv precise-match)))))
|
|
(define syntactically-a-procedure?
|
|
(match-lambda
|
|
(($ type _ e) (syntactically-a-procedure? e))
|
|
(($ check _ e) (syntactically-a-procedure? e))
|
|
(($ var x) (name-primitive x))
|
|
((? lam?) #t)
|
|
((? vlam?) #t)
|
|
(($ let _ body)
|
|
(syntactically-a-procedure? body))
|
|
(($ let* _ body)
|
|
(syntactically-a-procedure? body))
|
|
(($ letr _ body)
|
|
(syntactically-a-procedure? body))
|
|
(($ if _ e2 e3)
|
|
(and (syntactically-a-procedure? e2)
|
|
(syntactically-a-procedure? e3)))
|
|
(($ begin exps)
|
|
(syntactically-a-procedure? (rac exps)))
|
|
(($ body _ exps)
|
|
(syntactically-a-procedure? (rac exps)))
|
|
(_ #f)))
|
|
(define typeof
|
|
(match-lambda
|
|
(($ type t _) t)
|
|
(($ check _ e) (typeof e))
|
|
(($ let _ body) (typeof body))
|
|
(($ let* _ body) (typeof body))
|
|
(($ letr _ body) (typeof body))
|
|
(($ body _ exps) (typeof (rac exps)))
|
|
(($ begin exps) (typeof (rac exps)))
|
|
(($ var x) (name-ty x))))
|
|
(define limit-name
|
|
(lambda (n)
|
|
(when (name-mutated n)
|
|
(unify (name-ty n) (out1tvar)))))
|
|
(define limit-expansive
|
|
(letrec ((limit! (lambda (t) (unify t (out1tvar))))
|
|
(expansive-pattern?
|
|
(match-lambda
|
|
((? pconst?) #f)
|
|
(($ pvar x) (name-mutated x))
|
|
(($ pobj _ pats) (ormap expansive-pattern? pats))
|
|
((? pany?) #f)
|
|
((? pelse?) #f)
|
|
(($ pand pats) (ormap expansive-pattern? pats))
|
|
(($ ppred x) (name-mutated x))
|
|
(($ pnot pat) (expansive-pattern? pat))))
|
|
(limit-expr
|
|
(match-lambda
|
|
(($ bind b e)
|
|
(if (name-mutated b)
|
|
(limit! (typeof e))
|
|
(limit-expr e)))
|
|
((? defstruct?) #f)
|
|
((? datatype?) #f)
|
|
(($ define x e)
|
|
(if (and x (name-mutated x))
|
|
(limit! (typeof e))
|
|
(limit-expr e)))
|
|
(($ type
|
|
t
|
|
($ app ($ type _ ($ check _ ($ var x))) exps))
|
|
(cond ((list? (name-pure x))
|
|
(if (= (length (name-pure x)) (length exps))
|
|
(for-each2
|
|
(lambda (pure e)
|
|
(if pure (limit-expr e) (limit! (typeof e))))
|
|
(name-pure x)
|
|
exps)
|
|
(limit! t)))
|
|
((or (eq? #t (name-pure x))
|
|
(and (eq? 'cons (name-pure x))
|
|
(not cons-is-mutable)))
|
|
(for-each limit-expr exps))
|
|
(else (limit! t))))
|
|
(($ type t ($ app _ _)) (limit! t))
|
|
(($ type t ($ check _ ($ app _ _))) (limit! t))
|
|
(($ delay _) #f)
|
|
(($ type t ($ set! _ _)) (limit! t))
|
|
(($ var _) #f)
|
|
((? const?) #f)
|
|
(($ lam _ _) #f)
|
|
(($ vlam _ _ _) #f)
|
|
(($ let bind body)
|
|
(limit-expr body)
|
|
(for-each limit-expr bind))
|
|
(($ let* bind body)
|
|
(limit-expr body)
|
|
(for-each limit-expr bind))
|
|
(($ letr bind body)
|
|
(limit-expr body)
|
|
(for-each limit-expr bind))
|
|
(($ body defs exps)
|
|
(for-each limit-expr defs)
|
|
(for-each limit-expr exps))
|
|
(($ and exps) (for-each limit-expr exps))
|
|
(($ or exps) (for-each limit-expr exps))
|
|
(($ begin exps) (for-each limit-expr exps))
|
|
(($ if e1 e2 e3)
|
|
(limit-expr e1)
|
|
(limit-expr e2)
|
|
(limit-expr e3))
|
|
(($ record bind)
|
|
(for-each
|
|
(match-lambda (($ bind _ e) (limit-expr e)))
|
|
bind))
|
|
(($ field _ exp) (limit-expr exp))
|
|
(($ cast _ exp) (limit-expr exp))
|
|
(($ match exp clauses)
|
|
(limit-expr exp)
|
|
(for-each
|
|
(match-lambda
|
|
(($ mclause pat body fail)
|
|
(if (or (and fail (name-mutated fail))
|
|
(expansive-pattern? pat))
|
|
(limit! (typeof body))
|
|
(limit-expr body))))
|
|
clauses))
|
|
(($ type _ e1) (limit-expr e1))
|
|
(($ check _ e1) (limit-expr e1)))))
|
|
limit-expr))
|
|
(define unparse
|
|
(lambda (e check-action)
|
|
(letrec ((pbind (match-lambda
|
|
(($ bind n e) (list (pname n) (pexpr e)))))
|
|
(pexpr (match-lambda
|
|
((and x ($ type _ (? check?)))
|
|
(check-action x pexpr))
|
|
(($ type _ exp) (pexpr exp))
|
|
(($ shape t exp) (pexpr exp))
|
|
(($ define x e)
|
|
(if (or (not x) (and (name? x) (not (name-name x))))
|
|
(pexpr e)
|
|
`(define ,(pname x) ,(pexpr e))))
|
|
(($ defstruct _ args _ _ _ _ _ _ _)
|
|
`(check-define-const-structure ,args))
|
|
(($ datatype d)
|
|
`(datatype
|
|
,@(map (match-lambda
|
|
(((tag . args) . bindings)
|
|
(cons (cons (ptag tag) args)
|
|
(map (match-lambda
|
|
(($ variant _ _ types) types))
|
|
bindings))))
|
|
d)))
|
|
(($ and exps) `(and ,@(maplr pexpr exps)))
|
|
(($ or exps) `(or ,@(maplr pexpr exps)))
|
|
(($ begin exps) `(begin ,@(maplr pexpr exps)))
|
|
(($ var x) (pname x))
|
|
(($ prim x) (pname x))
|
|
(($ const x _) (pconst x))
|
|
(($ lam x e1)
|
|
`(lambda ,(maplr pname x) ,@(pexpr e1)))
|
|
(($ vlam x rest e1)
|
|
`(lambda ,(append (maplr pname x) (pname rest))
|
|
,@(pexpr e1)))
|
|
(($ match e1 clauses)
|
|
(let* ((pclause
|
|
(match-lambda
|
|
(($ mclause p #f #f)
|
|
`(,(ppat p) <last clause>))
|
|
(($ mclause p exp fail)
|
|
(if fail
|
|
`(,(ppat p)
|
|
(=> ,(pname fail))
|
|
,@(pexpr exp))
|
|
`(,(ppat p) ,@(pexpr exp))))))
|
|
(p1 (pexpr e1)))
|
|
`(match ,p1 ,@(maplr pclause clauses))))
|
|
(($ app e1 args)
|
|
(let* ((p1 (pexpr e1))
|
|
(pargs (maplr pexpr args))
|
|
(unkwote
|
|
(match-lambda
|
|
(('quote x) x)
|
|
((? boolean? x) x)
|
|
((? number? x) x)
|
|
((? char? x) x)
|
|
((? string? x) x)
|
|
((? null? x) x)
|
|
((? box? x) x)
|
|
((? vector? x) x))))
|
|
(cond ((eq? p1 qlist) `',(maplr unkwote pargs))
|
|
((eq? p1 qcons)
|
|
(let ((unq (maplr unkwote pargs)))
|
|
`',(cons (car unq) (cadr unq))))
|
|
((eq? p1 qbox) (box (unkwote (car pargs))))
|
|
((eq? p1 qvector)
|
|
(list->vector (maplr unkwote pargs)))
|
|
(else (cons p1 pargs)))))
|
|
(($ let b e2)
|
|
(let ((pb (maplr pbind b)))
|
|
`(let ,pb ,@(pexpr e2))))
|
|
(($ let* b e2)
|
|
(let ((pb (maplr pbind b)))
|
|
`(let* ,pb ,@(pexpr e2))))
|
|
(($ letr b e2)
|
|
(let ((pb (maplr pbind b)))
|
|
`(letrec ,pb ,@(pexpr e2))))
|
|
(($ body defs exps)
|
|
(let ((pdefs (maplr pexpr defs)))
|
|
(append pdefs (maplr pexpr exps))))
|
|
(($ if e1 e2 e3)
|
|
(let* ((p1 (pexpr e1)) (p2 (pexpr e2)) (p3 (pexpr e3)))
|
|
`(if ,p1 ,p2 ,p3)))
|
|
(($ record bindings)
|
|
`(record ,@(maplr pbind bindings)))
|
|
(($ field x e2) `(field ,x ,(pexpr e2)))
|
|
(($ cast (ty . _) e2) `(: ,ty ,(pexpr e2)))
|
|
(($ delay e) `(delay ,(pexpr e)))
|
|
(($ set! x e) `(set! ,(pname x) ,(pexpr e))))))
|
|
(pexpr e))))
|
|
(define pexpr
|
|
(lambda (ex)
|
|
(unparse
|
|
ex
|
|
(lambda (e pexpr)
|
|
(match e
|
|
(($ type _ ($ check _ exp)) (pexpr exp)))))))
|
|
(define pdef pexpr)
|
|
(define ppat
|
|
(match-lambda
|
|
(($ pconst x _) (pconst x))
|
|
(($ pvar x) (pname x))
|
|
(($ pany) '_)
|
|
(($ pelse) 'else)
|
|
(($ pnot pat) `(not ,(ppat pat)))
|
|
(($ pand pats) `(and ,@(maplr ppat pats)))
|
|
(($ ppred pred)
|
|
(match (pname pred)
|
|
('false-object? #f)
|
|
('true-object? #t)
|
|
('null? '())
|
|
(x `(? ,x))))
|
|
(($ pobj tag args)
|
|
(match (cons (pname tag) args)
|
|
(('box? x) (box (ppat x)))
|
|
(('pair? x y) (cons (ppat x) (ppat y)))
|
|
(('vector? . x) (list->vector (maplr ppat x)))
|
|
((tg . _) `($ ,(strip-? tg) ,@(maplr ppat args)))))))
|
|
(define strip-?
|
|
(lambda (s)
|
|
(let* ((str (symbol->string s))
|
|
(n (string-length str)))
|
|
(if (or (zero? n)
|
|
(not (char=? #\? (string-ref str (- n 1)))))
|
|
s
|
|
(string->symbol (substring str 0 (- n 1)))))))
|
|
(define pname
|
|
(match-lambda
|
|
((? name? x) (or (name-name x) '<expr>))
|
|
((? symbol? x) x)))
|
|
(define ptag
|
|
(match-lambda
|
|
((? k? k) (k-name k))
|
|
((? symbol? x) x)))
|
|
(define pconst
|
|
(match-lambda
|
|
((? symbol? x) `',x)
|
|
((? boolean? x) x)
|
|
((? number? x) x)
|
|
((? char? x) x)
|
|
((? string? x) x)
|
|
((? null? x) `',x)))
|
|
(define check
|
|
(lambda (file)
|
|
(output-checked file '() type-check?)))
|
|
(define profcheck
|
|
(lambda (file)
|
|
(output-checked #f '() type-check?)
|
|
(output-checked
|
|
#f
|
|
(make-counters total-possible)
|
|
type-check?)))
|
|
(define fullcheck
|
|
(lambda (file)
|
|
(let ((check? (lambda (_) #t)))
|
|
(output-checked #f '() check?)
|
|
(output-checked
|
|
#f
|
|
(make-counters total-possible)
|
|
check?))))
|
|
(define make-counters
|
|
(lambda (n)
|
|
(let* ((init `(define check-counters (make-vector ,n 0)))
|
|
(sum '(define check-total
|
|
(lambda ()
|
|
(let ((foldr (lambda (f i l)
|
|
(recur loop
|
|
((l l))
|
|
(match l
|
|
(() i)
|
|
((x . y) (f x (loop y))))))))
|
|
(foldr + 0 (vector->list check-counters))))))
|
|
(incr '(extend-syntax
|
|
(check-increment-counter)
|
|
((check-increment-counter c)
|
|
(vector-set!
|
|
check-counters
|
|
c
|
|
(+ 1 (vector-ref check-counters c)))))))
|
|
(list init sum incr))))
|
|
(define output-checked
|
|
(lambda (file header check-test)
|
|
(set! summary '())
|
|
(set! total-possible 0)
|
|
(set! total-cast 0)
|
|
(set! total-err 0)
|
|
(set! total-any 0)
|
|
(let ((doit (lambda ()
|
|
(when (string? file)
|
|
(printf
|
|
";; Generated by Soft Scheme ~a~%"
|
|
st:version)
|
|
(printf ";; (st:control")
|
|
(for-each
|
|
(lambda (x) (printf " '~a" x))
|
|
(show-controls))
|
|
(printf ")~%")
|
|
(unless
|
|
(= 0 n-unbound)
|
|
(printf
|
|
";; CAUTION: ~a unbound references, this code is not safe~%"
|
|
n-unbound))
|
|
(printf "~%")
|
|
(for-each pretty-print header))
|
|
(for-each
|
|
(lambda (exp)
|
|
(match exp
|
|
(($ define x _)
|
|
(set! n-possible 0)
|
|
(set! n-clash 0)
|
|
(set! n-err 0)
|
|
(set! n-match 0)
|
|
(set! n-inexhaust 0)
|
|
(set! n-prim 0)
|
|
(set! n-lam 0)
|
|
(set! n-app 0)
|
|
(set! n-field 0)
|
|
(set! n-cast 0)
|
|
(if file
|
|
(pretty-print (pcheck exp check-test))
|
|
(pcheck exp check-test))
|
|
(make-summary-line x)
|
|
(set! total-possible
|
|
(+ total-possible n-possible))
|
|
(set! total-cast (+ total-cast n-cast))
|
|
(set! total-err (+ total-err n-err))
|
|
(set! total-any
|
|
(+ total-any
|
|
n-match
|
|
n-inexhaust
|
|
n-prim
|
|
n-lam
|
|
n-app
|
|
n-field
|
|
n-cast)))
|
|
(_ (when file
|
|
(pretty-print
|
|
(pcheck exp check-test))))))
|
|
tree)
|
|
(when (string? file)
|
|
(newline)
|
|
(newline)
|
|
(print-summary "; ")))))
|
|
(if (string? file)
|
|
(begin
|
|
(delete-file file)
|
|
(with-output-to-file file doit))
|
|
(doit)))))
|
|
(define total-possible 0)
|
|
(define total-err 0)
|
|
(define total-cast 0)
|
|
(define total-any 0)
|
|
(define n-possible 0)
|
|
(define n-clash 0)
|
|
(define n-err 0)
|
|
(define n-match 0)
|
|
(define n-inexhaust 0)
|
|
(define n-prim 0)
|
|
(define n-lam 0)
|
|
(define n-app 0)
|
|
(define n-field 0)
|
|
(define n-cast 0)
|
|
(define summary '())
|
|
(define make-summary-line
|
|
(lambda (x)
|
|
(let ((total (+ n-match
|
|
n-inexhaust
|
|
n-prim
|
|
n-lam
|
|
n-app
|
|
n-field
|
|
n-cast)))
|
|
(unless
|
|
(= 0 total)
|
|
(let* ((s (sprintf
|
|
"~a~a "
|
|
(padr (pname x) 16)
|
|
(padl total 2)))
|
|
(s (cond ((< 0 n-inexhaust)
|
|
(sprintf
|
|
"~a (~a match ~a inexhaust)"
|
|
s
|
|
n-match
|
|
n-inexhaust))
|
|
((< 0 n-match)
|
|
(sprintf "~a (~a match)" s n-match))
|
|
(else s)))
|
|
(s (if (< 0 n-prim)
|
|
(sprintf "~a (~a prim)" s n-prim)
|
|
s))
|
|
(s (if (< 0 n-field)
|
|
(sprintf "~a (~a field)" s n-field)
|
|
s))
|
|
(s (if (< 0 n-lam)
|
|
(sprintf "~a (~a lambda)" s n-lam)
|
|
s))
|
|
(s (if (< 0 n-app) (sprintf "~a (~a ap)" s n-app) s))
|
|
(s (if (< 0 n-err)
|
|
(sprintf "~a (~a ERROR)" s n-err)
|
|
s))
|
|
(s (if (< 0 n-cast)
|
|
(sprintf "~a (~a TYPE)" s n-cast)
|
|
s)))
|
|
(set! summary (cons s summary)))))))
|
|
(define print-summary
|
|
(lambda (hdr)
|
|
(for-each
|
|
(lambda (s) (printf "~a~a~%" hdr s))
|
|
(reverse summary))
|
|
(printf
|
|
"~a~a~a "
|
|
hdr
|
|
(padr "TOTAL CHECKS" 16)
|
|
(padl total-any 2))
|
|
(printf
|
|
" (of ~s is ~s%)"
|
|
total-possible
|
|
(if (= 0 total-possible)
|
|
0
|
|
(string->number
|
|
(chop-number
|
|
(exact->inexact
|
|
(* (/ total-any total-possible) 100))
|
|
4))))
|
|
(when (< 0 total-err)
|
|
(printf " (~s ERROR)" total-err))
|
|
(when (< 0 total-cast)
|
|
(printf " (~s TYPE)" total-cast))
|
|
(printf "~%")))
|
|
(define padl
|
|
(lambda (arg n)
|
|
(let ((s (sprintf "~a" arg)))
|
|
(recur loop
|
|
((s s))
|
|
(if (< (string-length s) n)
|
|
(loop (string-append " " s))
|
|
s)))))
|
|
(define padr
|
|
(lambda (arg n)
|
|
(let ((s (sprintf "~a" arg)))
|
|
(recur loop
|
|
((s s))
|
|
(if (< (string-length s) n)
|
|
(loop (string-append s " "))
|
|
s)))))
|
|
(define chop-number
|
|
(lambda (x n)
|
|
(substring
|
|
(sprintf "~s00000000000000000000" x)
|
|
0
|
|
(- n 1))))
|
|
(define pcheck
|
|
(lambda (ex check-test)
|
|
(unparse
|
|
ex
|
|
(lambda (e pexpr)
|
|
(match e
|
|
((and z ($ type _ ($ check inf ($ var x))))
|
|
(cond ((name-primitive x)
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pname x))
|
|
('def
|
|
(set! n-err (+ 1 n-err))
|
|
(set! n-prim (+ 1 n-prim))
|
|
`(,(symbol-append "CHECK-" (pname x))
|
|
,(tree-index z)
|
|
',(string->symbol "ERROR")))
|
|
(_ (set! n-prim (+ 1 n-prim))
|
|
`(,(symbol-append "CHECK-" (pname x))
|
|
,(tree-index z)))))
|
|
((name-unbound? x) `(check-bound ,(pname x)))
|
|
(else
|
|
(if (check-test inf)
|
|
(begin
|
|
(set! n-clash (+ 1 n-clash))
|
|
`(,(string->symbol "CLASH")
|
|
,(pname x)
|
|
,(tree-index z)))
|
|
(pname x)))))
|
|
((and z
|
|
($ type _ ($ check inf (and m ($ lam x e1)))))
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pexpr m))
|
|
('def
|
|
(set! n-err (+ 1 n-err))
|
|
(set! n-lam (+ 1 n-lam))
|
|
`(,(string->symbol "CHECK-lambda")
|
|
(,(tree-index z) ',(string->symbol "ERROR"))
|
|
,(map pname x)
|
|
,@(pexpr e1)))
|
|
(_ (set! n-lam (+ 1 n-lam))
|
|
`(,(string->symbol "CHECK-lambda")
|
|
(,(tree-index z))
|
|
,(map pname x)
|
|
,@(pexpr e1)))))
|
|
((and z
|
|
($ type
|
|
_
|
|
($ check inf (and m ($ vlam x rest e1)))))
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pexpr m))
|
|
('def
|
|
(set! n-err (+ 1 n-err))
|
|
(set! n-lam (+ 1 n-lam))
|
|
`(,(string->symbol "CHECK-lambda")
|
|
(,(tree-index z) ',(string->symbol "ERROR"))
|
|
,(append (map pname x) (pname rest))
|
|
,@(pexpr e1)))
|
|
(_ (set! n-lam (+ 1 n-lam))
|
|
`(,(string->symbol "CHECK-lambda")
|
|
(,(tree-index z))
|
|
,(append (map pname x) (pname rest))
|
|
,@(pexpr e1)))))
|
|
((and z
|
|
($ type _ ($ check inf (and m ($ app e1 args)))))
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pexpr m))
|
|
('def
|
|
(set! n-err (+ 1 n-err))
|
|
(set! n-app (+ 1 n-app))
|
|
`(,(string->symbol "CHECK-ap")
|
|
(,(tree-index z) ',(string->symbol "ERROR"))
|
|
,(pexpr e1)
|
|
,@(map pexpr args)))
|
|
(_ (set! n-app (+ 1 n-app))
|
|
(let ((p1 (pexpr e1)))
|
|
`(,(string->symbol "CHECK-ap")
|
|
(,(tree-index z))
|
|
,p1
|
|
,@(map pexpr args))))))
|
|
((and z
|
|
($ type _ ($ check inf (and m ($ field x e1)))))
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pexpr m))
|
|
('def
|
|
(set! n-err (+ 1 n-err))
|
|
(set! n-field (+ 1 n-field))
|
|
`(,(string->symbol "CHECK-field")
|
|
(,(tree-index z) ',(string->symbol "ERROR"))
|
|
,x
|
|
,(pexpr e1)))
|
|
(_ (set! n-field (+ 1 n-field))
|
|
`(,(string->symbol "CHECK-field")
|
|
(,(tree-index z))
|
|
,x
|
|
,(pexpr e1)))))
|
|
((and z
|
|
($ type
|
|
_
|
|
($ check inf (and m ($ cast (x . _) e1)))))
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pexpr m))
|
|
(_ (set! n-cast (+ 1 n-cast))
|
|
`(,(string->symbol "CHECK-:")
|
|
(,(tree-index z))
|
|
,x
|
|
,(pexpr e1)))))
|
|
((and z
|
|
($ type
|
|
_
|
|
($ check inf (and m ($ match e1 clauses)))))
|
|
(set! n-possible (+ 1 n-possible))
|
|
(match (check-test inf)
|
|
(#f (pexpr m))
|
|
(inx (let* ((pclause
|
|
(match-lambda
|
|
(($ mclause p exp fail)
|
|
(if fail
|
|
`(,(ppat p)
|
|
(=> ,(pname fail))
|
|
,@(pexpr exp))
|
|
`(,(ppat p) ,@(pexpr exp))))))
|
|
(p1 (pexpr e1)))
|
|
(if (eq? 'inexhaust inx)
|
|
(begin
|
|
(set! n-inexhaust (+ 1 n-inexhaust))
|
|
`(,(string->symbol "CHECK-match")
|
|
(,(tree-index z)
|
|
,(string->symbol "INEXHAUST"))
|
|
,p1
|
|
,@(maplr pclause clauses)))
|
|
(begin
|
|
(set! n-match (+ 1 n-match))
|
|
`(,(string->symbol "CHECK-match")
|
|
(,(tree-index z))
|
|
,p1
|
|
,@(maplr pclause clauses)))))))))))))
|
|
(define tree-index-list '())
|
|
(define reinit-output!
|
|
(lambda () (set! tree-index-list '())))
|
|
(define tree-index
|
|
(lambda (syntax)
|
|
(match (assq syntax tree-index-list)
|
|
(#f
|
|
(let ((n (length tree-index-list)))
|
|
(set! tree-index-list
|
|
(cons (cons syntax n) tree-index-list))
|
|
n))
|
|
((_ . n) n))))
|
|
(define tree-unindex
|
|
(lambda (n)
|
|
(let ((max (length tree-index-list)))
|
|
(when (<= max n)
|
|
(use-error "Invalid CHECK number ~a" n))
|
|
(car (list-ref tree-index-list (- (- max 1) n))))))
|
|
(define cause
|
|
(lambda ()
|
|
(for-each
|
|
(lambda (def)
|
|
(for-each pretty-print (exp-cause def)))
|
|
tree)))
|
|
(define cause*
|
|
(lambda names
|
|
(if (null? names)
|
|
(for-each
|
|
(lambda (def)
|
|
(for-each pretty-print (exp-cause def)))
|
|
tree)
|
|
(for-each
|
|
(match-lambda
|
|
((? symbol? dname)
|
|
(for-each
|
|
pretty-print
|
|
(exp-cause (find-global dname)))))
|
|
names))))
|
|
(define exp-cause
|
|
(let ((sum (lambda (exps)
|
|
(foldr (lambda (x y) (append (exp-cause x) y))
|
|
'()
|
|
exps)))
|
|
(src (lambda (inf)
|
|
(let ((nonlocal (map tree-index (check-sources inf))))
|
|
(if (type-check1? inf)
|
|
(cons (check-local-sources inf) nonlocal)
|
|
nonlocal)))))
|
|
(match-lambda
|
|
((and z ($ type ty ($ check inf ($ var x))))
|
|
(if (name-primitive x)
|
|
(if (type-check? inf)
|
|
(list `((,(symbol-append 'check- (pname x))
|
|
,(tree-index z))
|
|
,@(src inf)))
|
|
'())
|
|
(if (type-check1? inf)
|
|
(list `((clash ,(pname x) ,(tree-index z)) ,@(src inf)))
|
|
'())))
|
|
((and z ($ type ty ($ check inf ($ lam x e1))))
|
|
(append
|
|
(if (type-check? inf)
|
|
(list `((check-lambda ,(tree-index z) ,(map pname x) ...)
|
|
,@(src inf)))
|
|
'())
|
|
(exp-cause e1)))
|
|
((and z
|
|
($ type ty ($ check inf ($ vlam x rest e1))))
|
|
(append
|
|
(if (type-check? inf)
|
|
(list `((check-lambda
|
|
,(tree-index z)
|
|
,(append (map pname x) (pname rest))
|
|
...)
|
|
,@(src inf)))
|
|
'())
|
|
(exp-cause e1)))
|
|
((and z ($ type _ ($ check inf ($ app e1 args))))
|
|
(append
|
|
(if (type-check? inf)
|
|
(list `((check-ap ,(tree-index z)) ,@(src inf)))
|
|
'())
|
|
(exp-cause e1)
|
|
(sum args)))
|
|
((and z ($ type _ ($ check inf ($ field x e1))))
|
|
(append
|
|
(if (type-check? inf)
|
|
(list `((check-field ,(tree-index z) ,x ...)
|
|
,@(src inf)))
|
|
'())
|
|
(exp-cause e1)))
|
|
((and z
|
|
($ type _ ($ check inf ($ cast (x . _) e1))))
|
|
(append
|
|
(if (type-check? inf)
|
|
(list `((check-: ,(tree-index z) ,x ...) ,@(src inf)))
|
|
'())
|
|
(exp-cause e1)))
|
|
((and z
|
|
($ type
|
|
_
|
|
($ check inf (and m ($ match e1 clauses)))))
|
|
(append
|
|
(if (type-check? inf)
|
|
(list `((check-match ,(tree-index z) ...) ,@(src inf)))
|
|
'())
|
|
(exp-cause m)))
|
|
(($ define _ e) (exp-cause e))
|
|
((? defstruct?) '())
|
|
((? datatype?) '())
|
|
(($ app e1 args) (sum (cons e1 args)))
|
|
(($ match exp clauses)
|
|
(foldr (lambda (x y)
|
|
(append
|
|
(match x (($ mclause _ e _) (exp-cause e)))
|
|
y))
|
|
(exp-cause exp)
|
|
clauses))
|
|
(($ var _) '())
|
|
(($ and exps) (sum exps))
|
|
(($ begin exps) (sum exps))
|
|
((? const?) '())
|
|
(($ if test then els)
|
|
(append
|
|
(exp-cause test)
|
|
(exp-cause then)
|
|
(exp-cause els)))
|
|
(($ let bindings body)
|
|
(foldr (lambda (x y)
|
|
(append (match x (($ bind _ e) (exp-cause e))) y))
|
|
(exp-cause body)
|
|
bindings))
|
|
(($ let* bindings body)
|
|
(foldr (lambda (x y)
|
|
(append (match x (($ bind _ e) (exp-cause e))) y))
|
|
(exp-cause body)
|
|
bindings))
|
|
(($ letr bindings body)
|
|
(foldr (lambda (x y)
|
|
(append (match x (($ bind _ e) (exp-cause e))) y))
|
|
(exp-cause body)
|
|
bindings))
|
|
(($ body defs exps) (sum (append defs exps)))
|
|
(($ or exps) (sum exps))
|
|
(($ delay e) (exp-cause e))
|
|
(($ set! var body) (exp-cause body))
|
|
(($ record bindings)
|
|
(foldr (lambda (x y)
|
|
(append (match x (($ bind _ e) (exp-cause e))) y))
|
|
'()
|
|
bindings))
|
|
(($ type _ exp) (exp-cause exp)))))
|
|
(define display-type tidy)
|
|
(define type
|
|
(lambda names
|
|
(if (null? names)
|
|
(for-each globaldef tree)
|
|
(for-each
|
|
(match-lambda
|
|
((? symbol? x)
|
|
(match (lookup? global-env x)
|
|
(#f (use-error "~a is not defined" x))
|
|
(ty (pretty-print
|
|
`(,x : ,(display-type (name-ty ty)))))))
|
|
((? number? n)
|
|
(let* ((ty (check-type (tree-unindex n)))
|
|
(type (display-type ty)))
|
|
(pretty-print `(,n : ,type))))
|
|
(_ (use-error
|
|
"arguments must be identifiers or CHECK numbers")))
|
|
names))))
|
|
(define localtype
|
|
(lambda names
|
|
(if (null? names)
|
|
(for-each localdef tree)
|
|
(for-each
|
|
(lambda (x) (localdef (find-global x)))
|
|
names))))
|
|
(define find-global
|
|
(lambda (name)
|
|
(let ((d (ormap (match-lambda
|
|
((and d ($ define x _))
|
|
(and (eq? name (name-name x)) d))
|
|
(_ #f))
|
|
tree)))
|
|
(unless d (use-error "~a is not defined" name))
|
|
d)))
|
|
(define globaldef
|
|
(lambda (e)
|
|
(match e
|
|
(($ define x _)
|
|
(let ((type (display-type (name-ty x))))
|
|
(pretty-print `(,(pname x) : ,type))))
|
|
(_ #f))))
|
|
(define localdef
|
|
(lambda (e) (pretty-print (expdef e))))
|
|
(define expdef
|
|
(let* ((show (lambda (x)
|
|
`(,(pname x) : ,(display-type (name-ty x)))))
|
|
(pbind (match-lambda
|
|
(($ bind x e) `(,(show x) ,(expdef e))))))
|
|
(match-lambda
|
|
(($ define x e)
|
|
(if (or (not x) (and (name? x) (not (name-name x))))
|
|
(expdef e)
|
|
`(define ,(show x) ,(expdef e))))
|
|
((? defstruct? d) (pdef d))
|
|
((? datatype? d) (pdef d))
|
|
(($ and exps) `(and ,@(maplr expdef exps)))
|
|
(($ app fun args)
|
|
`(,(expdef fun) ,@(maplr expdef args)))
|
|
(($ begin exps) `(begin ,@(maplr expdef exps)))
|
|
(($ const c _) (pconst c))
|
|
(($ if test then els)
|
|
`(if ,(expdef test) ,(expdef then) ,(expdef els)))
|
|
(($ lam params body)
|
|
`(lambda ,(map show params) ,@(expdef body)))
|
|
(($ vlam params rest body)
|
|
`(lambda ,(append (map show params) (show rest))
|
|
,@(expdef body)))
|
|
(($ let bindings body)
|
|
`(let ,(map pbind bindings) ,@(expdef body)))
|
|
(($ let* bindings body)
|
|
`(let* ,(map pbind bindings) ,@(expdef body)))
|
|
(($ letr bindings body)
|
|
`(letrec ,(map pbind bindings) ,@(expdef body)))
|
|
(($ body defs exps)
|
|
(let ((pdefs (maplr expdef defs)))
|
|
(append pdefs (maplr expdef exps))))
|
|
(($ record bindings)
|
|
`(record ,@(maplr pbind bindings)))
|
|
(($ field x e) `(field ,x ,(expdef e)))
|
|
(($ cast (ty . _) e) `(: ,ty ,(expdef e)))
|
|
(($ or exps) `(or ,@(maplr expdef exps)))
|
|
(($ delay e) `(delay ,(expdef e)))
|
|
(($ set! x body)
|
|
`(set! ,(pname x) ,(expdef body)))
|
|
(($ var x) (pname x))
|
|
(($ match e1 clauses)
|
|
(let* ((pclause
|
|
(match-lambda
|
|
(($ mclause p exp fail)
|
|
(if fail
|
|
`(,(expdef p) (=> ,(pname fail)) ,@(expdef exp))
|
|
`(,(expdef p) ,@(expdef exp))))))
|
|
(p1 (expdef e1)))
|
|
`(match ,p1 ,@(maplr pclause clauses))))
|
|
(($ pconst x _) (pconst x))
|
|
(($ pvar x) (show x))
|
|
(($ pany) '_)
|
|
(($ pelse) 'else)
|
|
(($ pnot pat) `(not ,(expdef pat)))
|
|
(($ pand pats) `(and ,@(maplr expdef pats)))
|
|
(($ ppred pred)
|
|
(match (pname pred)
|
|
('false-object? #f)
|
|
('true-object? #t)
|
|
('null? '())
|
|
(x `(? ,x))))
|
|
(($ pobj tag args)
|
|
(match (cons (pname tag) args)
|
|
(('pair? x y) (cons (expdef x) (expdef y)))
|
|
(('box? x) (box (expdef x)))
|
|
(('vector? . x) (list->vector (maplr expdef x)))
|
|
((tg . _)
|
|
`($ ,(strip-? tg) ,@(maplr expdef args)))))
|
|
(($ type _ exp) (expdef exp))
|
|
(($ check _ exp) (expdef exp)))))
|
|
(define check-type
|
|
(match-lambda
|
|
(($ type ty ($ check inf ($ var x))) ty)
|
|
(($ type ty ($ check inf ($ lam x e1))) ty)
|
|
(($ type ty ($ check inf ($ vlam x rest e1))) ty)
|
|
(($ type _ ($ check inf ($ app e1 args)))
|
|
(typeof e1))
|
|
(($ type _ ($ check inf ($ field x e1)))
|
|
(typeof e1))
|
|
(($ type _ ($ check inf ($ cast (x . _) e1)))
|
|
(typeof e1))
|
|
(($ type _ ($ check inf ($ match e1 clauses)))
|
|
(typeof e1))))
|
|
(define tree '())
|
|
(define global-env empty-env)
|
|
(define verbose #f)
|
|
(define times #t)
|
|
(define benchmarking #f)
|
|
(define cons-mutators '(set-car! set-cdr!))
|
|
(define st:check
|
|
(lambda args
|
|
(parameterize
|
|
((print-level #f)
|
|
(print-length #f)
|
|
(pretty-maximum-lines #f))
|
|
(let ((output (apply do-soft args)))
|
|
(when output
|
|
(printf
|
|
"Typed program written to file ~a~%"
|
|
output))))))
|
|
(define st:run
|
|
(lambda (file)
|
|
(parameterize
|
|
((optimize-level 3))
|
|
(when benchmarking
|
|
(printf "Reloading slow CHECKs...~%")
|
|
(load (string-append
|
|
installation-directory
|
|
"checklib.scm"))
|
|
(set! benchmarking #f))
|
|
(load file))))
|
|
(define st:bench
|
|
(lambda (file)
|
|
(parameterize
|
|
((optimize-level 3))
|
|
(unless
|
|
benchmarking
|
|
(unless
|
|
fastlibrary-file
|
|
(use-error
|
|
"No benchmarking mode in this version"))
|
|
(printf "Reloading fast CHECKs...~%")
|
|
(load (string-append
|
|
installation-directory
|
|
fastlibrary-file))
|
|
(set! benchmarking #t))
|
|
(load file))))
|
|
(define st:
|
|
(lambda args
|
|
(parameterize
|
|
((print-level #f)
|
|
(print-length #f)
|
|
(pretty-maximum-lines #f))
|
|
(let ((output (apply do-soft args)))
|
|
(cond ((not output)
|
|
(use-error "Output file name required to run"))
|
|
((= 0 n-unbound)
|
|
(printf
|
|
"Typed program written to file ~a, executing ...~%"
|
|
output)
|
|
(flush-output)
|
|
(st:run output))
|
|
(else
|
|
(printf
|
|
"Typed program written to file ~a, not executing (unbound refs)~%"
|
|
output)))))))
|
|
(define do-soft
|
|
(match-lambda*
|
|
((input (? string? output))
|
|
(when (strip-suffix output)
|
|
(use-error
|
|
"output file name cannot end in .ss or .scm"))
|
|
(cond ((string? input)
|
|
(soft-files (list input) output)
|
|
output)
|
|
((and (list? input) (andmap string? input))
|
|
(soft-files input output)
|
|
output)
|
|
(else (soft-def input output) output)))
|
|
((input #f)
|
|
(cond ((string? input) (soft-files (list input) #f) #f)
|
|
((and (list? input) (andmap string? input))
|
|
(soft-files input #f)
|
|
#f)
|
|
(else (soft-def input #f) #f)))
|
|
((input)
|
|
(cond ((string? input)
|
|
(let ((o (string-append
|
|
(or (strip-suffix input) input)
|
|
".soft")))
|
|
(soft-files (list input) o)
|
|
o))
|
|
((and (list? input) (andmap string? input))
|
|
(use-error "Output file name required"))
|
|
(else (soft-def input #t) #f)))
|
|
(else (use-error
|
|
"Input must be a file name or list of file names"))))
|
|
(define rawmode #f)
|
|
(define st:control
|
|
(lambda args
|
|
(let ((dbg (match-lambda
|
|
('raw
|
|
(set! display-type ptype)
|
|
(set! rawmode #t))
|
|
('!raw
|
|
(set! display-type tidy)
|
|
(set! rawmode #f))
|
|
('verbose (set! verbose #t))
|
|
('!verbose (set! verbose #f))
|
|
('times (set! times #t))
|
|
('!times (set! times #f))
|
|
('partial (set! fullsharing #f))
|
|
('!partial (set! fullsharing #t))
|
|
('pseudo (set! pseudo pseudo-subtype))
|
|
('!pseudo (set! pseudo #f))
|
|
('populated (set! populated #t))
|
|
('!populated (set! populated #f))
|
|
('matchst (set! matchst #t))
|
|
('!matchst (set! matchst #f))
|
|
('genmatch (set! genmatch #t))
|
|
('!genmatch (set! genmatch #f))
|
|
('letonce (set! letonce #t))
|
|
('!letonce (set! letonce #f))
|
|
('global-error (set! global-error #t))
|
|
('!global-error (set! global-error #f))
|
|
('share (set! share #t))
|
|
('!share (set! share #f))
|
|
('flags (set! flags #t))
|
|
('!flags (set! flags #f))
|
|
('depths (set! dump-depths #t))
|
|
('!depths (set! dump-depths #f))
|
|
('match (set! keep-match #t))
|
|
('!match (set! keep-match #f))
|
|
(x (printf "Error: unknown debug switch ~a~%" x)
|
|
(st:control)))))
|
|
(if (null? args)
|
|
(begin
|
|
(printf "Current values:")
|
|
(for-each
|
|
(lambda (x) (printf " ~a" x))
|
|
(show-controls))
|
|
(printf "~%"))
|
|
(for-each dbg args)))))
|
|
(define show-controls
|
|
(lambda ()
|
|
(list (if rawmode 'raw '!raw)
|
|
(if verbose 'verbose '!verbose)
|
|
(if times 'times '!times)
|
|
(if share 'share '!share)
|
|
(if flags 'flags '!flags)
|
|
(if dump-depths 'depths '!depths)
|
|
(if fullsharing '!partial 'partial)
|
|
(if pseudo 'pseudo '!pseudo)
|
|
(if populated 'populated '!populated)
|
|
(if letonce 'letonce '!letonce)
|
|
(if matchst 'matchst '!matchst)
|
|
(if genmatch 'genmatch '!genmatch)
|
|
(if global-error 'global-error '!global-error)
|
|
(if keep-match 'match '!match))))
|
|
(define soft-def
|
|
(lambda (exp output)
|
|
(reinit-macros!)
|
|
(reinit-types!)
|
|
(reinit-output!)
|
|
(set! visible-time 0)
|
|
(match-let*
|
|
((before-parse (cpu-time))
|
|
(defs (parse-def exp))
|
|
(before-bind (cpu-time))
|
|
((defs env tenv unbound)
|
|
(bind-defs
|
|
defs
|
|
initial-env
|
|
initial-type-env
|
|
'()
|
|
0))
|
|
(_ (warn-unbound unbound))
|
|
(_ (if cons-is-mutable
|
|
(printf
|
|
"Note: use of ~a, treating cons as MUTABLE~%"
|
|
cons-mutators)
|
|
(printf
|
|
"Note: no use of ~a, treating cons as immutable~%"
|
|
cons-mutators)))
|
|
(before-improve (cpu-time))
|
|
(defs (improve-defs defs))
|
|
(before-typecheck (cpu-time))
|
|
(_ (type-check defs))
|
|
(_ (set! global-env env))
|
|
(before-output (cpu-time))
|
|
(_ (check output))
|
|
(_ (print-summary ""))
|
|
(before-end (cpu-time)))
|
|
(when times
|
|
(printf
|
|
"~a seconds parsing,~%"
|
|
(exact->inexact
|
|
(* (- before-bind before-parse)
|
|
clock-granularity)))
|
|
(printf
|
|
"~a seconds binding,~%"
|
|
(exact->inexact
|
|
(* (- before-improve before-bind)
|
|
clock-granularity)))
|
|
(printf
|
|
"~a seconds improving,~%"
|
|
(exact->inexact
|
|
(* (- before-typecheck before-improve)
|
|
clock-granularity)))
|
|
(printf
|
|
"~a seconds type checking,~%"
|
|
(exact->inexact
|
|
(* (- (- before-output before-typecheck)
|
|
visible-time)
|
|
clock-granularity)))
|
|
(printf
|
|
"~a seconds setting visibility,~%"
|
|
(exact->inexact
|
|
(* visible-time clock-granularity)))
|
|
(printf
|
|
"~a seconds writing output,~%"
|
|
(exact->inexact
|
|
(* (- before-end before-output)
|
|
clock-granularity)))
|
|
(printf
|
|
"~a seconds in total.~%"
|
|
(exact->inexact
|
|
(* (- before-end before-parse) clock-granularity)))))))
|
|
(define type-check
|
|
(lambda (defs)
|
|
(set! tree defs)
|
|
(type-defs defs)
|
|
defs))
|
|
(define soft-files
|
|
(lambda (files output)
|
|
(let ((contents
|
|
(map (lambda (f) `(begin ,@(readfile f))) files)))
|
|
(soft-def `(begin ,@contents) output))))
|
|
(define strip-suffix
|
|
(lambda (name)
|
|
(let ((n (string-length name)))
|
|
(or (and (<= 3 n)
|
|
(equal? ".ss" (substring name (- n 3) n))
|
|
(substring name 0 (- n 3)))
|
|
(and (<= 4 n)
|
|
(equal? ".scm" (substring name (- n 4) n))
|
|
(substring name 0 (- n 4)))))))
|
|
(define st:deftype
|
|
(match-lambda*
|
|
(((? symbol? x) ? list? mutability)
|
|
(=> fail)
|
|
(if (andmap boolean? mutability)
|
|
(deftype x mutability)
|
|
(fail)))
|
|
(args (use-error
|
|
"Invalid command ~a"
|
|
`(st:deftype ,@args)))))
|
|
(define st:defprim
|
|
(match-lambda*
|
|
(((? symbol? x) type) (defprim x type 'impure))
|
|
(((? symbol? x) type (? symbol? mode))
|
|
(defprim x type mode))
|
|
(args (use-error
|
|
"Invalid command ~a"
|
|
`(st:defprim ,@args)))))
|
|
(define st:help
|
|
(lambda ()
|
|
(printf
|
|
"Commands for Soft Scheme (~a)~%"
|
|
st:version)
|
|
(printf
|
|
" (st: file (output)) type check file and execute~%")
|
|
(printf
|
|
" (st:type (name)) print types of global defs~%")
|
|
(printf
|
|
" (st:check file (output)) type check file~%")
|
|
(printf
|
|
" (st:run file) execute type checked file~%")
|
|
(printf
|
|
" (st:bench file) execute type checked file fast~%")
|
|
(printf
|
|
" (st:ltype (name)) print types of local defs~%")
|
|
(printf
|
|
" (st:cause) print cause of CHECKs~%")
|
|
(printf
|
|
" (st:summary) print summary of CHECKs~%")
|
|
(printf
|
|
" (st:help) prints this message~%")
|
|
(printf
|
|
" (st:defprim name type (mode)) define a new primitive~%")
|
|
(printf
|
|
" (st:deftype name bool ...) define a new type constructor~%")
|
|
(printf
|
|
" (st:control flag ...) set internal flags~%")
|
|
(printf
|
|
"For more info, see ftp://ftp.nj.nec.com/pub/wright/ssmanual/softscheme.html~%")
|
|
(printf
|
|
"Copyright (c) 1993, 1994, 1995 by Andrew K. Wright under the~%")
|
|
(printf
|
|
"terms of the Gnu Public License. No warranties of any kind apply.~%")))
|
|
(define st:type type)
|
|
(define st:ltype localtype)
|
|
(define st:cause cause)
|
|
(define st:summary
|
|
(lambda () (print-summary "")))
|
|
(define init!
|
|
(lambda ()
|
|
(when customization-file
|
|
(load (string-append
|
|
installation-directory
|
|
customization-file)))
|
|
(let ((softrc
|
|
(string-append home-directory "/.softschemerc")))
|
|
(when (file-exists? softrc) (load softrc)))
|
|
(set! global-env initial-env)
|
|
(st:help)))
|
|
(init!)
|