[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
guile/guile-scsh ChangeLog INCOMPAT USAGE alt-s...
From: |
Gary Houston |
Subject: |
guile/guile-scsh ChangeLog INCOMPAT USAGE alt-s... |
Date: |
Sat, 04 Aug 2001 03:26:38 -0700 |
CVSROOT: /cvs
Module name: guile
Changes by: Gary Houston <address@hidden> 01/08/04 03:26:38
Modified files:
guile-scsh : ChangeLog INCOMPAT USAGE alt-syntax.scm
fileinfo.scm fr.scm glob.scm let-opt.scm
Log message:
* glob.scm, fr.scm, fileinfo.scm, let-opt.scm:
upgraded with scsh 0.5.2 -> scsh 0.5.3 changes.
* fr.scm, glob.scm: don't use module (scsh cset-obsolete).
* let-opt.scm: don't export really-let-optionals*, it's gone.
commented out the last part the file to avoid 2nd let-optionals*
definition, which doesn't work in Guile. use module (ice-9 receive).
* alt-syntax.scm: re-export syntax-error: a kludge to allow
define-syntax macro expansion to use it.
CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/ChangeLog.diff?cvsroot=OldCVS&tr1=1.71&tr2=1.72&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/INCOMPAT.diff?cvsroot=OldCVS&tr1=1.23&tr2=1.24&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/USAGE.diff?cvsroot=OldCVS&tr1=1.19&tr2=1.20&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/alt-syntax.scm.diff?cvsroot=OldCVS&tr1=1.3&tr2=1.4&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/fileinfo.scm.diff?cvsroot=OldCVS&tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/fr.scm.diff?cvsroot=OldCVS&tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/glob.scm.diff?cvsroot=OldCVS&tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/guile/guile-scsh/let-opt.scm.diff?cvsroot=OldCVS&tr1=1.5&tr2=1.6&r1=text&r2=text
Patches:
Index: guile/guile-scsh/ChangeLog
diff -u guile/guile-scsh/ChangeLog:1.71 guile/guile-scsh/ChangeLog:1.72
--- guile/guile-scsh/ChangeLog:1.71 Wed Aug 1 14:49:58 2001
+++ guile/guile-scsh/ChangeLog Sat Aug 4 03:26:37 2001
@@ -1,3 +1,16 @@
+2001-08-03 Gary Houston <address@hidden>
+
+ * glob.scm, fr.scm, fileinfo.scm, let-opt.scm:
+ upgraded with scsh 0.5.2 -> scsh 0.5.3 changes.
+
+ * fr.scm, glob.scm: don't use module (scsh cset-obsolete).
+ * let-opt.scm: don't export really-let-optionals*, it's gone.
+ commented out the last part the file to avoid 2nd let-optionals*
+ definition, which doesn't work in Guile. use module (ice-9 receive).
+
+ * alt-syntax.scm: re-export syntax-error: a kludge to allow
+ define-syntax macro expansion to use it.
+
2001-08-01 Gary Houston <address@hidden>
* char-p.scm: new file, for new module (scsh char-p).
Index: guile/guile-scsh/INCOMPAT
diff -u guile/guile-scsh/INCOMPAT:1.23 guile/guile-scsh/INCOMPAT:1.24
--- guile/guile-scsh/INCOMPAT:1.23 Tue Jun 12 14:38:44 2001
+++ guile/guile-scsh/INCOMPAT Sat Aug 4 03:26:37 2001
@@ -8,9 +8,13 @@
scsh features not implemented
=============================
+The ODBC interface.
+
enabled-interrupts, interrupt-set, itimer, %set-unix-signal-handler,
set-enabled-interrupts, %unix-signal-handler,
with-enabled-interrupts*.
+
+(incomplete, more below.)
Bugs in scsh fixed in guile-scsh
================================
Index: guile/guile-scsh/USAGE
diff -u guile/guile-scsh/USAGE:1.19 guile/guile-scsh/USAGE:1.20
--- guile/guile-scsh/USAGE:1.19 Wed Aug 1 13:42:57 2001
+++ guile/guile-scsh/USAGE Sat Aug 4 03:26:37 2001
@@ -174,8 +174,9 @@
(regexp-fold regexp-fold-right regexp-for-each)
(scsh rx re-syntax)
-;; rx macro generates code that requires
-;; (scsh rx re)
+;; rx macro generates code that requires at least:
+;; (scsh rx re) (srfi srfi-14) (scsh cset-obsolete)
+;; (scsh cset-obsolete only needed until rx upgraded to 0.5.3.
(sre-form? expand-rx if-sre-form rx)
(scsh rx parse)
Index: guile/guile-scsh/alt-syntax.scm
diff -u guile/guile-scsh/alt-syntax.scm:1.3 guile/guile-scsh/alt-syntax.scm:1.4
--- guile/guile-scsh/alt-syntax.scm:1.3 Sun Oct 15 13:14:50 2000
+++ guile/guile-scsh/alt-syntax.scm Sat Aug 4 03:26:37 2001
@@ -5,6 +5,9 @@
:use-module (scsh signals))
(export-syntax define-syntax syntax-rules)
+;; kludge: may appear in define-syntax expansion.
+(re-export syntax-error)
+
; This definition of define-syntax is appropriate for Scheme-to-C.
;(define-macro define-syntax
Index: guile/guile-scsh/fileinfo.scm
diff -u guile/guile-scsh/fileinfo.scm:1.4 guile/guile-scsh/fileinfo.scm:1.5
--- guile/guile-scsh/fileinfo.scm:1.4 Sat Jul 7 08:35:28 2001
+++ guile/guile-scsh/fileinfo.scm Sat Aug 4 03:26:37 2001
@@ -67,7 +67,7 @@
(let ((uid (user-effective-uid)))
(with-errno-handler ((err data)
((errno/acces) 'search-denied)
- ((errno/notdir) 'not-directory)
+ ((errno/notdir) 'no-directory)
;; If the file doesn't exist, we usually return
;; 'nonexistent, but we special-case writability
Index: guile/guile-scsh/fr.scm
diff -u guile/guile-scsh/fr.scm:1.4 guile/guile-scsh/fr.scm:1.5
--- guile/guile-scsh/fr.scm:1.4 Wed Aug 1 13:42:57 2001
+++ guile/guile-scsh/fr.scm Sat Aug 4 03:26:37 2001
@@ -11,7 +11,10 @@
:use-module (ice-9 receive)
:use-module (scsh let-opt)
:use-module (srfi srfi-14)
+
+ ;; can be removed when rx upgraded to 0.5.3
:use-module (scsh cset-obsolete)
+
:use-module (scsh rdelim)
:use-module (scsh rx re)
:use-module (scsh rx re-low)
@@ -332,7 +335,7 @@
s)))
((concat) ; CONCAT-delimiter reader.
- (let ((not-delims (char-set-invert delims)))
+ (let ((not-delims (char-set-complement delims)))
(lambda maybe-port
(let* ((p (:optional maybe-port (current-input-port)))
(s (read-delimited delims p 'concat)))
@@ -342,7 +345,7 @@
(string-append s extra-delims))))))))
((split) ; SPLIT-delimiter reader.
- (let ((not-delims (char-set-invert delims)))
+ (let ((not-delims (char-set-complement delims)))
(lambda maybe-port
(let ((p (:optional maybe-port (current-input-port))))
(receive (s delim) (read-delimited delims p 'split)
Index: guile/guile-scsh/glob.scm
diff -u guile/guile-scsh/glob.scm:1.4 guile/guile-scsh/glob.scm:1.5
--- guile/guile-scsh/glob.scm:1.4 Wed Aug 1 13:42:57 2001
+++ guile/guile-scsh/glob.scm Sat Aug 4 03:26:37 2001
@@ -16,7 +16,6 @@
:use-module (scsh rx re)
:use-module (scsh utilities)
:use-module (srfi srfi-14)
- :use-module (scsh cset-obsolete)
:use-module (scsh scsh-condition)
:use-module (scsh syscalls)
)
@@ -119,7 +118,7 @@
(res (list re-bos))
(i 0))
(if (= i pat-len)
- (re-seq (reverse (str-cons chars res)))
+ (re-seq (reverse (cons re-eos (str-cons chars res))))
(let ((c (string-ref pat i))
(i (+ i 1)))
@@ -136,10 +135,9 @@
(cons re-any (str-cons chars res))
i))
- ((#\[) (receive (cset i) (parse-glob-bracket pat i)
+ ((#\[) (receive (re i) (parse-glob-bracket pat i)
(lp '()
- (cons (re-char-set cset)
- (str-cons chars res))
+ (cons re (str-cons chars res))
i)))
(else (lp (cons c chars) res i))))))))))
@@ -165,16 +163,15 @@
(case c
((#\])
(let ((cset (fold (lambda (elt cset)
- (char-set-union
- cset
- (if (char? elt)
- (char-set elt)
- (ascii-range->char-set (char->ascii
(car elt))
- (+ 1
(char->ascii (cdr elt)))))))
- char-set:empty
+ (if (char? elt)
+ (char-set-adjoin! cset elt)
+ (ucs-range->char-set! (char->ascii
(car elt))
+ (+ 1
(char->ascii (cdr elt)))
+ #f cset)))
+ (char-set-copy char-set:empty)
elts)))
(values (re-char-set (if negate?
- (char-set-invert cset)
+ (char-set-complement! cset)
cset))
i)))
Index: guile/guile-scsh/let-opt.scm
diff -u guile/guile-scsh/let-opt.scm:1.5 guile/guile-scsh/let-opt.scm:1.6
--- guile/guile-scsh/let-opt.scm:1.5 Sun Jul 22 10:54:26 2001
+++ guile/guile-scsh/let-opt.scm Sat Aug 4 03:26:37 2001
@@ -1,45 +1,66 @@
+;;; LET-OPTIONALS macros
+;;; Copyright (c) 2001 by Olin Shivers.
+;;; See file COPYING.
+
;;; This file defines three macros for parsing optional arguments to procs:
-;;; (LET-OPTIONALS arg-list ((var1 default1) ...) . body)
-;;; (LET-OPTIONALS* arg-list ((var1 default1) ...) . body)
-;;; (:OPTIONAL rest-arg default-exp)
+;;; (LET-OPTIONALS arg-list (opt-clause1 ... opt-clauseN [rest])
+;;; body ...)
+;;; (LET-OPTIONALS* arg-list (opt-clause1 ... opt-clauseN [rest])
+;;; body ...)
+;;; (:OPTIONAL rest-arg default-exp [arg-check])
+;;; where
+;;; <opt-clause> ::= (var default [arg-check supplied?])
+;;; | ((var1 ... varN) external-arg-parser)
+;;;
+;;; LET-OPTIONALS* has LET* scope -- each arg clause sees the bindings of
+;;; the previous clauses. LET-OPTIONALS has LET scope -- each arg clause
+;;; sees the outer scope (an ARG-CHECK expression sees the outer scope
+;;; *plus* the variable being bound by that clause, by necessity).
+;;;
+;;; In practice, LET-OPTIONALS* is the one you want.
+;;;
+;;; The only interesting module that is exported by this file is
+;;; LET-OPT
+;;; which obeys the following interface:
+;;; (exports (let-optionals :syntax)
+;;; (let-optionals* :syntax)
+;;; (:optional :syntax))
;;;
;;; The LET-OPTIONALS macro is defined using the Clinger/Rees
;;; explicit-renaming low-level macro system. You'll have to do some work to
;;; port it to another macro system.
;;;
-;;; The LET-OPTIONALS* and :OPTIONAL macros are defined with simple
-;;; high-level macros, and should be portable to any R4RS system.
+;;; The :OPTIONAL macro is defined with simple high-level macros,
+;;; and should be portable to any R4RS system.
;;;
;;; These macros are all careful to evaluate their default forms *only* if
;;; their values are needed.
;;;
+;;; The LET-OPTIONALS expander is pretty hairy. Sorry. It does produce
+;;; very good code.
+;;;
;;; The top-level forms in this file are Scheme 48 module expressions.
;;; I use the module system to help me break up the expander code for
;;; LET-OPTIONALS into three procedures, which makes it easier to understand
;;; and test. But if you wanted to port this code to a module-less Scheme
-;;; system, you'd probably have to inline the three procs into the actual
+;;; system, you'd probably have to inline the auxiliary procs into the actual
;;; macro definition.
;;;
-;;; The only interesting module that is exported by this file is
-;;; LET-OPT
-;;; which obeys the following interface:
-;;; (exports (let-optionals :syntax)
-;;; (let-optionals* :syntax)
-;;; (:optional :syntax))
-;;;
;;; To repeat: This code is not simple Scheme code; it is module code.
;;; It must be loaded into the Scheme 48 ,config package, not the ,user
;;; package.
;;;
-;;; The only non-R4RS dependencies in the macros are ERROR
+;;; The only non-R4RS dependencies in the macros are ERROR, RECEIVE,
;;; and CALL-WITH-VALUES.
;;;
;;; See below for details on each macro.
;;; -Olin
-;;; (LET-OPTIONALS arg-list ((var1 default1) ...)
-;;; body
-;;; ...)
+;;; (LET-OPTIONALS* arg-list (clause ... [rest]) body ...)
+;;; (LET-OPTIONALS arg-list (clause ... [rest]) body ...)
+;;;
+;;; clause ::= (var default [arg-test supplied?]) ; The simple case
+;;; | ((var1 ...) external-arg-parser) ; external hook
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; This form is for binding a procedure's optional arguments to either
;;; the passed-in values or a default.
@@ -49,138 +70,392 @@
;;; the remaining VARi are bound to their corresponding DEFAULTi values.
;;; It is an error if there are more args than variables.
;;;
+;;; Simple example:
+;;; (let-optionals* args ((in (current-input-port))
+;;; (out (current-output-port))
+;;; (nbytes (string-length s)))
+;;; ...)
+;;;
;;; - The default expressions are *not* evaluated unless needed.
+;;;
+;;; - When a LET-OPTIONALS* form is evaluated, the default expressions are
+;;; carried out in a "sequential" LET*-style scope -- each clause is
+;;; evaluated in a scope that sees the bindings introduced by the previous
+;;; clauses.
+;;;
+;;; - LET-OPTIONALS, in contrast, evaluates all clauses in the *outer*
+;;; environment. Each ARG-TEST form, however, does see the variable
+;;; bound by that clause (see below).
+;;;
+;;; - If there's an ARG-TEST form, it is evaluated when an argument is
+;;; passed in; it is not evaluated when the argument is defaulted.
+;;; If it produces false, an error is raised. You can stick an arg-checking
+;;; expression here. Here's the above example with full arg-checking:
+;;; (let ((strlen (string-length s)))
+;;; (let-optionals args ((in (current-input-port) (input-port? in))
+;;; (out (current-output-port) (output-port? out))
+;;; (nbytes strlen (and (integer? nbytes)
+;;; (< -1 nbytes strlen))))
+;;; ...))
;;;
-;;; - When evaluated, the default expressions are carried out in the *outer*
-;;; environment. That is, the DEFAULTi forms do *not* see any of the VARi
-;;; bindings.
-;;;
-;;; I originally wanted to have the DEFAULTi forms get eval'd in a LET*
-;;; style scope -- DEFAULT3 would see VAR1 and VAR2, etc. But this is
-;;; impossible to implement without side effects or redundant conditional
-;;; tests. If I drop this requirement, I can use the efficient expansion
-;;; shown below. If you need LET* scope, use the less-efficient
-;;; LET-OPTIONALS* form defined below.
+;;; The ARG-TEST expression is evaluated in the outer scope of the LET,
+;;; plus a binding for the parameter being checked.
;;;
-;;; Example:
+;;; - A SUPPLIED? variable is bound to true/false depending on whether or
+;;; not a value was passed in by the caller for this parameter.
+;;;
+;;; - If there's a final REST variable in the binding list, it is bound
+;;; to any leftover unparsed values from ARG-LIST. If there isn't a final
+;;; REST var, it is an error to have extra values left. You can use this
+;;; feature to parse a couple of arguments with LET-OPTIONALS, and handle
+;;; following args with some other mechanism. It is also useful for
+;;; procedures whose final arguments are homogeneous.
+;;;
+;;; - A clause of the form ((var1 ... varn) external-arg-parser) allows you
+;;; to parse & arg-check a group of arguments together. EXTERNAL-ARG-PARSER
+;;; is applied to the argument list. It returns n+1 values: one
+;;; for the leftover argument list, and one for each VARi.
+;;;
+;;; This facility is intended for things like substring start/end index
+;;; pairs. You can abstract out the code for parsing the pair of arguments
+;;; in a separate procedure (parse-substring-index-args args string proc)
+;;; and then a function such as READ-STRING! can simply invoke the procedure
+;;; with a
+;;; ((start end) (lambda (args) (parse-substring-index-args args s
read-string!)))
+;;; clause. That is, the external-arg parser facility is a hook
+;;; that lets you interface other arg parsers into LET-OPTIONALS.
+
+;;; Expanding the form
+;;;;;;;;;;;;;;;;;;;;;;
+;;; We expand the form into a code DAG that avoids repeatedly testing the
+;;; arg list once it runs out, but still shares code. For example,
+;;;
;;; (define (read-string! str . maybe-args)
-;;; (let-optionals maybe-args ((port (current-input-port))
-;;; (start 0)
-;;; (end (string-length str)))
+;;; (let-optionals* maybe-args ((port (current-input-port))
+;;; (start 0)
+;;; (end (string-length str)))
;;; ...))
;;;
;;; expands to:
;;;
;;; (let* ((body (lambda (port start end) ...))
-;;; (end-def (lambda (%port %start) (body %port %start <end-default>)))
-;;; (start-def (lambda (%port) (end-def %port <start-default>)))
+;;; (end-def (lambda (port start) (body port start <end-default>)))
+;;; (start-def (lambda (port) (end-def port <start-default>)))
;;; (port-def (lambda () (start-def <port-def>))))
-;;; (if (null? rest) (port-def)
-;;; (let ((%port (car rest))
-;;; (rest (cdr rest)))
-;;; (if (null? rest) (start-def %port)
-;;; (let ((%start (car rest))
-;;; (rest (cdr rest)))
-;;; (if (null? rest) (end-def %port %start)
-;;; (let ((%end (car rest))
-;;; (rest (cdr rest)))
-;;; (if (null? rest) (body %port %start %end)
-;;; (error ...)))))))))
-
+;;; (if (pair? tail)
+;;; (let ((port (car tail))
+;;; (tail (cdr tail)))
+;;; (if (pair? tail)
+;;; (let ((start (car tail))
+;;; (tail (cdr tail)))
+;;; (if (pair? tail)
+;;; (let ((end (car tail))
+;;; (tail (cdr tail)))
+;;; (if (pair? tail)
+;;; (error ...)
+;;; (body port start end)))
+;;; (end-def port start)))
+;;; (start-def port)))
+;;; (port-def)))
+;;;
+;;; Note that the defaulter code (the chain of ...-DEF procs) is just a
+;;; linear sequence of machine code into which the IF-tree branches. Once
+;;; we jump into the defaulter chain, we never test the arg list again.
+;;; A reasonable compiler can turn this into optimal parameter-parsing code.
(define-module (scsh let-opt)
+ :use-module (ice-9 receive)
:use-module (scsh alt-syntax)
:use-module (scsh module-system))
-(export-syntax let-optionals let-optionals* :optional)
-;; this shouldn't be exported, but let-optionals* needs it.
-(export-syntax really-let-optionals*)
+(export-syntax let-optionals let-optionals* :optional)
-(define-structure let-opt-expanders (export expand-let-optionals)
- (open scheme)
+(define-structure let-opt-expanders (export expand-let-optionals
+ expand-let-optionals*)
+ (open scheme
+ error-package
+ receiving)
(begin
+(define (make-gensym prefix)
+ (let ((counter 0))
+ (lambda ()
+ (set! counter (+ counter 1))
+ (string->symbol (string-append prefix (number->string counter))))))
+
;;; This guy makes the END-DEF, START-DEF, PORT-DEF definitions above.
+;;; If an elt of VARS is a list, we are dealing with a group-parser clause.
+;;; In this case, the corresponding element of DEFS is the name of
+;;; the parser.
;;; I wish I had a reasonable loop macro.
+;;;
+;;; DEFAULTER-NAMES also holds the xparser expressions
+;;; - STAR? true
+;;; LET* scope semantics -- default I & xparser I are evaluated in
+;;; a scope that sees vars 1 ... I-1.
+;;; - STAR? false
+;;; LET scope semantics -- default and xparser forms don't see any of the
+;;; vars.
+;;;
+;;; I considered documenting this procedure better, but finally decided
+;;; that if it was this hard for me to write, it should be hard for you
+;;; to read. -Olin
+
+(define (make-default-procs vars body-proc defaulter-names defs
+ sup-vars rest-var star? rename)
+ (receive (defaulters ignore-me and-me-too)
+ (really-make-default-procs vars body-proc defaulter-names defs
+ sup-vars rest-var star? rename)
+ (reverse defaulters)))
+
+(define (really-make-default-procs vars body-proc defaulter-names defs
+ sup-vars rest-var star? rename)
+ (let ((%lambda (rename 'lambda))
+ (%let (rename 'let))
+ (%ignore (rename '_))
+ (%call/values (rename 'call-with-values))
+ (tail (rename 'tail))
+ (make-rv (let ((g (make-gensym "%ov.")))
+ (lambda x (rename (g)))))
+ (make-sv (let ((g (make-gensym "%sv.")))
+ (lambda () (rename (g))))))
+
+ ;; RECUR returns 2 values: a LET*-binding list of defaulter proc
+ ;; bindings, and an expression to evaluate in their scope.
+ (let recur ((vars vars)
+ (rev-params '()) ; These guys
+ (rev-vals '()) ; have these values.
+ (sup-vars sup-vars)
+ (rev-sup-params '()) ; These guys
+ (rev-sup-vals '()) ; have these values.
+ (defaulter-names defaulter-names)
+ (defs defs))
+ ;; Note that the #F's bound to the SUPPLIED? parameters have no
+ ;; effects, and so commute with the evaluation of the defaults.
+ ;; Hence we don't need the VALS-EVALED? trick for them, just for the
+ ;; default forms & their parameters.
+ (if (pair? vars)
+ (let* ((var (car vars)) (vars (cdr vars)) ; "VAR" is really a list
+ (def (car defs)) (defs (cdr defs)) ; in xparser case...
+ (rvar (if star? var ; scope control
+ (if (pair? var) (map make-rv var) (make-rv))))
+ (rev-params1 (if (pair? rvar)
+ (append (reverse rvar) rev-params)
+ (cons rvar rev-params)))
+ (rev-vals1 (if (pair? rvar) rev-params1
+ (cons def rev-params)))
+ (sv (car sup-vars))
+ (sv (if (or star? (not sv)) sv (make-sv)))
+ (rev-sup-params1 (if sv (cons sv rev-sup-params)
+ rev-sup-params))
+ (rev-sup-vals1 (cond (sv (cons #f rev-sup-params))
+ ((pair? var) rev-sup-vals)
+ (else rev-sup-params)))
+ (defaulter (car defaulter-names))
+ (defaulter-names (cdr defaulter-names)))
+ (receive (procs exp vals-evaled?)
+ (recur vars rev-params1 rev-vals1 (cdr sup-vars)
+ rev-sup-params1 rev-sup-vals1
+ defaulter-names defs)
+ (if (pair? var)
+ ;; Return #f for VALS-EVALED? so we'll force any prior
+ ;; default to be eval'd & not pushed below this default eval.
+ (values procs
+ `(,%call/values (,%lambda () (,defaulter '()))
+ (,%lambda ,(cons %ignore rvar) ,exp))
+ #f)
+
+ (let ((params (reverse (append rev-sup-params rev-params)))
+ (exp (if vals-evaled? exp
+ `(,%let ((,rvar ,def)) ,exp))))
+ (values `((,defaulter (,%lambda ,params ,exp))
+ . ,procs)
+ `(,defaulter ,@(reverse rev-vals)
+ ,@(reverse rev-sup-vals))
+ #t)))))
+
+ (values '() `(,body-proc ,@(if rest-var '('()) '())
+ ,@(reverse rev-vals)
+ . ,(reverse rev-sup-vals))
+ #t)))))
+
+
+;;; This guy makes the (IF (PAIR? TAIL) ... (PORT-DEF)) tree above.
+;;; DEFAULTERS is a list of the names of the defaulter procs & the xparser
+;;; forms.
-(define (make-default-procs vars body-proc defaulter-names defs rename)
- (let ((%lambda (rename 'lambda)))
- (let recur ((vars (reverse vars))
- (defaulter-names (reverse defaulter-names))
- (defs (reverse defs))
- (next-guy body-proc))
- (if (null? vars) '()
- (let ((vars (cdr vars)))
- `((,(car defaulter-names)
- (,%lambda ,(reverse vars)
- (,next-guy ,@(reverse vars) ,(car defs))))
- . ,(recur vars
- (cdr defaulter-names)
- (cdr defs)
- (car defaulter-names))))))))
-
-
-;;; This guy makes the (IF (NULL? REST) (PORT-DEF) ...) tree above.
-
-(define (make-if-tree vars defaulters body-proc rest rename)
+(define (make-if-tree vars defaulters arg-tests body-proc
+ tail supvars rest-var star? rename)
(let ((%if (rename 'if))
- (%null? (rename 'null?))
+ (%pair? (rename 'pair?))
+ (%not (rename 'not))
(%error (rename 'error))
(%let (rename 'let))
+ (%lambda (rename 'lambda))
+ (%call/values (rename 'call-with-values))
(%car (rename 'car))
- (%cdr (rename 'cdr)))
+ (%cdr (rename 'cdr))
+ (make-rv (let ((g (make-gensym "%ov.")))
+ (lambda x (rename (g))))))
- (let recur ((vars vars) (defaulters defaulters) (non-defaults '()))
+ (let recur ((vars vars) (defaulters defaulters)
+ (ats arg-tests) (non-defaults '())
+ (supvars supvars) (sup-trues '()))
(if (null? vars)
- `(,%if (,%null? ,rest) (,body-proc . ,(reverse non-defaults))
- (,%error "Too many optional arguments." ,rest))
-
- (let ((v (car vars)))
- `(,%if (,%null? ,rest)
- (,(car defaulters) . ,(reverse non-defaults))
- (,%let ((,v (,%car ,rest))
- (,rest (,%cdr ,rest)))
- ,(recur (cdr vars)
- (cdr defaulters)
- (cons v non-defaults)))))))))
+ (if rest-var
+ `(,body-proc ,tail ,@(reverse non-defaults) . ,sup-trues)
+ `(,%if (,%pair? ,tail)
+ (,%error "Too many optional arguments." ,tail)
+ (,body-proc ,@(reverse non-defaults) . ,sup-trues)))
+
+ (let* ((v (car vars))
+ (rv (if star? v ; Scope control
+ (if (pair? v) (map make-rv v) (make-rv))))
+ (at (car ats))
+ (sup-trues1 (if (car supvars) (cons #t sup-trues) sup-trues))
+
+ (body `(,@(if (not (eq? at #t))
+ (let ((test (if star? at
+ `(,%let ((,v ,rv)) ,at))))
+ `((,%if (,%not ,test)
+ (,%error "Optional argument failed
test"
+ ',at ',v ,rv))))
+ '()) ; No arg test
+ ,(recur (cdr vars)
+ (cdr defaulters)
+ (cdr ats)
+ (if (pair? rv)
+ (append (reverse rv) non-defaults)
+ (cons rv non-defaults))
+ (cdr supvars) sup-trues1))))
+ (if (pair? rv)
+ `(,%call/values (,%lambda ()
+ (,(car defaulters) ,tail))
+ (,%lambda (,tail . ,rv) . ,body))
+
+ `(,%if (,%pair? ,tail)
+ (,%let ((,rv (,%car ,tail))
+ (,tail (,%cdr ,tail)))
+ . ,body)
+ (,(car defaulters) ,@(reverse non-defaults) .
,sup-trues))))))))
-(define (expand-let-optionals exp rename compare?)
+;;; Parse the clauses into
+;;; - a list of vars,
+;;; - a list of defaults,
+;;; - a list of possible arg-tests. No arg-test is represented as #T.
+;;; - a list of possible SUPPLIED? vars. An elt is either (var) or #f.
+;;; - either the rest var or #f
+;;;
+;;; This is written out in painful detail so that we can do a lot of
+;;; syntax checking.
+
+(define (parse-clauses bindings)
+ ;; LIST-LIB defines EVERY... but uses LET-OPTIONALS.
+ ;; Define here to break the dependency loop:
+ (define (every pred lis)
+ (or (not (pair? lis)) (and (pred (car lis)) (every pred (car lis)))))
+
+ (cond ((pair? bindings)
+ (let ((rev (reverse bindings)))
+ (receive (rest-var rev) (if (symbol? (car rev))
+ (values (car rev) (cdr rev))
+ (values #f rev))
+ (receive (vars defs ats supvars)
+ (let recur ((bindings (reverse rev)))
+ (if (not (pair? bindings))
+ (values '() '() '() '())
+ (receive (vars defs ats supvars) (recur (cdr bindings))
+ (let ((binding (car bindings)))
+ (if (not (and (list? binding) (<= 2 (length binding)
4)))
+ (error "Illegal binding form in LET-OPTIONAL or
LET-OPTIONAL*"
+ binding))
+
+ (let* ((var (car binding))
+ (vars (cons var vars))
+ (defs (cons (cadr binding) defs))
+ (stuff (cddr binding)))
+ (if (not (or (symbol? var)
+ (and (list? var)
+ (= 2 (length binding))
+ (every symbol? var))))
+ (error "Illegal parameter in LET-OPTIONAL or
LET-OPTIONAL* binding"
+ binding))
+ (receive (at sup-var)
+ (if (not (pair? stuff)) (values #t #f)
+ (let ((at (car stuff))
+ (stuff (cdr stuff)))
+ (if (not (pair? stuff))
+ (values at #f)
+ (let ((sv (car stuff)))
+ (if (not (symbol? sv))
+ (error "Illegal SUPPLIED?
parameter in LET-OPTIONAL or LET-OPTIONAL*"
+ binding sv))
+ (values at sv)))))
+ (values vars defs (cons at ats) (cons sup-var
supvars))))))))
+ (values vars defs ats supvars rest-var)))))
+
+ ((null? bindings) (values '() '() '() '() #f))
+ (else (error "Illegal bindings to LET-OPTIONAL or LET-OPTIONAL* form"
+ bindings))))
+
+(define (really-expand-let-optionals exp star? rename compare?)
(let* ((arg-list (cadr exp))
(var/defs (caddr exp))
(body (cdddr exp))
- (vars (map car var/defs))
-
- (prefix-sym (lambda (prefix sym)
- (string->symbol (string-append prefix (symbol->string
sym)))))
-
- ;; Private vars, one for each user var.
- ;; We prefix the % to help keep macro-expanded code from being
- ;; too confusing.
- (vars2 (map (lambda (v) (rename (prefix-sym "%" v)))
- vars))
-
- (defs (map cadr var/defs))
- (body-proc (rename 'body))
- ;; A private var, bound to the value of the ARG-LIST expression.
- (rest-var (rename '%rest))
+ (body-proc (rename 'body))
+ (tail-var (rename '%tail)) ; Bound to remaining args to be parsed.
(%let* (rename 'let*))
(%lambda (rename 'lambda))
+
+ (prefix-sym (lambda (prefix sym)
+ (string->symbol (string-append prefix (symbol->string
sym))))))
+
+ (receive (vars defs arg-tests maybe-supvars maybe-rest)
+ (parse-clauses var/defs)
+ (let* ((defaulter-names (map (lambda (var def)
+ (if (pair? var)
+ def ; xparser
+ (rename (prefix-sym "def-" var))))
+ vars defs))
+ (rsupvars (if star? maybe-supvars
+ (let ((g (make-gensym "%sv.")))
+ (map (lambda (x) (and x (rename (g))))
+ maybe-supvars))))
+ (just-supvars (let recur ((svs maybe-supvars)) ; filter
+ (if (not (pair? svs)) '()
+ (let ((sv (car svs))
+ (tail (recur (cdr svs))))
+ (if sv (cons sv tail) tail)))))
+
+ (defaulters (make-default-procs vars body-proc defaulter-names
+ defs rsupvars maybe-rest
+ star? rename))
+
+ (if-tree (make-if-tree vars defaulter-names arg-tests body-proc
+ tail-var rsupvars maybe-rest star? rename))
+
+ ;; Flatten out the multi-arg items.
+ (allvars (apply append (map (lambda (v) (if (pair? v) v
+ (list v)))
+ vars))))
+
+ `(,%let* ((,tail-var ,arg-list)
+ (,body-proc (,%lambda ,(append (if maybe-rest
+ (cons maybe-rest allvars)
+ allvars)
+ just-supvars)
+ . ,body))
+ . ,defaulters)
+ ,if-tree)))))
- (defaulter-names (map (lambda (var) (rename (prefix-sym "def-" var)))
- vars))
+(define (expand-let-optionals exp rename compare?)
+ (really-expand-let-optionals exp #f rename compare?))
+(define (expand-let-optionals* exp rename compare?)
+ (really-expand-let-optionals exp #t rename compare?))
- (defaulters (make-default-procs vars2 body-proc
- defaulter-names defs rename))
- (if-tree (make-if-tree vars2 defaulter-names body-proc
- rest-var rename)))
-
- `(,%let* ((,rest-var ,arg-list)
- (,body-proc (,%lambda ,vars . ,body))
- . ,defaulters)
- ,if-tree)))
)) ; erutcurts-enifed
;;; nilO- .noitnevnoc gnitekcarb sugob a ni deppart m'I !pleh !pleh
@@ -195,14 +470,14 @@
(for-syntax (open let-opt-expanders scheme))
(begin
-
-;;; (LET-OPTIONALS args ((var1 default1) ...) body1 ...)
-;;; The expander is defined in the code above.
-(define-syntax let-optionals expand-let-optionals)
+;;; (LET-OPTIONALS args ((var1 default1 [arg-test supplied?]) ...) body1 ...)
+;;; (LET-OPTIONALS* args ((var1 default1 [arg-test supplied?]) ...) body1 ...)
+(define-syntax let-optionals expand-let-optionals)
+(define-syntax let-optionals* expand-let-optionals*)
-;;; (:optional rest-arg default-exp)
+;;; (:optional rest-arg default-exp [test-pred])
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; This form is for evaluating optional arguments and their defaults
;;; in simple procedures that take a *single* optional argument. It is
@@ -213,61 +488,168 @@
;;; - If REST-ARG has 0 elements, evaluate DEFAULT-EXP and return that.
;;; - If REST-ARG has 1 element, return that element.
;;; - If REST-ARG has >1 element, error.
+;;;
+;;; If there is an TEST-PRED form, it is a predicate that is used to test
+;;; a non-default value. If the predicate returns false, an error is raised.
(define-syntax :optional
(syntax-rules ()
((:optional rest default-exp)
(let ((maybe-arg rest))
- (cond ((null? maybe-arg) default-exp)
- ((null? (cdr maybe-arg)) (car maybe-arg))
- (else (error "too many optional arguments" maybe-arg)))))))
-
-
-;;; (LET-OPTIONALS* args ((var1 default1) ... [rest]) body1 ...)
-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-;;; This is just like LET-OPTIONALS, except that the DEFAULTi forms
-;;; are evaluated in a LET*-style environment. That is, DEFAULT3 is evaluated
-;;; within the scope of VAR1 and VAR2, and so forth.
-;;;
-;;; - If the last form in the ((var1 default1) ...) list is not a
-;;; (VARi DEFAULTi) pair, but a simple variable REST, then it is
-;;; bound to any left-over values. For example, if we have VAR1 through
-;;; VAR7, and ARGS has 9 values, then REST will be bound to the list of
-;;; the two values of ARGS. If ARGS is too short, causing defaults to
-;;; be used, then REST is bound to '().
-;;; - If there is no REST variable, then it is an error to have excess
-;;; values in the ARGS list.
+ (if (pair? maybe-arg)
+ (if (null? (cdr maybe-arg)) (car maybe-arg)
+ (error "too many optional arguments" maybe-arg))
+ default-exp)))
+ ((:optional rest default-exp arg-test)
+ (let ((maybe-arg rest))
+ (if (pair? maybe-arg)
+ (if (null? (cdr maybe-arg))
+ (let ((val (car maybe-arg)))
+ (if (arg-test val) val
+ (error "Optional argument failed test"
+ 'arg-test val)))
+ (error "too many optional arguments" maybe-arg))
+ default-exp)))))
-;;; This just interfaces to REALLY-LET-OPTIONALS*, which expects
-;;; the ARGS form to be a variable.
+)) ; erutcurts-enifed
-(define-syntax let-optionals*
- (syntax-rules ()
- ((let-optionals* args vars&defaults body1 ...)
- (let ((rest args))
- (really-let-optionals* rest vars&defaults body1 ...)))))
+
+;;; Here is a simpler but less-efficient version of LET-OPTIONALS*.
+;;; It redundantly performs end-of-list checks for every optional var,
+;;; even after the list runs out.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(define-syntax really-let-optionals*
- (syntax-rules ()
- ;; Standard case. Do the first var/default and recurse.
- ((really-let-optionals* args ((var1 default1) etc ...)
- body1 ...)
- (call-with-values (lambda () (if (null? args)
- (values default1 '())
- (values (car args) (cdr args))))
- (lambda (var1 rest)
- (really-let-optionals* rest (etc ...)
- body1 ...))))
-
- ;; Single rest arg -- bind to the remaining rest values.
- ((really-let-optionals* args (rest) body1 ...)
- (let ((rest args)) body1 ...))
-
- ;; No more vars. Make sure there are no unaccounted-for values, and
- ;; do the body.
- ((really-let-optionals* args () body1 ...)
- (if (null? args) (begin body1 ...)
- (error "Too many optional arguments." args)))))
+; (define-structure slow-simple-let-opt (export (let-optionals* :syntax))
+; (open scheme)
+; (begin
+
+; (define-syntax let-optionals*
+; (syntax-rules ()
+; ((let-optionals* arg (opt-clause ...) body ...)
+; (let ((rest arg))
+; (let-optionals* rest (opt-clause ...) body ...)))))
+
+; ;;; The arg-list expression *must* be a variable.
+; ;;; (Or must be side-effect-free, in any event.)
+
+; (define-syntax %let-optionals*
+; (syntax-rules ()
+; ((%let-optionals* arg (((var ...) xparser) opt-clause ...) body ...)
+; (call-with-values (lambda () (xparser arg))
+; (lambda (rest var ...)
+; (%let-optionals* rest (opt-clause ...) body ...))))
+
+; ((%let-optionals* arg ((var default) opt-clause ...) body ...)
+; (call-with-values (lambda () (if (null? arg) (values default '())
+; (values (car arg) (cdr arg))))
+; (lambda (var rest)
+; (%let-optionals* rest (opt-clause ...) body ...))))
+
+; ((%let-optionals* arg ((var default test) opt-clause ...) body ...)
+; (call-with-values (lambda ()
+; (if (null? arg) (values default '())
+; (let ((var (car arg)))
+; (if test (values var (cdr arg))
+; (error "arg failed LET-OPT test" var)))))
+; (lambda (var rest)
+; (%let-optionals* rest (opt-clause ...) body ...))))
+
+; ((%let-optionals* arg ((var default test supplied?) opt-clause ...) body
...)
+; (call-with-values (lambda ()
+; (if (null? arg) (values default #f '())
+; (let ((var (car arg)))
+; (if test (values var #t (cdr arg))
+; (error "arg failed LET-OPT test" var)))))
+; (lambda (var supplied? rest)
+; (%let-optionals* rest (opt-clause ...) body ...))))
+
+; ((%let-optionals* arg (rest) body ...)
+; (let ((rest arg)) body ...))
+
+; ((%let-optionals* arg () body ...)
+; (if (null? arg) (begin body ...)
+; (error "Too many arguments in let-opt" arg)))))
+; )) ; erutcurts-enifed
+
+
+; ;;; Example derived syntax:
+; ;;; - (fn (var ...) (opt-clause ...) body ...)
+; ;;; - (defn (name var ...) (opt-clause ...) body ...)
+; ;;; - (defn name exp)
+;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; (define-structure defn-package (export (fn :syntax)
+; (defn :syntax))
+; (open let-opt scheme)
+; (begin
+
+; (define-syntax fn
+; (syntax-rules ()
+; ((fn vars () body ...) (lambda vars body ...))
+; ((fn (var ...) opts body ...)
+; (lambda (var ... . rest)
+; (let-optionals rest opts body ...)))))
+
+; (define-syntax defn
+; (syntax-rules ()
+; ((defn (name . params) opts body ...)
+; (define name (fn params opts body ...)))
+; ((defn name val) (define name val))))
+; )) ; erutcurts-enifed
+
+
+; ;;; Another example derived syntax -- Common-Lisp style fun:
+; ;;; (FUN (var ... &OPTIONAL opt-clause ... &REST rest-var) body ...)
+; ;;; (DEFUN (name var ... &OPTIONAL opt-clause ... &REST rest-var)
+; ;;; body ...)
+; ;;; (DEFUN name exp)
+;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; (define-structure defun-package (export (fun :syntax)
+; (defun :syntax))
+; (open let-opt scheme)
+; (begin
+
+; (define-syntax fun
+; (syntax-rules ()
+; ((fun args body ...) (%fun1 () () () args body ...))))
+
+; ;;; This guy basically parses the pieces of the parameter list.
+; (define-syntax %fun1
+; (syntax-rules (&optional &rest)
+
+; ((%fun1 reg opt () (&optional &rest var) body ...)
+; (%fun2 reg opt var body ...))
+
+; ((%fun1 reg opt () (&rest var) body ...)
+; (%fun2 reg opt var body ...))
+
+; ((%fun1 reg opt () (&optional) body ...)
+; (%fun2 reg opt () body ...))
+
+; ((%fun1 reg opt () () body ...)
+; (%fun2 reg opt () body ...))
+
+; ((%fun1 reg (opt ...) () (&optional opt1 opt2 ...) body ...)
+; (%fun1 reg (opt ... opt1) () (&optional opt2 ...) body ...))
+
+; ((%fun1 (var1 ...) opt () (varn varn+1 ...) body ...)
+; (%fun1 (var1 ... varn) opt () (varn+1 ...) body ...))))
+
+; ;;; This guy does the expansion into a LET-OPTIONALS*.
+; (define-syntax %fun2
+; (syntax-rules ()
+; ((%fun2 (var ...) () rest body ...)
+; (lambda (var ... . rest) body ...))
+; ((%fun2 (v1 ...) opts () body ...)
+; (lambda (v1 ... . rest) (let-opt rest opts body ...)))
+; ((%fun2 (v1 ...) (opt1 ...) rest body ...)
+; (lambda (v1 ... . %rest) (let-opt %rest (opt1 ... rest) body ...)))))
+
+; (define-syntax defun
+; (syntax-rules ()
+; ((defun (name arg ...) body ...)
+; (define name (fun (arg ...) body ...)))
-)) ; erutcurts-enifed
+; ((defun name exp) (define name exp))))
+; )) ; erutcurts-enifed
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- guile/guile-scsh ChangeLog INCOMPAT USAGE alt-s...,
Gary Houston <=