123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- ;;; Copyright (C) Joo ChurlSoo (2004). All Rights Reserved.
- ;;; Permission is hereby granted, free of charge, to any person obtaining a copy
- ;;; of this software and associated documentation files (the "Software"), to
- ;;; deal in the Software without restriction, including without limitation the
- ;;; rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- ;;; sell copies of the Software, and to permit persons to whom the Software is
- ;;; furnished to do so, subject to the following conditions:
- ;;; The above copyright notice and this permission notice shall be included in
- ;;; all copies or substantial portions of the Software.
- ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- ;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- ;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- ;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- ;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- ;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- ;;; IN THE SOFTWARE.
- (define (rest-values rest . default)
- (let* ((caller (if (or (null? default)
- (boolean? (car default))
- (integer? (car default))
- (memq (car default) (list + -)))
- '()
- (if (string? rest) rest (list rest))))
- (rest-list (if (null? caller) rest (car default)))
- (rest-length (if (list? rest-list)
- (length rest-list)
- (if (string? caller)
- (error caller rest-list 'rest-list
- '(list? rest-list))
- (apply error "bad rest list" rest-list 'rest-list
- '(list? rest-list) caller))))
- (default (if (null? caller) default (cdr default)))
- (default-list (if (null? default) default (cdr default)))
- (default-length (length default-list))
- (number
- (and (not (null? default))
- (let ((option (car default)))
- (or (and (integer? option)
- (or (and (> rest-length (abs option))
- (if (string? caller)
- (error caller rest-list 'rest-list
- `(<= (length rest-list)
- ,(abs option)))
- (apply error "too many arguments"
- rest-list 'rest-list
- `(<= (length rest-list)
- ,(abs option))
- caller)))
- (and (> default-length (abs option))
- (if (string? caller)
- (error caller default-list
- 'default-list
- `(<= (length default-list)
- ,(abs option)))
- (apply error "too many defaults"
- default-list 'default-list
- `(<= (length default-list)
- ,(abs option))
- caller)))
- option))
- (eq? option #t)
- (and (not option) 'false)
- (and (eq? option +) +)
- (and (eq? option -) -)
- (if (string? caller)
- (error caller option 'option
- '(or (boolean? option)
- (integer? option)
- (memq option (list + -))))
- (apply error "bad optional argument" option 'option
- '(or (boolean? option)
- (integer? option)
- (memq option (list + -)))
- caller)))))))
- (cond
- ((or (eq? #t number) (eq? 'false number))
- (and (not (every pair? default-list))
- (if (string? caller)
- (error caller default-list 'default-list
- '(every pair? default-list))
- (apply error "bad default list" default-list 'default-list
- '(every pair? default-list) caller)))
- (let loop ((rest-list rest-list)
- (default-list default-list)
- (result '()))
- (if (null? default-list)
- (if (null? rest-list)
- (apply values (reverse result))
- (if (eq? #t number)
- (if (string? caller)
- (error caller rest-list 'rest-list '(null? rest-list))
- (apply error "bad argument" rest-list 'rest-list
- '(null? rest-list) caller))
- (apply values (append-reverse result rest-list))))
- (if (null? rest-list)
- (apply values (append-reverse result (map car default-list)))
- (let ((default (car default-list)))
- (let lp ((rest rest-list)
- (head '()))
- (if (null? rest)
- (loop (reverse head)
- (cdr default-list)
- (cons (car default) result))
- (if (list? default)
- (if (member (car rest) default)
- (loop (append-reverse head (cdr rest))
- (cdr default-list)
- (cons (car rest) result))
- (lp (cdr rest) (cons (car rest) head)))
- (if ((cdr default) (car rest))
- (loop (append-reverse head (cdr rest))
- (cdr default-list)
- (cons (car rest) result))
- (lp (cdr rest) (cons (car rest) head)))))))))))
- ((or (and (integer? number) (> number 0))
- (eq? number +))
- (and (not (every pair? default-list))
- (if (string? caller)
- (error caller default-list 'default-list
- '(every pair? default-list))
- (apply error "bad default list" default-list 'default-list
- '(every pair? default-list) caller)))
- (let loop ((rest rest-list)
- (default default-list))
- (if (or (null? rest) (null? default))
- (apply values
- (if (> default-length rest-length)
- (append rest-list
- (map car (list-tail default-list rest-length)))
- rest-list))
- (let ((arg (car rest))
- (par (car default)))
- (if (list? par)
- (if (member arg par)
- (loop (cdr rest) (cdr default))
- (if (string? caller)
- (error caller arg 'arg `(member arg ,par))
- (apply error "unmatched argument"
- arg 'arg `(member arg ,par) caller)))
- (if ((cdr par) arg)
- (loop (cdr rest) (cdr default))
- (if (string? caller)
- (error caller arg 'arg `(,(cdr par) arg))
- (apply error "incorrect argument"
- arg 'arg `(,(cdr par) arg) caller))))))))
- (else
- (apply values (if (> default-length rest-length)
- (append rest-list (list-tail default-list rest-length))
- rest-list))))))
- (define-syntax arg-and
- (syntax-rules()
- ((arg-and arg (a1 a2 ...) ...)
- (and (or (symbol? 'arg)
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(arg-and arg (a1 a2 ...) ...)))
- (or (a1 a2 ...)
- (error "incorrect argument" arg 'arg '(a1 a2 ...)))
- ...))
- ((arg-and caller arg (a1 a2 ...) ...)
- (and (or (symbol? 'arg)
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(arg-and caller arg (a1 a2 ...) ...)))
- (or (a1 a2 ...)
- (if (string? caller)
- (error caller arg 'arg '(a1 a2 ...))
- (error "incorrect argument" arg 'arg '(a1 a2 ...) caller)))
- ...))))
- ;; accessory macro for arg-ands
- (define-syntax caller-arg-and
- (syntax-rules()
- ((caller-arg-and caller arg (a1 a2 ...) ...)
- (and (or (symbol? 'arg)
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(caller-arg-and caller arg (a1 a2 ...) ...)))
- (or (a1 a2 ...)
- (if (string? caller)
- (error caller arg 'arg '(a1 a2 ...))
- (error "incorrect argument" arg 'arg '(a1 a2 ...) caller)))
- ...))
- ((caller-arg-and null caller arg (a1 a2 ...) ...)
- (and (or (symbol? 'arg)
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(caller-arg-and caller arg (a1 a2 ...) ...)))
- (or (a1 a2 ...)
- (if (string? caller)
- (error caller arg 'arg '(a1 a2 ...))
- (error "incorrect argument" arg 'arg '(a1 a2 ...) caller)))
- ...))))
- (define-syntax arg-ands
- (syntax-rules (common)
- ((arg-ands (a1 a2 ...) ...)
- (and (arg-and a1 a2 ...) ...))
- ((arg-ands common caller (a1 a2 ...) ...)
- (and (caller-arg-and caller a1 a2 ...) ...))))
- (define-syntax arg-or
- (syntax-rules()
- ((arg-or arg (a1 a2 ...) ...)
- (or (and (not (symbol? 'arg))
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(arg-or arg (a1 a2 ...) ...)))
- (and (a1 a2 ...)
- (error "incorrect argument" arg 'arg '(a1 a2 ...)))
- ...))
- ((arg-or caller arg (a1 a2 ...) ...)
- (or (and (not (symbol? 'arg))
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(arg-or caller arg (a1 a2 ...) ...)))
- (and (a1 a2 ...)
- (if (string? caller)
- (error caller arg 'arg '(a1 a2 ...))
- (error "incorrect argument" arg 'arg '(a1 a2 ...) caller)))
- ...))))
- ;; accessory macro for arg-ors
- (define-syntax caller-arg-or
- (syntax-rules()
- ((caller-arg-or caller arg (a1 a2 ...) ...)
- (or (and (not (symbol? 'arg))
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(caller-arg-or caller arg (a1 a2 ...) ...)))
- (and (a1 a2 ...)
- (if (string? caller)
- (error caller arg 'arg '(a1 a2 ...))
- (error "incorrect argument" arg 'arg '(a1 a2 ...) caller)))
- ...))
- ((caller-arg-or null caller arg (a1 a2 ...) ...)
- (or (and (not (symbol? 'arg))
- (error "bad syntax" 'arg '(symbol? 'arg)
- '(caller-arg-or caller arg (a1 a2 ...) ...)))
- (and (a1 a2 ...)
- (if (string? caller)
- (error caller arg 'arg '(a1 a2 ...))
- (error "incorrect argument" arg 'arg '(a1 a2 ...) caller)))
- ...))))
- (define-syntax arg-ors
- (syntax-rules (common)
- ((arg-ors (a1 a2 ...) ...)
- (or (arg-or a1 a2 ...) ...))
- ((arg-ors common caller (a1 a2 ...) ...)
- (or (caller-arg-or caller a1 a2 ...) ...))))
- (define-syntax err-and
- (syntax-rules ()
- ((err-and err expression ...)
- (and (or expression
- (if (string? err)
- (error err 'expression)
- (error "false expression" 'expression err)))
- ...))))
- (define-syntax err-ands
- (syntax-rules ()
- ((err-ands (err expression ...) ...)
- (and (err-and err expression ...)
- ...))))
- (define-syntax err-or
- (syntax-rules ()
- ((err-or err expression ...)
- (or (and expression
- (if (string? err)
- (error err 'expression)
- (error "true expression" 'expression err)))
- ...))))
- (define-syntax err-ors
- (syntax-rules ()
- ((err-ors (err expression ...) ...)
- (or (err-or err expression ...)
- ...))))
|