From ed9ef46202519bca3937935f8fb8f80613bab3c9 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Thu, 2 Aug 2001 10:14:17 +0000 Subject: [PATCH 01/46] *** empty log message *** --- test-suite/ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index 90bab7d41..4c59ef578 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,7 @@ +2001-08-02 Thien-Thi Nguyen + + * tests/getopt-long.test: New file. + 2001-08-01 Thien-Thi Nguyen * lib.scm (run-test-exception): Add special handling for From 4f70d598bf3e98f9b886421a146cfd68fd2759ba Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Thu, 2 Aug 2001 10:26:52 +0000 Subject: [PATCH 02/46] Refill to fit in 80 columns. (process-long-option): Fix bug: Keep track of `optional' value-required info and use this to determine whether or not the next element is to be taken as the option arg. --- ice-9/getopt-long.scm | 366 ++++++++++++++++++++++++------------------ 1 file changed, 212 insertions(+), 154 deletions(-) diff --git a/ice-9/getopt-long.scm b/ice-9/getopt-long.scm index a5722dbf5..ab30658f6 100644 --- a/ice-9/getopt-long.scm +++ b/ice-9/getopt-long.scm @@ -1,5 +1,5 @@ ;;; Author: Russ McManus -;;; $Id: getopt-long.scm,v 1.4 2001-06-03 23:29:45 mvo Exp $ +;;; $Id: getopt-long.scm,v 1.5 2001-08-02 10:26:52 ttn Exp $ ;;; ;;; Copyright (C) 1998, 2001 Free Software Foundation, Inc. ;;; @@ -190,147 +190,147 @@ (begin (define option-spec->name (lambda - (obj) + (obj) (if (option-spec? obj) (vector-ref obj 1) (slib:error - (quote option-spec->name) - ": bad record" - obj)))) + (quote option-spec->name) + ": bad record" + obj)))) (define option-spec->value (lambda - (obj) + (obj) (if (option-spec? obj) (vector-ref obj 2) (slib:error - (quote option-spec->value) - ": bad record" - obj)))) + (quote option-spec->value) + ": bad record" + obj)))) (define option-spec->value-required? (lambda - (obj) + (obj) (if (option-spec? obj) (vector-ref obj 3) (slib:error - (quote option-spec->value-required?) - ": bad record" - obj)))) + (quote option-spec->value-required?) + ": bad record" + obj)))) (define option-spec->single-char (lambda - (obj) + (obj) (if (option-spec? obj) (vector-ref obj 4) (slib:error - (quote option-spec->single-char) - ": bad record" - obj)))) + (quote option-spec->single-char) + ": bad record" + obj)))) (define option-spec->predicate-ls (lambda - (obj) + (obj) (if (option-spec? obj) (vector-ref obj 5) (slib:error - (quote option-spec->predicate-ls) - ": bad record" - obj)))) + (quote option-spec->predicate-ls) + ": bad record" + obj)))) (define option-spec->parse-ls (lambda - (obj) + (obj) (if (option-spec? obj) (vector-ref obj 6) (slib:error - (quote option-spec->parse-ls) - ": bad record" - obj)))) + (quote option-spec->parse-ls) + ": bad record" + obj)))) (define set-option-spec-name! (lambda - (obj val) + (obj val) (if (option-spec? obj) (vector-set! obj 1 val) (slib:error - (quote set-option-spec-name!) - ": bad record" - obj)))) + (quote set-option-spec-name!) + ": bad record" + obj)))) (define set-option-spec-value! (lambda - (obj val) + (obj val) (if (option-spec? obj) (vector-set! obj 2 val) (slib:error - (quote set-option-spec-value!) - ": bad record" - obj)))) + (quote set-option-spec-value!) + ": bad record" + obj)))) (define set-option-spec-value-required?! (lambda - (obj val) + (obj val) (if (option-spec? obj) (vector-set! obj 3 val) (slib:error - (quote set-option-spec-value-required?!) - ": bad record" - obj)))) + (quote set-option-spec-value-required?!) + ": bad record" + obj)))) (define set-option-spec-single-char! (lambda - (obj val) + (obj val) (if (option-spec? obj) (vector-set! obj 4 val) (slib:error - (quote set-option-spec-single-char!) - ": bad record" - obj)))) + (quote set-option-spec-single-char!) + ": bad record" + obj)))) (define set-option-spec-predicate-ls! (lambda - (obj val) + (obj val) (if (option-spec? obj) (vector-set! obj 5 val) (slib:error - (quote set-option-spec-predicate-ls!) - ": bad record" - obj)))) + (quote set-option-spec-predicate-ls!) + ": bad record" + obj)))) (define set-option-spec-parse-ls! (lambda - (obj val) + (obj val) (if (option-spec? obj) (vector-set! obj 6 val) (slib:error - (quote set-option-spec-parse-ls!) - ": bad record" - obj)))) + (quote set-option-spec-parse-ls!) + ": bad record" + obj)))) (define option-spec? (lambda - (obj) + (obj) (and (vector? obj) (= (vector-length obj) 7) (eq? (vector-ref obj 0) (quote option-spec))))) (define make-option-spec (lambda - (option-spec->name - option-spec->value - option-spec->value-required? - option-spec->single-char - option-spec->predicate-ls - option-spec->parse-ls) + (option-spec->name + option-spec->value + option-spec->value-required? + option-spec->single-char + option-spec->predicate-ls + option-spec->parse-ls) (vector - (quote option-spec) - option-spec->name - option-spec->value - option-spec->value-required? - option-spec->single-char - option-spec->predicate-ls - option-spec->parse-ls)))) + (quote option-spec) + option-spec->name + option-spec->value + option-spec->value-required? + option-spec->single-char + option-spec->predicate-ls + option-spec->parse-ls)))) ;;; @@ -394,80 +394,102 @@ (let ((key (car ls)) (val (cadr ls))) (cond ((and (eq? key 'required?) val) - ;; required values are implemented as a predicate - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - (option-spec->single-char spec) - (cons (make-option-required-predicate) - (option-spec->predicate-ls spec)) - (cdr parse-ls)))) - ;; if the value is not required, then don't add a predicate, + ;; required values implemented as a predicate + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + (option-spec->value-required? spec) + (option-spec->single-char spec) + (cons (make-option-required-predicate) + (option-spec->predicate-ls spec)) + (cdr parse-ls)))) + ;; if value not required, don't add predicate, ((eq? key 'required?) - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - (option-spec->single-char spec) - (option-spec->predicate-ls spec) - (cdr parse-ls)))) + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + (option-spec->value-required? spec) + (option-spec->single-char spec) + (option-spec->predicate-ls spec) + (cdr parse-ls)))) ;; handle value specification ((eq? key 'value) (cond ((eq? val #t) - ;; when value is required, add a predicate to that effect - ;; and record the fact in value-required? field. - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - #t - (option-spec->single-char spec) - (cons (make-required-value-fn) - (option-spec->predicate-ls spec)) - (cdr parse-ls)))) + ;; when value is required, add a + ;; predicate to that effect and record + ;; the fact in value-required? field. + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + #t + (option-spec->single-char spec) + (cons (make-required-value-fn) + (option-spec->predicate-ls spec)) + (cdr parse-ls)))) ((eq? val #f) - ;; when the value is not allowed, add a predicate to that effect. - ;; one can detect that a value is not supplied by checking the option - ;; value against #f. - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - #f - (option-spec->single-char spec) - (cons (make-not-allowed-value-fn) - (option-spec->predicate-ls spec)) - (cdr parse-ls)))) + ;; when the value is not allowed, add a + ;; predicate to that effect. one can + ;; detect that a value is not supplied + ;; by checking the option value against + ;; #f. + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + #f + (option-spec->single-char spec) + (cons (make-not-allowed-value-fn) + (option-spec->predicate-ls spec)) + (cdr parse-ls)))) ((eq? val 'optional) - ;; for optional values, don't add a predicate. do, however - ;; put the value 'optional in the value-required? field. this - ;; setting checks whether optional values are 'greedy'. set - ;; to #f to make optional value clauses 'non-greedy'. - - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - 'optional - (option-spec->single-char spec) - (option-spec->predicate-ls spec) - (cdr parse-ls)))) + ;; for optional values, don't add a + ;; predicate. do, however put the value + ;; 'optional in the value-required? + ;; field. this setting checks whether + ;; optional values are 'greedy'. set to + ;; #f to make optional value clauses + ;; 'non-greedy'. + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + 'optional + (option-spec->single-char spec) + (option-spec->predicate-ls spec) + (cdr parse-ls)))) (#t ;; error case - (error "Bad value specification for option:" (cons key val))))) - ;; specify which single char is defined for this option. + (error "Bad value specification for option:" + (cons key val))))) + ;; specify single char defined for this option. ((eq? key 'single-char) (if (not (single-char-value? val)) - (error "Not a single-char-value:" val " for option:" key) - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - val - (option-spec->predicate-ls spec) - (cdr parse-ls))))) + (error "Not a single-char-value:" + val " for option:" key) + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + (option-spec->value-required? spec) + val + (option-spec->predicate-ls spec) + (cdr parse-ls))))) ((eq? key 'predicate) (if (procedure? val) - (parse-iter (make-option-spec (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - (option-spec->single-char spec) - (cons (make-user-predicate val) - (option-spec->predicate-ls spec)) - (cdr parse-ls))) - (error "Bad predicate specified for option:" (cons key val)))))))))))) + (parse-iter + (make-option-spec + (option-spec->name spec) + (option-spec->value spec) + (option-spec->value-required? spec) + (option-spec->single-char spec) + (cons (make-user-predicate val) + (option-spec->predicate-ls spec)) + (cdr parse-ls))) + (error "Bad predicate specified for option:" + (cons key val)))))))))))) (if (or (not (pair? desc)) (string? (car desc))) (error "Bad option specification:" desc)) @@ -514,26 +536,30 @@ is the list to not process." ((is-short-opt? (car opt-ls)) (let* ((orig-str (car opt-ls)) (match-pair (vector-ref response 2)) - (match-str (substring orig-str (car match-pair) (cdr match-pair)))) + (match-str (substring orig-str (car match-pair) + (cdr match-pair)))) (if (= (string-length match-str) 1) (iter (cdr opt-ls) (cons (string-append "-" match-str) ret-ls)) - (iter (cons (string-append "-" (substring match-str 1)) (cdr opt-ls)) - (cons (string-append "-" (substring match-str 0 1)) ret-ls))))) + (iter (cons (string-append "-" (substring match-str 1)) + (cdr opt-ls)) + (cons (string-append "-" (substring match-str 0 1)) + ret-ls))))) (#t (iter (cdr opt-ls) (cons (car opt-ls) ret-ls))))) (iter opt-ls '()))) (define (process-short-option specifications argument-ls alist) "Process a single short option that appears at the front of the ARGUMENT-LS, -according to SPECIFICATIONS. Returns #f is there is no such argument. Otherwise -returns a pair whose car is the list of remaining arguments, and whose cdr is a -new association list, constructed by adding a pair to the supplied ALIST. -The pair on the front of the returned association list describes the option -found at the head of ARGUMENT-LS. The way this routine currently works, an -option that never takes a value that is followed by a non option will cause -an error, which is probably a bug. To fix the bug the option specification -needs to record whether the option ever can take a value." +according to SPECIFICATIONS. Returns #f is there is no such argument. +Otherwise returns a pair whose car is the list of remaining arguments, and +whose cdr is a new association list, constructed by adding a pair to the +supplied ALIST. The pair on the front of the returned association list +describes the option found at the head of ARGUMENT-LS. The way this routine +currently works, an option that never takes a value that is followed by a non +option will cause an error, which is probably a bug. To fix the bug the +option specification needs to record whether the option ever can take a +value." (define (short-option->char option) (string-ref option 1)) (define (is-short-option? option) @@ -543,29 +569,36 @@ needs to record whether the option ever can take a value." (regexp-exec long-opt-no-value-rx option))) (define (find-matching-spec option) (let ((key (short-option->char option))) - (find-if (lambda (spec) (eq? key (option-spec->single-char spec))) specifications))) + (find-if (lambda (spec) + (eq? key (option-spec->single-char spec))) specifications))) (let ((option (car argument-ls))) (if (is-short-option? option) (let ((spec (find-matching-spec option))) (if spec - (let* ((next-value (if (null? (cdr argument-ls)) #f (cadr argument-ls))) + (let* ((next-value (if (null? (cdr argument-ls)) + #f + (cadr argument-ls))) (option-value (if (and next-value (not (is-short-option? next-value)) (not (is-long-option? next-value)) (option-spec->value-required? spec)) next-value #t)) - (new-alist (cons (cons (option-spec->name spec) option-value) alist))) + (new-alist (cons (cons (option-spec->name spec) + option-value) + alist))) (cons (if (eq? option-value #t) - (cdr argument-ls) ; there was one value specified, skip just one - (cddr argument-ls)) ; there must have been a value specified, skip two + (cdr argument-ls) ; one value, skip just one + (cddr argument-ls)) ; must be a value, skip two new-alist)) (error "No such option:" option))) #f))) (define (process-long-option specifications argument-ls alist) (define (find-matching-spec key) - (find-if (lambda (spec) (eq? key (option-spec->name spec))) specifications)) + (find-if (lambda (spec) + (eq? key (option-spec->name spec))) + specifications)) (define (split-long-option option) ;; returns a pair whose car is a symbol naming the option, cdr is ;; the option value. as a special case, if the option value is @@ -577,27 +610,50 @@ needs to record whether the option ever can take a value." ;; Maybe we need to grab a value from argument-ls. To find ;; out we need to refer to the option-spec. (let* ((key-pair (vector-ref resp 2)) - (key (string->symbol (substring option (car key-pair) (cdr key-pair)))) + (key (string->symbol + (substring option (car key-pair) (cdr key-pair)))) (spec (find-matching-spec key))) - (cons key (if (option-spec->value-required? spec) #f #t))) + (let* ((req (option-spec->value-required? spec)) + (retval (cons key (if req #f #t)))) + ;; this is a fucking kludge, i hate it. it's necessary because + ;; the protocol (return #f to indicate next element is an option + ;; arg) is insufficient. needs redesign. why am i checking in + ;; such ugliness? read moby dick! -ttn + (and (eq? 'optional req) + (set-object-property! retval 'optional #t)) + retval)) (let ((resp (regexp-exec long-opt-with-value-rx option))) ;; Aha, we've found a long option with an equal sign. The ;; option value is simply the value to the right of the ;; equal sign. (if resp (let* ((key-pair (vector-ref resp 2)) - (key (string->symbol (substring option (car key-pair) (cdr key-pair)))) + (key (string->symbol + (substring option + (car key-pair) (cdr key-pair)))) (value-pair (vector-ref resp 3)) - (value (substring option (car value-pair) (cdr value-pair)))) + (value (substring option + (car value-pair) (cdr value-pair)))) (cons key value)) - #f))))) + #f))))) (let* ((option (car argument-ls)) (pair (split-long-option option))) (cond ((and pair (eq? (cdr pair) #f)) - (if (null? (cdr argument-ls)) - (error "Not enough options.") - (cons (cddr argument-ls) - (cons (cons (car pair) (cadr argument-ls)) alist)))) + (cond ((and (null? (cdr argument-ls)) + (not (object-property pair 'optional))) + (error "Not enough options.")) + ((null? (cdr argument-ls)) + (cons '() (cons (cons (car pair) #t) alist))) + ((let* ((next (cadr argument-ls)) + (m (or (regexp-exec short-opt-rx next) + (regexp-exec long-opt-with-value-rx next) + (regexp-exec long-opt-no-value-rx next)))) + (and m (object-property pair 'optional))) + (cons (cdr argument-ls) + (cons (cons (car pair) #t) alist))) + (else + (cons (cddr argument-ls) + (cons (cons (car pair) (cadr argument-ls)) alist))))) (pair (cons (cdr argument-ls) (cons pair alist))) (else #f)))) @@ -611,7 +667,8 @@ needs to record whether the option ever can take a value." (let ((argument-ls (car pair)) (alist (cdr pair))) (iter argument-ls alist rest-ls)) - (let ((pair (process-long-option specifications argument-ls alist))) + (let ((pair (process-long-option + specifications argument-ls alist))) (if pair (let ((argument-ls (car pair)) (alist (cdr pair))) @@ -659,11 +716,12 @@ to add a 'single-char' clause to the option description." (let* ((opt-pair (process-options specifications split-ls)) (alist (car opt-pair)) (rest-ls (append (cdr opt-pair) non-split-ls))) - ;; loop through the returned alist, and set the values into the specifications + ;; loop through returned alist, set values into specifications (for-each (lambda (pair) (let* ((key (car pair)) (val (cdr pair)) - (spec (find-if (lambda (spec) (eq? key (option-spec->name spec))) + (spec (find-if (lambda (spec) + (eq? key (option-spec->name spec))) specifications))) (if spec (set-option-spec-value! spec val)))) alist) From 8940c16b17df0dd2cdbec8b7a40d751dbb87d76b Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Thu, 2 Aug 2001 10:29:32 +0000 Subject: [PATCH 03/46] *** empty log message *** --- ice-9/ChangeLog | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ice-9/ChangeLog b/ice-9/ChangeLog index 93d053506..844f1a825 100644 --- a/ice-9/ChangeLog +++ b/ice-9/ChangeLog @@ -1,3 +1,11 @@ +2001-08-02 Thien-Thi Nguyen + + * getopt-long.scm: Refill to fit in 80 columns. + + (process-long-option): Fix bug: Keep track of `optional' + value-required info and use this to determine whether or not the + next element is to be taken as the option arg. + 2001-07-31 Keisuke Nishida * boot-9.scm (process-define-module): Fixed a bug that did not @@ -67,7 +75,7 @@ Changes to support tracing other than inside the repl-stack that is set up by the REPL code in boot-9.scm. - + * debug.scm (trace-entry, trace-exit): Conditionalize tracing on whether the current stack id is in `traced-stack-ids'. (traced-stack-ids, trace-all-stacks?, trace-stack, untrace-stack): @@ -82,7 +90,7 @@ * debug.scm (trace): Set evaluator trap options to handle tracing. Don't reset trace-level to 0. - + * boot-9.scm (lazy-handler-dispatch): Remove enter-frame-handler, apply-frame-handler and exit-frame-handler. (They're replaced by evaluator trap options.) From 8c84b81ecade2e364e725506b0ef91ff5dc4c8c1 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Thu, 2 Aug 2001 10:48:12 +0000 Subject: [PATCH 04/46] *** empty log message *** --- AUTHORS | 6 ++++-- NEWS | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index c1dd0b3ed..2eeba2c1b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -220,7 +220,7 @@ In the top-level directory, wrote: In the subdirectory ice-9, changes to: boot-9.scm documentation.scm emacs.scm ls.scm session.scm string-fun.scm - threads.scm + threads.scm getopt-long.scm In the subdirectory scripts, wrote: Makefile.am PROGRAM display-commentary generate-autoload @@ -236,8 +236,10 @@ In the subdirectory doc, changes to: scheme-scheduling.texi In the subdirectory test-suite, changes to: guile-test lib.scm +In the subdirectory test-suite/tests, wrote: + exceptions.test getopt-long.test In the subdirectory test-suite/tests, changes to: - exceptions.test eval.test + eval.test Robert Merkel: In the subdirectory doc, co-wrote: diff --git a/NEWS b/NEWS index ea966c86d..eadbbf48d 100644 --- a/NEWS +++ b/NEWS @@ -6,7 +6,7 @@ Please send Guile bug reports to bug-guile@gnu.org. Changes since the stable branch: -** Variables have no longer a special behavior for `equal?'. +** Variables have no longer a special behavior for `equal?'. Previously, comparing two variables with `equal?' would recursivly compare their values. This is no longer done. Variables are now only @@ -681,6 +681,14 @@ Use module system operations for all variables. That is, a call to `throw', `error', etc is now guaranteed to not return. +** Bugfix for (ice-9 getopt-long) + +Parsing for options that are specified to have `optional' args now checks if +the next element is an option instead of unconditionally taking it as the +option arg. + +Also, this module is now tested using test-suite/tests/getopt-long.test. + * Changes to the C interface ** Types have been renamed from scm_*_t to scm_t_*. From ee0346032640284cba26f596dd90d09bf1562a13 Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Thu, 2 Aug 2001 19:45:07 +0000 Subject: [PATCH 05/46] * Added `call-with-readline-completion-function'. --- guile-readline/ChangeLog | 4 ++++ guile-readline/readline.scm | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/guile-readline/ChangeLog b/guile-readline/ChangeLog index e431af5bf..aba59dcb3 100644 --- a/guile-readline/ChangeLog +++ b/guile-readline/ChangeLog @@ -1,3 +1,7 @@ +2001-08-02 Neil Jerram + + * readline.scm (call-with-readline-completion-function): New. + 2001-07-18 Martin Grabmueller * Makefile.am, readline.scm: Updated copyright notice. diff --git a/guile-readline/readline.scm b/guile-readline/readline.scm index 24f9de58f..99e63bce0 100644 --- a/guile-readline/readline.scm +++ b/guile-readline/readline.scm @@ -187,6 +187,16 @@ (set! *readline-completion-function* apropos-completion-function) )) +(define-public (call-with-readline-completion-function completer thunk) + "With @var{completer} as readline completion function, call @var{thunk}." + (let ((old-completer *readline-completion-function*)) + (dynamic-wind + (lambda () + (set! *readline-completion-function* completer)) + thunk + (lambda () + (set! *readline-completion-function* old-completer))))) + (define-public (activate-readline) (if (and (isatty? (current-input-port)) (not (and (module-defined? the-root-module 'use-emacs-interface) From d3b924ba3bd0bf4958c1893e8f4ff66216b5f2fe Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Thu, 2 Aug 2001 19:52:09 +0000 Subject: [PATCH 06/46] * Fix obscure debugger bug - trying to rerun last command when last command fluid is not yet set. --- ice-9/ChangeLog | 5 +++++ ice-9/debugger.scm | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ice-9/ChangeLog b/ice-9/ChangeLog index 844f1a825..62ba0a291 100644 --- a/ice-9/ChangeLog +++ b/ice-9/ChangeLog @@ -1,3 +1,8 @@ +2001-08-02 Neil Jerram + + * debugger.scm (run-last-command): Return current state if + last-command fluid is not yet set. + 2001-08-02 Thien-Thi Nguyen * getopt-long.scm: Refill to fit in 80 columns. diff --git a/ice-9/debugger.scm b/ice-9/debugger.scm index 3bf29ab75..f98509c2c 100644 --- a/ice-9/debugger.scm +++ b/ice-9/debugger.scm @@ -114,7 +114,8 @@ (define (run-last-command state) (let ((procedure (fluid-ref last-command))) (if procedure - (procedure state)))) + (procedure state) + state))) (define (catch-user-errors port thunk) (catch 'debugger-user-error From baffb19f273aaa2fe71f6dcd6f8ca9e1c23eab91 Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Thu, 2 Aug 2001 20:26:21 +0000 Subject: [PATCH 07/46] * Explain cutting args for `make-stack'. --- libguile/ChangeLog | 5 +++++ libguile/stacks.c | 23 ++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/libguile/ChangeLog b/libguile/ChangeLog index 8570e57db..b0a1460e4 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,8 @@ +2001-08-02 Neil Jerram + + * stacks.c (scm_make_stack): Improve docstring by explaining use + of cutting args. + 2001-08-01 Marius Vollmer * chars.c (scm_char_alphabetic_p, scm_char_numeric_p, diff --git a/libguile/stacks.c b/libguile/stacks.c index c49924a38..c00b47bf5 100644 --- a/libguile/stacks.c +++ b/libguile/stacks.c @@ -420,9 +420,26 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1, "Create a new stack. If @var{obj} is @code{#t}, the current\n" "evaluation stack is used for creating the stack frames,\n" "otherwise the frames are taken from @var{obj} (which must be\n" - "either a debug object or a continuation).\n" - "@var{args} must be a list of integers and specifies how the\n" - "resulting stack will be narrowed.") + "either a debug object or a continuation).\n\n" + "@var{args} should be a list containing any combination of\n" + "integer, procedure and @code{#t} values.\n\n" + "These values specify various ways of cutting away uninteresting\n" + "stack frames from the top and bottom of the stack that\n" + "@code{make-stack} returns. They come in pairs like this:\n" + "@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n" + "@var{outer_cut_2} @dots{})}.\n\n" + "Each @var{inner_cut_N} can be @code{#t}, an integer, or a\n" + "procedure. @code{#t} means to cut away all frames up to but\n" + "excluding the first user module frame. An integer means to cut\n" + "away exactly that number of frames. A procedure means to cut\n" + "away all frames up to but excluding the application frame whose\n" + "procedure matches the specified one.\n\n" + "Each @var{outer_cut_N} can be an integer or a procedure. An\n" + "integer means to cut away that number of frames. A procedure\n" + "means to cut away frames down to but excluding the application\n" + "frame whose procedure matches the specified one.\n\n" + "If the @var{outer_cut_N} of the last pair is missing, it is\n" + "taken as 0.") #define FUNC_NAME s_scm_make_stack { long n, size; From 3524efbcd9f45174a4fec6a1802697531f63cc97 Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Thu, 2 Aug 2001 20:27:42 +0000 Subject: [PATCH 08/46] * Improve `make-stack' doc by explaining cutting args. --- doc/ChangeLog | 5 ++ doc/scheme-debug.texi | 165 ------------------------------------------ 2 files changed, 5 insertions(+), 165 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 4f5660483..3d6210db9 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,8 @@ +2001-08-02 Neil Jerram + + * scheme-debug.texi (Debugging): Improve `make-stack' doc by + explaining cutting args. + 2001-07-19 Rob Browning * posix.texi (Signals): add docs for setitimer and getitimer. diff --git a/doc/scheme-debug.texi b/doc/scheme-debug.texi index cbb35cb17..e69de29bb 100644 --- a/doc/scheme-debug.texi +++ b/doc/scheme-debug.texi @@ -1,165 +0,0 @@ -@page -@node Debugging -@chapter Internal Debugging Interface - ---- The name of this chapter needs to clearly distinguish it - from the appendix describing the debugger UI. The intro - should have a pointer to the UI appendix. - -@deffn primitive display-error stack port subr message args rest -Display an error message to the output port @var{port}. -@var{stack} is the saved stack for the error, @var{subr} is -the name of the procedure in which the error occured and -@var{message} is the actual error message, which may contain -formatting instructions. These will format the arguments in -the list @var{args} accordingly. @var{rest} is currently -ignored. -@end deffn - -@deffn primitive display-application frame [port [indent]] -Display a procedure application @var{frame} to the output port -@var{port}. @var{indent} specifies the indentation of the -output. -@end deffn - -@deffn primitive display-backtrace stack port [first [depth]] -Display a backtrace to the output port @var{port}. @var{stack} -is the stack to take the backtrace from, @var{first} specifies -where in the stack to start and @var{depth} how much frames -to display. Both @var{first} and @var{depth} can be @code{#f}, -which means that default values will be used. -@end deffn - -@deffn primitive backtrace -Display a backtrace of the stack saved by the last error -to the current output port. -@end deffn - -@deffn primitive malloc-stats -Return an alist ((@var{what} . @var{n}) ...) describing number -of malloced objects. -@var{what} is the second argument to @code{scm_must_malloc}, -@var{n} is the number of objects of that type currently -allocated. -@end deffn - -@deffn primitive debug-options-interface [setting] -Option interface for the debug options. Instead of using -this procedure directly, use the procedures @code{debug-enable}, -@code{debug-disable}, @code{debug-set!} and @var{debug-options}. -@end deffn - -@deffn primitive with-traps thunk -Call @var{thunk} with traps enabled. -@end deffn - -@deffn primitive memoized? obj -Return @code{#t} if @var{obj} is memoized. -@end deffn - -@deffn primitive unmemoize m -Unmemoize the memoized expression @var{m}, -@end deffn - -@deffn primitive memoized-environment m -Return the environment of the memoized expression @var{m}. -@end deffn - -@deffn primitive procedure-name proc -Return the name of the procedure @var{proc} -@end deffn - -@deffn primitive procedure-source proc -Return the source of the procedure @var{proc}. -@end deffn - -@deffn primitive procedure-environment proc -Return the environment of the procedure @var{proc}. -@end deffn - -@deffn primitive debug-object? obj -Return @code{#t} if @var{obj} is a debug object. -@end deffn - -@deffn primitive frame-arguments frame -Return the arguments of @var{frame}. -@end deffn - -@deffn primitive frame-evaluating-args? frame -Return @code{#t} if @var{frame} contains evaluated arguments. -@end deffn - -@deffn primitive frame-next frame -Return the next frame of @var{frame}, or @code{#f} if -@var{frame} is the last frame in its stack. -@end deffn - -@deffn primitive frame-number frame -Return the frame number of @var{frame}. -@end deffn - -@deffn primitive frame-overflow? frame -Return @code{#t} if @var{frame} is an overflow frame. -@end deffn - -@deffn primitive frame-previous frame -Return the previous frame of @var{frame}, or @code{#f} if -@var{frame} is the first frame in its stack. -@end deffn - -@deffn primitive frame-procedure frame -Return the procedure for @var{frame}, or @code{#f} if no -procedure is associated with @var{frame}. -@end deffn - -@deffn primitive frame-procedure? frame -Return @code{#t} if a procedure is associated with @var{frame}. -@end deffn - -@deffn primitive frame-real? frame -Return @code{#t} if @var{frame} is a real frame. -@end deffn - -@deffn primitive frame-source frame -Return the source of @var{frame}. -@end deffn - -@deffn primitive frame? obj -Return @code{#t} if @var{obj} is a stack frame. -@end deffn - -@deffn primitive last-stack-frame obj -Return a stack which consists of a single frame, which is the -last stack frame for @var{obj}. @var{obj} must be either a -debug object or a continuation. -@end deffn - -@deffn primitive make-stack obj . args -Create a new stack. If @var{obj} is @code{#t}, the current -evaluation stack is used for creating the stack frames, -otherwise the frames are taken from @var{obj} (which must be -either a debug object or a continuation). -@var{args} must be a list of integers and specifies how the -resulting stack will be narrowed. -@end deffn - -@deffn primitive stack-id stack -Return the identifier given to @var{stack} by @code{start-stack}. -@end deffn - -@deffn primitive stack-length stack -Return the length of @var{stack}. -@end deffn - -@deffn primitive stack-ref stack i -Return the @var{i}'th frame from @var{stack}. -@end deffn - -@deffn primitive stack? obj -Return @code{#t} if @var{obj} is a calling stack. -@end deffn - - -@c Local Variables: -@c TeX-master: "guile.texi" -@c End: From 848458d99068f7542b5f63d52eb2338595a5fb1e Mon Sep 17 00:00:00 2001 From: Gary Houston Date: Sat, 4 Aug 2001 18:37:08 +0000 Subject: [PATCH 09/46] * srfi-1.scm (filter): replaced with a tail-recursive version. (remove): implement using filter, to make it tail-recursive. --- srfi/ChangeLog | 5 +++++ srfi/srfi-1.scm | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/srfi/ChangeLog b/srfi/ChangeLog index 109ff9940..d4b650181 100644 --- a/srfi/ChangeLog +++ b/srfi/ChangeLog @@ -1,3 +1,8 @@ +2001-08-04 Gary Houston + + * srfi-1.scm (filter): replaced with a tail-recursive version. + (remove): implement using filter, to make it tail-recursive. + 2001-07-31 Gary Houston * srfi-14.c (scm_char_set_diff_plus_intersection): wasn't correctly diff --git a/srfi/srfi-1.scm b/srfi/srfi-1.scm index 4c361a57e..cd2ca757d 100644 --- a/srfi/srfi-1.scm +++ b/srfi/srfi-1.scm @@ -720,11 +720,15 @@ ;;; Filtering & partitioning (define (filter pred list) - (if (null? list) - '() - (if (pred (car list)) - (cons (car list) (filter pred (cdr list))) - (filter pred (cdr list))))) + (letrec ((filiter (lambda (pred rest result) + (if (null? rest) + (reverse! result) + (filiter pred (cdr rest) + (cond ((pred (car rest)) + (cons (car rest) result)) + (else + result))))))) + (filiter pred list '()))) (define (partition pred list) (if (null? list) @@ -736,11 +740,7 @@ (values in (cons (car list) out)))))) (define (remove pred list) - (if (null? list) - '() - (if (pred (car list)) - (remove pred (cdr list)) - (cons (car list) (remove pred (cdr list)))))) + (filter (lambda (x) (not (pred x))) list)) (define (filter! pred list) (filter pred list)) ; XXX:optimize From 5753f02f67d31e87bceba2b1f559c20e6e21b015 Mon Sep 17 00:00:00 2001 From: Gary Houston Date: Sun, 5 Aug 2001 10:12:37 +0000 Subject: [PATCH 10/46] * srfi-1.scm (check-arg-type, non-negative-integer?): a couple of new internal definitions. (list-tabulate, iota): check for bad arguments that otherwise give weird output. (filter): check for proper list, to avoid infinite recursion on a circular list. --- srfi/ChangeLog | 9 +++++++++ srfi/srfi-1.scm | 13 +++++++++++++ 2 files changed, 22 insertions(+) diff --git a/srfi/ChangeLog b/srfi/ChangeLog index d4b650181..d2e94bbe5 100644 --- a/srfi/ChangeLog +++ b/srfi/ChangeLog @@ -1,3 +1,12 @@ +2001-08-05 Gary Houston + + * srfi-1.scm (check-arg-type, non-negative-integer?): a couple of new + internal definitions. + (list-tabulate, iota): check for bad arguments that otherwise + give weird output. + (filter): check for proper list, to avoid infinite recursion on + a circular list. + 2001-08-04 Gary Houston * srfi-1.scm (filter): replaced with a tail-recursive version. diff --git a/srfi/srfi-1.scm b/srfi/srfi-1.scm index cd2ca757d..f58c1ebfe 100644 --- a/srfi/srfi-1.scm +++ b/srfi/srfi-1.scm @@ -254,7 +254,18 @@ (define (xcons d a) (cons a d)) +;; internal helper, similar to (scsh utilities) check-arg. +(define (check-arg-type pred arg caller) + (if (pred arg) + arg + (scm-error 'wrong-type-arg caller + "Wrong type argument: ~S" (list arg) '()))) + +;; the srfi spec doesn't seem to forbid inexact integers. +(define (non-negative-integer? x) (and (integer? x) (>= x 0))) + (define (list-tabulate n init-proc) + (check-arg-type non-negative-integer? n "list-tabulate") (let lp ((n n) (acc '())) (if (<= n 0) acc @@ -272,6 +283,7 @@ (lp (cdr r) (cdr p))))))) (define (iota count . rest) + (check-arg-type non-negative-integer? count "iota") (let ((start (if (pair? rest) (car rest) 0)) (step (if (and (pair? rest) (pair? (cdr rest))) (cadr rest) 1))) (let lp ((n 0) (acc '())) @@ -720,6 +732,7 @@ ;;; Filtering & partitioning (define (filter pred list) + (check-arg-type list? list "caller") ; reject circular lists. (letrec ((filiter (lambda (pred rest result) (if (null? rest) (reverse! result) From fd7ec88302a3307b5d83ca16ff30fdbbc6409bfa Mon Sep 17 00:00:00 2001 From: Michael Livshin Date: Mon, 6 Aug 2001 23:19:05 +0000 Subject: [PATCH 11/46] * snarf-check-and-output-texi: print optional args in a prettier manner. --- scripts/ChangeLog | 5 +++++ scripts/snarf-check-and-output-texi | 35 ++++++++++++++--------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/scripts/ChangeLog b/scripts/ChangeLog index 0a8dab25a..b4eced90c 100644 --- a/scripts/ChangeLog +++ b/scripts/ChangeLog @@ -1,3 +1,8 @@ +2001-08-07 Michael Livshin + + * snarf-check-and-output-texi: print optional args in a prettier + manner. + 2001-08-01 Thien-Thi Nguyen * PROGRAM, README, display-commentary, doc-snarf, diff --git a/scripts/snarf-check-and-output-texi b/scripts/snarf-check-and-output-texi index bc1287b38..a300ca78e 100755 --- a/scripts/snarf-check-and-output-texi +++ b/scripts/snarf-check-and-output-texi @@ -152,26 +152,25 @@ exec ${GUILE-guile} -l $0 -c "(apply $main (cdr (command-line)))" "$@" (with-output-to-string (lambda () (format #t "~A" *function-name*) - (let loop-req ((r 0)) + (let loop-req ((args *args*) (r 0)) (if (< r req) (begin - (format #t " ~A" (list-ref *args* r)) - (loop-req (+ 1 r))) - (begin - (if (> opt 0) - (format #t "~A[" (if (> req 0) " " ""))) - (let loop-opt ((o 0) (space #f)) - (if (< o opt) - (begin - (format #t "~A~A" (if space " " "") - (list-ref *args* (+ r o))) - (loop-opt (+ 1 o) #t)) - (begin - (if (> opt 0) - (format #t "]")) - (if (> var 0) - (format #t " . ~A" - (car (last-pair *args*))))))))))))))) + (format #t " ~A" (car args)) + (loop-req (cdr args) (+ 1 r))) + (let loop-opt ((o 0) (args args) (tail '())) + (if (< o opt) + (begin + (format #t " [~A" (car args)) + (loop-opt (+ 1 o) (cdr args) (cons #\] tail))) + (begin + (if (> var 0) + (format #t " . ~A" + (car args))) + (let loop-tail ((tail tail)) + (if (not (null? tail)) + (begin + (format #t "~A" (car tail)) + (loop-tail (cdr tail))))))))))))))) (format #t "\n ~A\n" *function-name*) (format #t "@c snarfed from ~A:~A\n" *file* *line*) (format #t "@deffn primitive ~A\n" nice-sig) From 8b1d12c79a19778c0c1bbc15ea074f62a9e6843e Mon Sep 17 00:00:00 2001 From: Michael Livshin Date: Mon, 6 Aug 2001 23:19:50 +0000 Subject: [PATCH 12/46] * guile-snarf-docs-texi.in: don't call the tokenizer here, we now do it from the Makefile. * Makefile.am: rearrange the snarfing slightly, so that .doc files are of a reasonable size. --- libguile/ChangeLog | 8 ++++++++ libguile/Makefile.am | 10 +++++----- libguile/guile-snarf-docs-texi.in | 2 +- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/libguile/ChangeLog b/libguile/ChangeLog index b0a1460e4..be1fbc87a 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,11 @@ +2001-08-07 Michael Livshin + + * guile-snarf-docs-texi.in: don't call the tokenizer here, we now + do it from the Makefile. + + * Makefile.am: rearrange the snarfing slightly, so that .doc files + are of a reasonable size. + 2001-08-02 Neil Jerram * stacks.c (scm_make_stack): Improve docstring by explaining use diff --git a/libguile/Makefile.am b/libguile/Makefile.am index c16bf2f2f..c8c7b8960 100644 --- a/libguile/Makefile.am +++ b/libguile/Makefile.am @@ -192,19 +192,19 @@ SUFFIXES = .x .doc || { rm $@; false; } .c.doc: -(test -n "${AWK+set}" || AWK="@AWK@"; ${AWK} -f ./guile-func-name-check $<) - ./guile-snarf-docs $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $< > $@ \ - || { rm $@; false; } + (./guile-snarf-docs $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS) $< | \ + ./guile_filter_doc_snarfage --filter-snarfage) > $@ || { rm $@; false; } $(DOT_X_FILES) $(EXTRA_DOT_DOC_FILES): snarf.h guile-snarf.in -$(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES): snarf.h guile-snarf-docs.in +$(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES): snarf.h guile-snarf-docs.in guile_filter_doc_snarfage error.x: cpp_err_symbols.c posix.x: cpp_sig_symbols.c load.x: libpath.h -guile.texi: $(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES) guile-snarf-docs-texi.in guile guile_filter_doc_snarfage - ./guile-snarf-docs-texi $(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES) > $@ \ +guile.texi: $(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES) guile-snarf-docs-texi.in guile + cat $(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES) | ./guile-snarf-docs-texi > $@ \ || { rm $@; false; } guile-procedures.txt: guile.texi diff --git a/libguile/guile-snarf-docs-texi.in b/libguile/guile-snarf-docs-texi.in index 0aa9f9cff..6481534b2 100755 --- a/libguile/guile-snarf-docs-texi.in +++ b/libguile/guile-snarf-docs-texi.in @@ -34,4 +34,4 @@ if [ `basename ${bindir}` = libguile ]; then GUILE_LOAD_PATH=${srcdir}/..; export GUILE_LOAD_PATH fi -cat "$@" | ${bindir}/guile_filter_doc_snarfage --filter-snarfage | ${bindir}/guile -c "${apply_main}" +${bindir}/guile -c "${apply_main}" From 720e1c3045f4bb78bfb5564beb2200805135e3d9 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Tue, 7 Aug 2001 14:39:02 +0000 Subject: [PATCH 13/46] *** empty log message *** --- NEWS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/NEWS b/NEWS index eadbbf48d..bba3769b5 100644 --- a/NEWS +++ b/NEWS @@ -256,6 +256,14 @@ default. * Changes to Scheme functions and syntax +** Character classifiers work for non-ASCII characters. + +The predicates `char-alphabetic?', `char-numeric?', +`char-whitespace?', `char-lower?', `char-upper?' and `char-is-both?' +no longer check whether their arguments are ASCII characters. +Previously, a character would only be considered alphabetic when it +was also ASCII, for example. + ** Previously deprecated Scheme functions have been removed: tag - no replacement. From 41973b48bb529e2c512b971ef167805def9be3cd Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Tue, 7 Aug 2001 18:14:56 +0000 Subject: [PATCH 14/46] (EXTRA_DIST): Distribute ChangeLog-1996-1999 and ChangeLog-2000. Thanks to Daniel Skarda! --- libguile/Makefile.am | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libguile/Makefile.am b/libguile/Makefile.am index c8c7b8960..a97db45db 100644 --- a/libguile/Makefile.am +++ b/libguile/Makefile.am @@ -144,8 +144,9 @@ modinclude_DATA = scmconfig.h bin_SCRIPTS = guile-snarf guile-doc-snarf guile-snarf-docs \ guile-snarf-docs-texi guile-func-name-check -EXTRA_DIST = ChangeLog-gh ChangeLog-scm ChangeLog-threads cpp_signal.c \ - cpp_errno.c cpp_err_symbols.in cpp_sig_symbols.in cpp_cnvt.awk \ +EXTRA_DIST = ChangeLog-gh ChangeLog-scm ChangeLog-threads \ + ChangeLog-1996-1999 ChangeLog-2000 cpp_signal.c \ + cpp_errno.c cpp_err_symbols.in cpp_sig_symbols.in cpp_cnvt.awk \ c-tokenize.lex # $(DOT_DOC_FILES) $(EXTRA_DOT_DOC_FILES) \ # guile-procedures.txt guile.texi From bc79995a9a18b35c656d41b3ecb5c10f778f6cdc Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Tue, 7 Aug 2001 18:17:14 +0000 Subject: [PATCH 15/46] Added "test-suite/Makefile". --- configure.in | 1 + 1 file changed, 1 insertion(+) diff --git a/configure.in b/configure.in index 532f0ccfc..6bb4ef87c 100644 --- a/configure.in +++ b/configure.in @@ -641,6 +641,7 @@ AC_CONFIG_FILES([ examples/box-dynamic-module/Makefile examples/modules/Makefile examples/safe/Makefile + test-suite/Makefile check-guile guile-tools]) From c4361fe59466e860bc9b1bd621e55623f29574cb Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Tue, 7 Aug 2001 18:17:27 +0000 Subject: [PATCH 16/46] (EXTRA_DIST, SUBDIRS): Move test-suite from EXTRA_DIST to SUBDIRS. --- Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.am b/Makefile.am index a4824d826..e37a678a4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,7 +21,7 @@ SUBDIRS = oop qt libltdl libguile ice-9 guile-config guile-readline \ - scripts srfi doc examples + scripts srfi doc examples test-suite bin_SCRIPTS = guile-tools @@ -30,7 +30,7 @@ include_HEADERS = libguile.h # automake sometimes forgets to distribute acconfig.h, # apparently depending on the phase of the moon. EXTRA_DIST = qthreads.m4 HACKING GUILE-VERSION ANON-CVS SNAPSHOTS TODO \ - test-suite $(ACLOCAL) acconfig.h + $(ACLOCAL) acconfig.h TESTS = check-guile From 067dd9c61c23cff69c10c65e0565645f66b2da40 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Tue, 7 Aug 2001 18:18:40 +0000 Subject: [PATCH 17/46] New file, to control distribution of the test-suite. --- test-suite/Makefile.am | 1 + 1 file changed, 1 insertion(+) create mode 100644 test-suite/Makefile.am diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am new file mode 100644 index 000000000..c2aaa7f57 --- /dev/null +++ b/test-suite/Makefile.am @@ -0,0 +1 @@ +EXTRA_DIST = guile-test lib.scm tests/*.test tests/asmobs tests/c-api From b754e3d1ecdb7db4db7e2b46b7c4ab8239c5adb7 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Tue, 7 Aug 2001 18:18:55 +0000 Subject: [PATCH 18/46] *** empty log message *** --- ChangeLog | 7 +++++++ libguile/ChangeLog | 5 +++++ test-suite/ChangeLog | 5 +++++ 3 files changed, 17 insertions(+) diff --git a/ChangeLog b/ChangeLog index e537d6951..2f5f0ce81 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2001-08-07 Marius Vollmer + + * Makefile.am (EXTRA_DIST, SUBDIRS): Move test-suite from + EXTRA_DIST to SUBDIRS. + + * configure.in: Added "test-suite/Makefile". + 2001-08-01 Marius Vollmer * configure.in: Added `--disable-linuxthreads' option and do not diff --git a/libguile/ChangeLog b/libguile/ChangeLog index be1fbc87a..f46645a44 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,8 @@ +2001-08-07 Marius Vollmer + + * Makefile.am (EXTRA_DIST): Distribute ChangeLog-1996-1999 and + ChangeLog-2000. Thanks to Daniel Skarda! + 2001-08-07 Michael Livshin * guile-snarf-docs-texi.in: don't call the tokenizer here, we now diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index 4c59ef578..ab281f5d4 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,8 @@ +2001-08-07 Marius Vollmer + + * Makefile.am: New file, to control distribution of the + test-suite. + 2001-08-02 Thien-Thi Nguyen * tests/getopt-long.test: New file. From 46a39e343af3c27f222e529e14ce455c452f687c Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Wed, 8 Aug 2001 16:34:57 +0000 Subject: [PATCH 19/46] *** empty log message *** --- .cvsignore | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.cvsignore b/.cvsignore index 24aa42bcc..994f72bbc 100644 --- a/.cvsignore +++ b/.cvsignore @@ -1,18 +1,19 @@ Makefile Makefile.in aclocal.m4 +check-guile +check-guile.log config.build-subdirs config.cache config.guess -config.sub config.h.in config.log config.status +config.sub configure guile-*.tar.gz +guile-tools +libltdl libtool ltconfig ltmain.sh -check-guile -check-guile.log -guile-tools From 83060bc4e71c0bc1c289373406d31aa07aa5556b Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Wed, 8 Aug 2001 16:41:28 +0000 Subject: [PATCH 20/46] (TESTS): List tests explicitely instead of using a wildcard. Wildcards don't seem to work for VPATH "make dist"s. --- test-suite/Makefile.am | 43 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am index c2aaa7f57..5206f26ae 100644 --- a/test-suite/Makefile.am +++ b/test-suite/Makefile.am @@ -1 +1,42 @@ -EXTRA_DIST = guile-test lib.scm tests/*.test tests/asmobs tests/c-api +TESTS = tests/alist.test \ + tests/asmobs \ + tests/bit-operations.test \ + tests/c-api \ + tests/c-api.test \ + tests/chars.test \ + tests/common-list.test \ + tests/environments.test \ + tests/eval.test \ + tests/exceptions.test \ + tests/format.test \ + tests/gc.test \ + tests/getopt-long.test \ + tests/goops.test \ + tests/guardians.test \ + tests/hooks.test \ + tests/import.test \ + tests/interp.test \ + tests/list.test \ + tests/load.test \ + tests/multilingual.nottest \ + tests/numbers.test \ + tests/optargs.test \ + tests/ports.test \ + tests/r4rs.test \ + tests/reader.test \ + tests/regexp.test \ + tests/srfi-10.test \ + tests/srfi-13.test \ + tests/srfi-14.test \ + tests/srfi-19.test \ + tests/srfi-4.test \ + tests/srfi-9.test \ + tests/strings.test \ + tests/symbols.test \ + tests/syncase.test \ + tests/syntax.test \ + tests/time.test \ + tests/version.test \ + tests/weaks.test + +EXTRA_DIST = guile-test lib.scm $(TESTS) From 5f09993304d52daf43efe5e542579d8c1bce7431 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Wed, 8 Aug 2001 16:41:38 +0000 Subject: [PATCH 21/46] *** empty log message *** --- test-suite/ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index ab281f5d4..f01c7488f 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,8 @@ +2001-08-08 Marius Vollmer + + * Makefile.am (TESTS): List tests explicitely instead of using a + wildcard. Wildcards don't seem to work for VPATH "make dist"s. + 2001-08-07 Marius Vollmer * Makefile.am: New file, to control distribution of the From 682542634b2fec0823302dc072084851621a11ec Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Thu, 9 Aug 2001 17:33:31 +0000 Subject: [PATCH 22/46] (TESTS): Do not call the variable "TESTS", call it "SCM_TESTS". This has special meaning to automake. How many tries left to get this right, mvo? --- test-suite/Makefile.am | 82 +++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am index 5206f26ae..5db5ba0d2 100644 --- a/test-suite/Makefile.am +++ b/test-suite/Makefile.am @@ -1,42 +1,42 @@ -TESTS = tests/alist.test \ - tests/asmobs \ - tests/bit-operations.test \ - tests/c-api \ - tests/c-api.test \ - tests/chars.test \ - tests/common-list.test \ - tests/environments.test \ - tests/eval.test \ - tests/exceptions.test \ - tests/format.test \ - tests/gc.test \ - tests/getopt-long.test \ - tests/goops.test \ - tests/guardians.test \ - tests/hooks.test \ - tests/import.test \ - tests/interp.test \ - tests/list.test \ - tests/load.test \ - tests/multilingual.nottest \ - tests/numbers.test \ - tests/optargs.test \ - tests/ports.test \ - tests/r4rs.test \ - tests/reader.test \ - tests/regexp.test \ - tests/srfi-10.test \ - tests/srfi-13.test \ - tests/srfi-14.test \ - tests/srfi-19.test \ - tests/srfi-4.test \ - tests/srfi-9.test \ - tests/strings.test \ - tests/symbols.test \ - tests/syncase.test \ - tests/syntax.test \ - tests/time.test \ - tests/version.test \ - tests/weaks.test +SCM_TESTS = tests/alist.test \ + tests/asmobs \ + tests/bit-operations.test \ + tests/c-api \ + tests/c-api.test \ + tests/chars.test \ + tests/common-list.test \ + tests/environments.test \ + tests/eval.test \ + tests/exceptions.test \ + tests/format.test \ + tests/gc.test \ + tests/getopt-long.test \ + tests/goops.test \ + tests/guardians.test \ + tests/hooks.test \ + tests/import.test \ + tests/interp.test \ + tests/list.test \ + tests/load.test \ + tests/multilingual.nottest \ + tests/numbers.test \ + tests/optargs.test \ + tests/ports.test \ + tests/r4rs.test \ + tests/reader.test \ + tests/regexp.test \ + tests/srfi-10.test \ + tests/srfi-13.test \ + tests/srfi-14.test \ + tests/srfi-19.test \ + tests/srfi-4.test \ + tests/srfi-9.test \ + tests/strings.test \ + tests/symbols.test \ + tests/syncase.test \ + tests/syntax.test \ + tests/time.test \ + tests/version.test \ + tests/weaks.test -EXTRA_DIST = guile-test lib.scm $(TESTS) +EXTRA_DIST = guile-test lib.scm $(SCM_TESTS) From 284774f38dbc22a249fcd388bc0743c1c2402677 Mon Sep 17 00:00:00 2001 From: Marius Vollmer Date: Thu, 9 Aug 2001 17:33:45 +0000 Subject: [PATCH 23/46] *** empty log message *** --- test-suite/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index f01c7488f..6f5571055 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,9 @@ +2001-08-09 Marius Vollmer + + * Makefile.am (TESTS): Do not call the variable "TESTS", call it + "SCM_TESTS". This has special meaning to automake. How many + tries left to get this right, mvo? + 2001-08-08 Marius Vollmer * Makefile.am (TESTS): List tests explicitely instead of using a From 2f4a254ac93145592018c3e7015a6678d6092981 Mon Sep 17 00:00:00 2001 From: Dirk Herrmann Date: Sat, 11 Aug 2001 16:59:42 +0000 Subject: [PATCH 24/46] * Added some syntax tests for numbers. --- test-suite/ChangeLog | 5 +++++ test-suite/tests/numbers.test | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index 6f5571055..0d06fcbfb 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,8 @@ +2001-08-11 Dirk Herrmann + + * tests/numbers.test: Added Some syntax tests for + string->number. + 2001-08-09 Marius Vollmer * Makefile.am (TESTS): Do not call the variable "TESTS", call it diff --git a/test-suite/tests/numbers.test b/test-suite/tests/numbers.test index f20a37d93..68f2b7477 100644 --- a/test-suite/tests/numbers.test +++ b/test-suite/tests/numbers.test @@ -850,6 +850,25 @@ ;;; string->number ;;; +(with-test-prefix "string->number" + + (pass-if "string->number" + (documented? string->number)) + + (pass-if "non number strings" + (for-each (lambda (x) (if (string->number x) (throw 'fail))) + '("" "q" "1q" "6+7iq" "8+9q" "10+11" "13+" "18@19 " "20@q" "23@" + "+25iq" "26i" "-q" "-iq" "i" "5#.0" "8/" "10#11" ".#" "." + "#o.2" "3.4q" "15.16e17q" "18.19e+q" ".a" ".17#18" "10q" "#b2" + "#b3" "#b4" "#b5" "#b6" "#b7" "#b8" "#b9" "#ba" "#bb" "#bc" + "#bd" "#be" "#bf" "#q" "#b#b1" "#o#o1" "#d#d1" "#x#x1" "#e#e1" + "#i#i1" "12@12+0i")) + #t) + + (pass-if-exception "exponent too big" + exception:out-of-range + (string->number "12.13e141414"))) + ;;; ;;; number? ;;; From 252422b02991833c1aa1e8b88f9c1a9e2059d6be Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Sun, 12 Aug 2001 18:31:10 +0000 Subject: [PATCH 25/46] (exception:no-such-option, exception:option-does-not-support-arg, exception:option-must-be-specified, exception:option-must-have-arg, exception:not-enough-args): New vars. ("option-ref", "required", "specified no value, given anyway", "specified arg required"): New top-level sections. --- test-suite/tests/getopt-long.test | 145 ++++++++++++++++++++++++++++-- 1 file changed, 138 insertions(+), 7 deletions(-) diff --git a/test-suite/tests/getopt-long.test b/test-suite/tests/getopt-long.test index 1d1658a09..b867835fa 100644 --- a/test-suite/tests/getopt-long.test +++ b/test-suite/tests/getopt-long.test @@ -18,19 +18,39 @@ ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ;;;; Boston, MA 02111-1307 USA +;;;; +;;;; NB: Please don't report the TTN_TEST_NEW env var refs as a bug. +;;;; They will go away on checkin of rewritten getopt-long.scm. +;;;; + (use-modules (test-suite lib) (ice-9 getopt-long) (ice-9 regex)) -(define exception:option-predicate-failed - (cons 'misc-error "^option predicate failed")) +(defmacro deferr (name-frag re) + (let ((name (symbol-append 'exception: name-frag))) + `(define ,name (cons 'misc-error ,re)))) + +(deferr no-such-option "^no such option") +(deferr option-predicate-failed "^option predicate failed") +(deferr option-does-not-support-arg "^option does not support argument") +(deferr option-must-be-specified "^option must be specified") +(deferr option-must-have-arg "^option must be specified with argument") + +(or (getenv "TTN_TEST_NEW") + (deferr not-enough-args "^not enough arg")) + +(with-test-prefix "exported procs" + (pass-if "`option-ref' defined" (defined? 'option-ref)) + (pass-if "`getopt-long' defined" (defined? 'getopt-long))) (with-test-prefix "specifying predicate" (define (test1 . args) - (getopt-long args `((test (value #t) - (predicate ,(lambda (x) - (string-match "^[0-9]+$" x))))))) + (getopt-long args + `((test (value #t) + (predicate ,(lambda (x) + (string-match "^[0-9]+$" x))))))) (pass-if "valid arg" (equal? (test1 "foo" "bar" "--test=123") @@ -41,8 +61,10 @@ (test1 "foo" "bar" "--test=foo")) (pass-if-exception "option has no arg" - exception:option-predicate-failed - (test1 "foo" "bar")) + (if (getenv "TTN_TEST_NEW") + exception:option-must-have-arg + exception:not-enough-args) + (test1 "foo" "bar" "--test")) ) @@ -90,6 +112,115 @@ (pass-if "long option `bar', long option `foo', no args" (equal? (test3 "prg" "--bar" "--foo") '((()) (foo . #t) (bar . #t)))) + + ) + +(with-test-prefix "option-ref" + + (define (test4 option-arg . args) + (equal? option-arg (option-ref (getopt-long + (cons "prog" args) + '((foo + (value optional) + (single-char #\f)) + (bar))) + 'foo #f))) + + (pass-if "option-ref `--foo 4'" + (test4 "4" "--foo" "4")) + + (pass-if "option-ref `-f 4'" + (test4 "4" "-f" "4")) + + (and (getenv "TTN_TEST_NEW") + (pass-if "option-ref `-f4'" + (test4 "4" "-f4"))) + + (pass-if "option-ref `--foo=4'" + (test4 "4" "--foo=4")) + + ) + +(with-test-prefix "required" + + (define (test5 args specs) + (getopt-long (cons "foo" args) specs)) + + (pass-if "not mentioned, not given" + (equal? (test5 '() '()) + '((())))) + + (and (getenv "TTN_TEST_NEW") + (pass-if-exception "not mentioned, given" + exception:no-such-option + (test5 '("--req") '((something))))) + + (pass-if "not specified required, not given" + (equal? (test5 '() '((req (required? #f)))) + '((())))) + + (pass-if "not specified required, given anyway" + (equal? (test5 '("--req") '((req (required? #f)))) + '((()) (req . #t)))) + + (pass-if "not specified required, but w/ value, given anyway w/ \"=\" val" + (equal? (test5 '("--req=7") '((req (required? #f) (value #t)))) + '((()) (req . "7")))) + + (pass-if "not specified required, but w/ value, given anyway w/ non-\"=\" val" + (equal? (test5 '("--req" "7") '((req (required? #f) (value #t)))) + '((()) (req . "7")))) + + (pass-if-exception "specified required, not given" + exception:option-must-be-specified + (test5 '() '((req (required? #t))))) + + ) + +(with-test-prefix "specified no-value, given anyway" + + (define (test6 args specs) + (getopt-long (cons "foo" args) specs)) + + (and (getenv "TTN_TEST_NEW") + (pass-if-exception "using \"=\" syntax" + exception:option-does-not-support-arg + (test6 '("--maybe=yes") '((maybe))))) + + ) + +(with-test-prefix "specified arg required" + + (define (test7 args) + (getopt-long (cons "foo" args) '((hmm (value #t) (single-char #\H)) + (ignore)))) + + (pass-if "short opt, arg given" + (equal? (test7 '("-H" "99")) + '((()) (hmm . "99")))) + + (pass-if "long non-\"=\" opt, arg given" + (equal? (test7 '("--hmm" "100")) + '((()) (hmm . "100")))) + + (pass-if "long \"=\" opt, arg given" + (equal? (test7 '("--hmm=101")) + '((()) (hmm . "101")))) + + (pass-if-exception "short opt, arg not given" + exception:option-must-have-arg + (test7 '("-H"))) + + (and (getenv "TTN_TEST_NEW") + (pass-if-exception "long non-\"=\" opt, arg not given (next arg an option)" + exception:option-must-have-arg + (test7 '("--hmm" "--ignore")))) + + (and (getenv "TTN_TEST_NEW") + (pass-if-exception "long \"=\" opt, arg not given" + exception:option-must-have-arg + (test7 '("--hmm")))) + ) ;;; getopt-long.test ends here From c3597bc4e08fc012d9af9808e6b08564bc06f8db Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Sun, 12 Aug 2001 18:34:11 +0000 Subject: [PATCH 26/46] *** empty log message *** --- test-suite/ChangeLog | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index 0d06fcbfb..e0d6c6716 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,14 @@ +2001-08-12 Thien-Thi Nguyen + + * tests/getopt-long.test (exception:no-such-option, + exception:option-does-not-support-arg, + exception:option-must-be-specified, + exception:option-must-have-arg, exception:not-enough-args): + New vars. + + ("option-ref", "required", "specified no value, given anyway", + "specified arg required"): New top-level sections. + 2001-08-11 Dirk Herrmann * tests/numbers.test: Added Some syntax tests for From 3925d0c31f82e36eabf2e37b93220e891b02b011 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Sun, 12 Aug 2001 18:56:39 +0000 Subject: [PATCH 27/46] Rewrite. Touch up docstrings. Augment commentary. --- ice-9/getopt-long.scm | 742 ++++++++++++------------------------------ 1 file changed, 212 insertions(+), 530 deletions(-) diff --git a/ice-9/getopt-long.scm b/ice-9/getopt-long.scm index ab30658f6..40fd4c4df 100644 --- a/ice-9/getopt-long.scm +++ b/ice-9/getopt-long.scm @@ -1,6 +1,3 @@ -;;; Author: Russ McManus -;;; $Id: getopt-long.scm,v 1.5 2001-08-02 10:26:52 ttn Exp $ -;;; ;;; Copyright (C) 1998, 2001 Free Software Foundation, Inc. ;;; ;;; This program is free software; you can redistribute it and/or modify @@ -41,19 +38,21 @@ ;;; whether to permit this exception to apply to your modifications. ;;; If you do not wish that, delete this exception notice. +;;; Author: Russ McManus (rewritten by Thien-Thi Nguyen) + ;;; Commentary: ;;; This module implements some complex command line option parsing, in -;;; the spirit of the GNU C library function 'getopt_long'. Both long +;;; the spirit of the GNU C library function `getopt_long'. Both long ;;; and short options are supported. ;;; ;;; The theory is that people should be able to constrain the set of ;;; options they want to process using a grammar, rather than some arbitrary ;;; structure. The grammar makes the option descriptions easy to read. ;;; - -;;; getopt-long is a function for parsing command-line arguments in a -;;; manner consistent with other GNU programs. +;;; `getopt-long' is a procedure for parsing command-line arguments in a +;;; manner consistent with other GNU programs. `option-ref' is a procedure +;;; that facilitates processing of the `getopt-long' return value. ;;; (getopt-long ARGS GRAMMAR) ;;; Parse the arguments ARGS according to the argument list grammar GRAMMAR. @@ -109,8 +108,8 @@ ;;; ;;; If an option's value is optional, then `getopt-long' decides ;;; whether it has a value by looking at what follows it in ARGS. If -;;; the next element is a string, and it does not appear to be an -;;; option itself, then that string is the option's value. +;;; the next element is does not appear to be an option itself, then +;;; that element is the option's value. ;;; ;;; The value of a long option can appear as the next element in ARGS, ;;; or it can follow the option name, separated by an `=' character. @@ -138,6 +137,8 @@ ;;; as a list, associated with the empty list. ;;; ;;; `getopt-long' throws an exception if: +;;; - it finds an unrecognized property in GRAMMAR +;;; - the value of the `single-char' property is not a character ;;; - it finds an unrecognized option in ARGS ;;; - a required option is omitted ;;; - an option that requires an argument doesn't get one @@ -168,515 +169,200 @@ ;;; (lockfile-dir . "/tmp") ;;; (verbose . #t)) +;;; (option-ref OPTIONS KEY DEFAULT) +;;; Return value in alist OPTIONS using KEY, a symbol; or DEFAULT if not +;;; found. The value is either a string or `#t'. +;;; +;;; For example, using the `getopt-long' return value from above: +;;; +;;; (option-ref (getopt-long ...) 'x-includes 42) => "/usr/include" +;;; (option-ref (getopt-long ...) 'not-a-key! 31) => 31 + ;;; Code: (define-module (ice-9 getopt-long) - :use-module (ice-9 common-list)) + :use-module ((ice-9 common-list) :select (some remove-if-not)) + :export (getopt-long option-ref)) - -;;; The code on this page was expanded by hand using the following code: -;;; (pretty-print -;;; (macroexpand -;;; '(define-record option-spec -;;; (name -;;; value -;;; value-required? -;;; single-char -;;; predicate-ls -;;; parse-ls)))) -;;; -;;; This avoids the need to load slib for records. -(define slib:error error) -(begin (define - option-spec->name - (lambda - (obj) - (if (option-spec? obj) - (vector-ref obj 1) - (slib:error - (quote option-spec->name) - ": bad record" - obj)))) - (define - option-spec->value - (lambda - (obj) - (if (option-spec? obj) - (vector-ref obj 2) - (slib:error - (quote option-spec->value) - ": bad record" - obj)))) - (define - option-spec->value-required? - (lambda - (obj) - (if (option-spec? obj) - (vector-ref obj 3) - (slib:error - (quote option-spec->value-required?) - ": bad record" - obj)))) - (define - option-spec->single-char - (lambda - (obj) - (if (option-spec? obj) - (vector-ref obj 4) - (slib:error - (quote option-spec->single-char) - ": bad record" - obj)))) - (define - option-spec->predicate-ls - (lambda - (obj) - (if (option-spec? obj) - (vector-ref obj 5) - (slib:error - (quote option-spec->predicate-ls) - ": bad record" - obj)))) - (define - option-spec->parse-ls - (lambda - (obj) - (if (option-spec? obj) - (vector-ref obj 6) - (slib:error - (quote option-spec->parse-ls) - ": bad record" - obj)))) - (define - set-option-spec-name! - (lambda - (obj val) - (if (option-spec? obj) - (vector-set! obj 1 val) - (slib:error - (quote set-option-spec-name!) - ": bad record" - obj)))) - (define - set-option-spec-value! - (lambda - (obj val) - (if (option-spec? obj) - (vector-set! obj 2 val) - (slib:error - (quote set-option-spec-value!) - ": bad record" - obj)))) - (define - set-option-spec-value-required?! - (lambda - (obj val) - (if (option-spec? obj) - (vector-set! obj 3 val) - (slib:error - (quote set-option-spec-value-required?!) - ": bad record" - obj)))) - (define - set-option-spec-single-char! - (lambda - (obj val) - (if (option-spec? obj) - (vector-set! obj 4 val) - (slib:error - (quote set-option-spec-single-char!) - ": bad record" - obj)))) - (define - set-option-spec-predicate-ls! - (lambda - (obj val) - (if (option-spec? obj) - (vector-set! obj 5 val) - (slib:error - (quote set-option-spec-predicate-ls!) - ": bad record" - obj)))) - (define - set-option-spec-parse-ls! - (lambda - (obj val) - (if (option-spec? obj) - (vector-set! obj 6 val) - (slib:error - (quote set-option-spec-parse-ls!) - ": bad record" - obj)))) - (define - option-spec? - (lambda - (obj) - (and (vector? obj) - (= (vector-length obj) 7) - (eq? (vector-ref obj 0) (quote option-spec))))) - (define - make-option-spec - (lambda - (option-spec->name - option-spec->value - option-spec->value-required? - option-spec->single-char - option-spec->predicate-ls - option-spec->parse-ls) - (vector - (quote option-spec) - option-spec->name - option-spec->value - option-spec->value-required? - option-spec->single-char - option-spec->predicate-ls - option-spec->parse-ls)))) +(define option-spec-fields '(name + value + required? + single-char + predicate + value-policy)) - -;;; -;;; parse functions go on this page. -;;; -(define make-user-predicate - (lambda (pred) - (lambda (spec) - (let ((val (option-spec->value spec))) - (if (and val - (pred val)) #t - (error "option predicate failed:" (option-spec->name spec))))))) +(define option-spec (make-record-type 'option-spec option-spec-fields)) +(define make-option-spec (record-constructor option-spec option-spec-fields)) -(define make-not-allowed-value-fn - (lambda () - (lambda (spec) - (let ((val (option-spec->value spec))) - (if (not (or (eq? val #t) - (eq? val #f))) - (let ((name (option-spec->name spec))) - (error "option does not support argument:" name))))))) +(define (define-one-option-spec-field-accessor field) + `(define ,(symbol-append 'option-spec-> field) ;;; name slib-compat + (record-accessor option-spec ',field))) -(define make-option-required-predicate - (lambda () - (lambda (spec) - (let ((val (option-spec->value spec))) - (if (not val) - (let ((name (option-spec->name spec))) - (error "option must be specified:" name))))))) +(define (define-one-option-spec-field-modifier field) + `(define ,(symbol-append 'set-option-spec- field '!) ;;; name slib-compat + (record-modifier option-spec ',field))) -(define make-option-value-predicate - (lambda (predicate) - (lambda (spec) - (let ((val (option-spec->value spec))) - (if (not (predicate val)) - (let ((name (option-spec->name spec))) - (error "Bad option value:" name val))))))) +(defmacro define-all-option-spec-accessors/modifiers () + `(begin + ,@(map define-one-option-spec-field-accessor option-spec-fields) + ,@(map define-one-option-spec-field-modifier option-spec-fields))) -(define make-required-value-fn - (lambda () - (lambda (spec) - (let ((val (option-spec->value spec))) - (if (eq? val #t) - (let ((name (option-spec->name spec))) - (error "option must be specified with argument:" name))))))) +(define-all-option-spec-accessors/modifiers) -(define single-char-value? - (lambda (val) - (char? val))) +(define make-option-spec + (let ((ctor (record-constructor option-spec '(name)))) + (lambda (name) + (ctor name)))) (define (parse-option-spec desc) - (letrec ((parse-iter - (lambda (spec) - (let ((parse-ls (option-spec->parse-ls spec))) - (if (null? parse-ls) - spec - (let ((ls (car parse-ls))) - (if (or (not (list? ls)) - (not (= (length ls) 2))) - (error "Bad option specification:" ls)) - (let ((key (car ls)) - (val (cadr ls))) - (cond ((and (eq? key 'required?) val) - ;; required values implemented as a predicate - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - (option-spec->single-char spec) - (cons (make-option-required-predicate) - (option-spec->predicate-ls spec)) - (cdr parse-ls)))) - ;; if value not required, don't add predicate, - ((eq? key 'required?) - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - (option-spec->single-char spec) - (option-spec->predicate-ls spec) - (cdr parse-ls)))) - ;; handle value specification - ((eq? key 'value) - (cond ((eq? val #t) - ;; when value is required, add a - ;; predicate to that effect and record - ;; the fact in value-required? field. - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - #t - (option-spec->single-char spec) - (cons (make-required-value-fn) - (option-spec->predicate-ls spec)) - (cdr parse-ls)))) - ((eq? val #f) - ;; when the value is not allowed, add a - ;; predicate to that effect. one can - ;; detect that a value is not supplied - ;; by checking the option value against - ;; #f. - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - #f - (option-spec->single-char spec) - (cons (make-not-allowed-value-fn) - (option-spec->predicate-ls spec)) - (cdr parse-ls)))) - ((eq? val 'optional) - ;; for optional values, don't add a - ;; predicate. do, however put the value - ;; 'optional in the value-required? - ;; field. this setting checks whether - ;; optional values are 'greedy'. set to - ;; #f to make optional value clauses - ;; 'non-greedy'. - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - 'optional - (option-spec->single-char spec) - (option-spec->predicate-ls spec) - (cdr parse-ls)))) - (#t - ;; error case - (error "Bad value specification for option:" - (cons key val))))) - ;; specify single char defined for this option. - ((eq? key 'single-char) - (if (not (single-char-value? val)) - (error "Not a single-char-value:" - val " for option:" key) - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - val - (option-spec->predicate-ls spec) - (cdr parse-ls))))) - ((eq? key 'predicate) - (if (procedure? val) - (parse-iter - (make-option-spec - (option-spec->name spec) - (option-spec->value spec) - (option-spec->value-required? spec) - (option-spec->single-char spec) - (cons (make-user-predicate val) - (option-spec->predicate-ls spec)) - (cdr parse-ls))) - (error "Bad predicate specified for option:" - (cons key val)))))))))))) - (if (or (not (pair? desc)) - (string? (car desc))) - (error "Bad option specification:" desc)) - (parse-iter (make-option-spec (car desc) - #f - #f - #f - '() - (cdr desc))))) + (let ((spec (make-option-spec (symbol->string (car desc))))) + (for-each (lambda (desc-elem) + (let ((given (lambda () (cadr desc-elem)))) + (case (car desc-elem) + ((required?) + (set-option-spec-required?! spec (given))) + ((value) + (set-option-spec-value-policy! spec (given))) + ((single-char) + (or (char? (given)) + (error "`single-char' value must be a char!")) + (set-option-spec-single-char! spec (given))) + ((predicate) + (set-option-spec-predicate! + spec ((lambda (pred) + (lambda (name val) + (or (not val) + (pred val) + (error "option predicate failed:" name)))) + (given)))) + (else + (error "invalid getopt-long option property:" + (car desc-elem)))))) + (cdr desc)) + spec)) - -;;; -;;; -;;; (define (split-arg-list argument-list) - "Given an ARGUMENT-LIST, decide which part to process for options. -Everything before an arg of \"--\" is fair game, everything after it -should not be processed. The \"--\" is discarded. A cons pair is -returned whose car is the list to process for options, and whose cdr -is the list to not process." - (let loop ((process-ls '()) - (not-process-ls argument-list)) - (cond ((null? not-process-ls) - (cons (reverse process-ls) '())) - ((string=? "--" (car not-process-ls)) - (cons (reverse process-ls) (cdr not-process-ls))) - (#t - (loop (cons (car not-process-ls) process-ls) - (cdr not-process-ls)))))) + ;; Scan ARGUMENT-LIST for "--" and return (BEFORE-LS . AFTER-LS). + ;; Discard the "--". If no "--" is found, AFTER-LS is empty. + (let loop ((yes '()) (no argument-list)) + (cond ((null? no) (cons (reverse yes) no)) + ((string=? "--" (car no)) (cons (reverse yes) (cdr no))) + (else (loop (cons (car no) yes) (cdr no)))))) -(define short-opt-rx (make-regexp "^-([a-zA-Z]+)")) -(define long-opt-no-value-rx (make-regexp "^--([^=]+)$")) +(define short-opt-rx (make-regexp "^-([a-zA-Z]+)(.*)")) +(define long-opt-no-value-rx (make-regexp "^--([^=]+)$")) (define long-opt-with-value-rx (make-regexp "^--([^=]+)=(.*)")) -(define (single-char-expander specifications opt-ls) - "Expand single letter options that are mushed together." - (let ((response #f)) - (define (is-short-opt? str) - (set! response (regexp-exec short-opt-rx str)) - response) - (define (iter opt-ls ret-ls) - (cond ((null? opt-ls) - (reverse ret-ls)) - ((is-short-opt? (car opt-ls)) - (let* ((orig-str (car opt-ls)) - (match-pair (vector-ref response 2)) - (match-str (substring orig-str (car match-pair) - (cdr match-pair)))) - (if (= (string-length match-str) 1) - (iter (cdr opt-ls) - (cons (string-append "-" match-str) ret-ls)) - (iter (cons (string-append "-" (substring match-str 1)) - (cdr opt-ls)) - (cons (string-append "-" (substring match-str 0 1)) - ret-ls))))) - (#t (iter (cdr opt-ls) - (cons (car opt-ls) ret-ls))))) - (iter opt-ls '()))) +(define (match-substring match which) + ;; condensed from (ice-9 regex) `match:{substring,start,end}' + (let ((sel (vector-ref match (1+ which)))) + (substring (vector-ref match 0) (car sel) (cdr sel)))) -(define (process-short-option specifications argument-ls alist) - "Process a single short option that appears at the front of the ARGUMENT-LS, -according to SPECIFICATIONS. Returns #f is there is no such argument. -Otherwise returns a pair whose car is the list of remaining arguments, and -whose cdr is a new association list, constructed by adding a pair to the -supplied ALIST. The pair on the front of the returned association list -describes the option found at the head of ARGUMENT-LS. The way this routine -currently works, an option that never takes a value that is followed by a non -option will cause an error, which is probably a bug. To fix the bug the -option specification needs to record whether the option ever can take a -value." - (define (short-option->char option) - (string-ref option 1)) - (define (is-short-option? option) - (regexp-exec short-opt-rx option)) - (define (is-long-option? option) - (or (regexp-exec long-opt-with-value-rx option) - (regexp-exec long-opt-no-value-rx option))) - (define (find-matching-spec option) - (let ((key (short-option->char option))) - (find-if (lambda (spec) - (eq? key (option-spec->single-char spec))) specifications))) - (let ((option (car argument-ls))) - (if (is-short-option? option) - (let ((spec (find-matching-spec option))) - (if spec - (let* ((next-value (if (null? (cdr argument-ls)) - #f - (cadr argument-ls))) - (option-value (if (and next-value - (not (is-short-option? next-value)) - (not (is-long-option? next-value)) - (option-spec->value-required? spec)) - next-value - #t)) - (new-alist (cons (cons (option-spec->name spec) - option-value) - alist))) - (cons (if (eq? option-value #t) - (cdr argument-ls) ; one value, skip just one - (cddr argument-ls)) ; must be a value, skip two - new-alist)) - (error "No such option:" option))) - #f))) +(define (expand-clumped-singles opt-ls) + ;; example: ("--xyz" "-abc5d") => ("--xyz" "-a" "-b" "-c" "5d") + (let loop ((opt-ls opt-ls) (ret-ls '())) + (cond ((null? opt-ls) + (reverse ret-ls)) ;;; retval + ((regexp-exec short-opt-rx (car opt-ls)) + => (lambda (match) + (let ((singles (reverse + (map (lambda (c) + (string-append "-" (make-string 1 c))) + (string->list + (match-substring match 1))))) + (extra (match-substring match 2))) + (loop (cdr opt-ls) + (append (if (string=? "" extra) + singles + (cons extra singles)) + ret-ls))))) + (else (loop (cdr opt-ls) + (cons (car opt-ls) ret-ls)))))) -(define (process-long-option specifications argument-ls alist) - (define (find-matching-spec key) - (find-if (lambda (spec) - (eq? key (option-spec->name spec))) - specifications)) - (define (split-long-option option) - ;; returns a pair whose car is a symbol naming the option, cdr is - ;; the option value. as a special case, if the option value is - ;; #f, then the caller should use the next item in argument-ls as - ;; the option value. - (let ((resp (regexp-exec long-opt-no-value-rx option))) - (if resp - ;; Aha, we've found a long option without an equal sign. - ;; Maybe we need to grab a value from argument-ls. To find - ;; out we need to refer to the option-spec. - (let* ((key-pair (vector-ref resp 2)) - (key (string->symbol - (substring option (car key-pair) (cdr key-pair)))) - (spec (find-matching-spec key))) - (let* ((req (option-spec->value-required? spec)) - (retval (cons key (if req #f #t)))) - ;; this is a fucking kludge, i hate it. it's necessary because - ;; the protocol (return #f to indicate next element is an option - ;; arg) is insufficient. needs redesign. why am i checking in - ;; such ugliness? read moby dick! -ttn - (and (eq? 'optional req) - (set-object-property! retval 'optional #t)) - retval)) - (let ((resp (regexp-exec long-opt-with-value-rx option))) - ;; Aha, we've found a long option with an equal sign. The - ;; option value is simply the value to the right of the - ;; equal sign. - (if resp - (let* ((key-pair (vector-ref resp 2)) - (key (string->symbol - (substring option - (car key-pair) (cdr key-pair)))) - (value-pair (vector-ref resp 3)) - (value (substring option - (car value-pair) (cdr value-pair)))) - (cons key value)) - #f))))) - (let* ((option (car argument-ls)) - (pair (split-long-option option))) - (cond ((and pair (eq? (cdr pair) #f)) - (cond ((and (null? (cdr argument-ls)) - (not (object-property pair 'optional))) - (error "Not enough options.")) - ((null? (cdr argument-ls)) - (cons '() (cons (cons (car pair) #t) alist))) - ((let* ((next (cadr argument-ls)) - (m (or (regexp-exec short-opt-rx next) - (regexp-exec long-opt-with-value-rx next) - (regexp-exec long-opt-no-value-rx next)))) - (and m (object-property pair 'optional))) - (cons (cdr argument-ls) - (cons (cons (car pair) #t) alist))) - (else - (cons (cddr argument-ls) - (cons (cons (car pair) (cadr argument-ls)) alist))))) - (pair - (cons (cdr argument-ls) (cons pair alist))) - (else #f)))) +(define (looks-like-an-option string) + (some (lambda (rx) + (regexp-exec rx string)) + `(,short-opt-rx + ,long-opt-with-value-rx + ,long-opt-no-value-rx))) -(define (process-options specifications argument-ls) - (define (iter argument-ls alist rest-ls) - (if (null? argument-ls) - (cons alist (reverse rest-ls)) - (let ((pair (process-short-option specifications argument-ls alist))) - (if pair - (let ((argument-ls (car pair)) - (alist (cdr pair))) - (iter argument-ls alist rest-ls)) - (let ((pair (process-long-option - specifications argument-ls alist))) - (if pair - (let ((argument-ls (car pair)) - (alist (cdr pair))) - (iter argument-ls alist rest-ls)) - (iter (cdr argument-ls) - alist - (cons (car argument-ls) rest-ls)))))))) - (iter argument-ls '() '())) +(define (process-options specs argument-ls) + ;; Use SPECS to scan ARGUMENT-LS; return (FOUND . ETC). + ;; FOUND is an unordered list of option specs for found options, while ETC + ;; is an order-maintained list of elements in ARGUMENT-LS that are neither + ;; options nor their values. + (let ((idx (map (lambda (spec) + (cons (option-spec->name spec) spec)) + specs)) + (sc-idx (map (lambda (spec) + (cons (make-string 1 (option-spec->single-char spec)) + spec)) + (remove-if-not option-spec->single-char specs)))) + (let loop ((argument-ls argument-ls) (found '()) (etc '())) + (let ((eat! (lambda (spec ls) + (let ((val!loop (lambda (val n-ls n-found n-etc) + (set-option-spec-value! spec val) + (loop n-ls n-found n-etc))) + (ERR:no-arg (lambda () + (error (string-append + "option must be specified" + " with argument:") + (option-spec->name spec))))) + (cond + ((eq? 'optional (option-spec->value-policy spec)) + (if (or (null? (cdr ls)) + (looks-like-an-option (cadr ls))) + (val!loop #t + (cdr ls) + (cons spec found) + etc) + (val!loop (cadr ls) + (cddr ls) + (cons spec found) + etc))) + ((eq? #t (option-spec->value-policy spec)) + (if (or (null? (cdr ls)) + (looks-like-an-option (cadr ls))) + (ERR:no-arg) + (val!loop (cadr ls) + (cddr ls) + (cons spec found) + etc))) + (else + (val!loop #t + (cdr ls) + (cons spec found) + etc))))))) + (if (null? argument-ls) + (cons found (reverse etc)) ;;; retval + (cond ((regexp-exec short-opt-rx (car argument-ls)) + => (lambda (match) + (let* ((c (match-substring match 1)) + (spec (or (assoc-ref sc-idx c) + (error "no such option:" c)))) + (eat! spec argument-ls)))) + ((regexp-exec long-opt-no-value-rx (car argument-ls)) + => (lambda (match) + (let* ((opt (match-substring match 1)) + (spec (or (assoc-ref idx opt) + (error "no such option:" opt)))) + (eat! spec argument-ls)))) + ((regexp-exec long-opt-with-value-rx (car argument-ls)) + => (lambda (match) + (let* ((opt (match-substring match 1)) + (spec (or (assoc-ref idx opt) + (error "no such option:" opt)))) + (if (option-spec->value-policy spec) + (eat! spec (append + (list 'ignored + (match-substring match 2)) + (cdr argument-ls))) + (error "option does not support argument:" + opt))))) + (else + (loop (cdr argument-ls) + found + (cons (car argument-ls) etc))))))))) (define (getopt-long program-arguments option-desc-list) "Process options, handling both long and short options, similar to @@ -708,41 +394,37 @@ or option values. By default, options are not required, and option values are not required. By default, single character equivalents are not supported; if you want to allow the user to use single character options, you need -to add a 'single-char' clause to the option description." +to add a `single-char' clause to the option description." (let* ((specifications (map parse-option-spec option-desc-list)) (pair (split-arg-list (cdr program-arguments))) - (split-ls (single-char-expander specifications (car pair))) - (non-split-ls (cdr pair))) - (let* ((opt-pair (process-options specifications split-ls)) - (alist (car opt-pair)) - (rest-ls (append (cdr opt-pair) non-split-ls))) - ;; loop through returned alist, set values into specifications - (for-each (lambda (pair) - (let* ((key (car pair)) - (val (cdr pair)) - (spec (find-if (lambda (spec) - (eq? key (option-spec->name spec))) - specifications))) - (if spec (set-option-spec-value! spec val)))) - alist) - ;; now fire all the predicates - (for-each (lambda (spec) - (let ((predicate-ls (option-spec->predicate-ls spec))) - (for-each (lambda (predicate) - (predicate spec)) - predicate-ls))) - specifications) - (cons (cons '() rest-ls) alist)))) + (split-ls (expand-clumped-singles (car pair))) + (non-split-ls (cdr pair)) + (found/etc (process-options specifications split-ls)) + (found (car found/etc)) + (rest-ls (append (cdr found/etc) non-split-ls))) + (for-each (lambda (spec) + (let ((name (option-spec->name spec)) + (val (option-spec->value spec))) + (and (option-spec->required? spec) + (or (memq spec found) + (error "option must be specified:" name))) + (and (memq spec found) + (eq? #t (option-spec->value-policy spec)) + (or val + (error "option must be specified with argument:" + name))) + (let ((pred (option-spec->predicate spec))) + (and pred (pred name val))))) + specifications) + (cons (cons '() rest-ls) + (map (lambda (spec) + (cons (string->symbol (option-spec->name spec)) + (option-spec->value spec))) + found)))) (define (option-ref options key default) - "Look for an option value in OPTIONS using KEY. If no such value is -found, return DEFAULT." - (let ((pair (assq key options))) - (if pair - (cdr pair) - default))) - -(export option-ref) -(export getopt-long) + "Return value in alist OPTIONS using KEY, a symbol; or DEFAULT if not found. +The value is either a string or `#t'." + (or (assq-ref options key) default)) ;;; getopt-long.scm ends here From 4030287ec095d3c21804f0ebfc92fceff3399148 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Sun, 12 Aug 2001 18:59:16 +0000 Subject: [PATCH 28/46] *** empty log message *** --- ice-9/ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ice-9/ChangeLog b/ice-9/ChangeLog index 62ba0a291..3bbf33074 100644 --- a/ice-9/ChangeLog +++ b/ice-9/ChangeLog @@ -1,3 +1,9 @@ +2001-08-12 Thien-Thi Nguyen + + * getopt-long.scm: Rewrite. + Touch up docstrings. + Augment commentary. + 2001-08-02 Neil Jerram * debugger.scm (run-last-command): Return current state if From c0c07ee9420de34151cd950d00f8fbf432de0aa5 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Sun, 12 Aug 2001 19:03:34 +0000 Subject: [PATCH 29/46] Remove dependency on `TTN_TEST_NEW' env var. --- test-suite/tests/getopt-long.test | 47 +++++++++++-------------------- 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/test-suite/tests/getopt-long.test b/test-suite/tests/getopt-long.test index b867835fa..f40fa5fb1 100644 --- a/test-suite/tests/getopt-long.test +++ b/test-suite/tests/getopt-long.test @@ -1,4 +1,4 @@ -;;;; getopt-long.test --- optional long arg processing -*- scheme -*- +;;;; getopt-long.test --- long options processing -*- scheme -*- ;;;; Thien-Thi Nguyen --- August 2001 ;;;; ;;;; Copyright (C) 2001 Free Software Foundation, Inc. @@ -18,11 +18,6 @@ ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ;;;; Boston, MA 02111-1307 USA -;;;; -;;;; NB: Please don't report the TTN_TEST_NEW env var refs as a bug. -;;;; They will go away on checkin of rewritten getopt-long.scm. -;;;; - (use-modules (test-suite lib) (ice-9 getopt-long) (ice-9 regex)) @@ -37,9 +32,6 @@ (deferr option-must-be-specified "^option must be specified") (deferr option-must-have-arg "^option must be specified with argument") -(or (getenv "TTN_TEST_NEW") - (deferr not-enough-args "^not enough arg")) - (with-test-prefix "exported procs" (pass-if "`option-ref' defined" (defined? 'option-ref)) (pass-if "`getopt-long' defined" (defined? 'getopt-long))) @@ -61,9 +53,7 @@ (test1 "foo" "bar" "--test=foo")) (pass-if-exception "option has no arg" - (if (getenv "TTN_TEST_NEW") - exception:option-must-have-arg - exception:not-enough-args) + exception:option-must-have-arg (test1 "foo" "bar" "--test")) ) @@ -132,9 +122,8 @@ (pass-if "option-ref `-f 4'" (test4 "4" "-f" "4")) - (and (getenv "TTN_TEST_NEW") - (pass-if "option-ref `-f4'" - (test4 "4" "-f4"))) + (pass-if "option-ref `-f4'" + (test4 "4" "-f4")) (pass-if "option-ref `--foo=4'" (test4 "4" "--foo=4")) @@ -150,10 +139,9 @@ (equal? (test5 '() '()) '((())))) - (and (getenv "TTN_TEST_NEW") - (pass-if-exception "not mentioned, given" - exception:no-such-option - (test5 '("--req") '((something))))) + (pass-if-exception "not mentioned, given" + exception:no-such-option + (test5 '("--req") '((something)))) (pass-if "not specified required, not given" (equal? (test5 '() '((req (required? #f)))) @@ -182,10 +170,9 @@ (define (test6 args specs) (getopt-long (cons "foo" args) specs)) - (and (getenv "TTN_TEST_NEW") - (pass-if-exception "using \"=\" syntax" - exception:option-does-not-support-arg - (test6 '("--maybe=yes") '((maybe))))) + (pass-if-exception "using \"=\" syntax" + exception:option-does-not-support-arg + (test6 '("--maybe=yes") '((maybe)))) ) @@ -211,15 +198,13 @@ exception:option-must-have-arg (test7 '("-H"))) - (and (getenv "TTN_TEST_NEW") - (pass-if-exception "long non-\"=\" opt, arg not given (next arg an option)" - exception:option-must-have-arg - (test7 '("--hmm" "--ignore")))) + (pass-if-exception "long non-\"=\" opt, arg not given (next arg an option)" + exception:option-must-have-arg + (test7 '("--hmm" "--ignore"))) - (and (getenv "TTN_TEST_NEW") - (pass-if-exception "long \"=\" opt, arg not given" - exception:option-must-have-arg - (test7 '("--hmm")))) + (pass-if-exception "long \"=\" opt, arg not given" + exception:option-must-have-arg + (test7 '("--hmm"))) ) From a583bf1ec681e8a869c8c8f2f1cb6025eb18a1e6 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Sun, 12 Aug 2001 19:19:41 +0000 Subject: [PATCH 30/46] Expand ice-9/getopt-long.scm bugfix news. --- NEWS | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index bba3769b5..5390f8c41 100644 --- a/NEWS +++ b/NEWS @@ -689,13 +689,37 @@ Use module system operations for all variables. That is, a call to `throw', `error', etc is now guaranteed to not return. -** Bugfix for (ice-9 getopt-long) +** Bugfixes for (ice-9 getopt-long) -Parsing for options that are specified to have `optional' args now checks if -the next element is an option instead of unconditionally taking it as the +This module is now tested using test-suite/tests/getopt-long.test. +The following bugs have been fixed: + +*** Parsing for options that are specified to have `optional' args now checks +if the next element is an option instead of unconditionally taking it as the option arg. -Also, this module is now tested using test-suite/tests/getopt-long.test. +*** An error is now thrown for `--opt=val' when the option description +does not specify `(value #t)' or `(value optional)'. This condition used to +be accepted w/o error, contrary to the documentation. + +*** The error message for unrecognized options is now more informative. +It used to be "not a record", an artifact of the implementation. + +*** The error message for `--opt' terminating the arg list (no value), when +`(value #t)' is specified, is now more informative. It used to be "not enough +args". + +*** "Clumped" single-char args now preserve trailing string, use it as arg. +The expansion used to be like so: + + ("-abc5d" "--xyz") => ("-a" "-b" "-c" "--xyz") + +Note that the "5d" is dropped. Now it is like so: + + ("-abc5d" "--xyz") => ("-a" "-b" "-c" "5d" "--xyz") + +This enables single-char options to have adjoining arguments as long as their +constituent characters are not potential single-char options. * Changes to the C interface From 85e6a2f842715daec99f2b7f4251211373b6c99b Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Thu, 16 Aug 2001 03:41:49 +0000 Subject: [PATCH 31/46] * GUILE-VERSION (GUILE_MINOR_VERSION): bump for new unstable. (GUILE_MICRO_VERSION): reset for new unstable. (LIBGUILE_INTERFACE_CURRENT): use libtool versioning scheme. (LIBGUILE_INTERFACE_REVISION): use libtool versioning scheme. (LIBGUILE_INTERFACE_AGE): use libtool versioning scheme. (LIBGUILE_INTERFACE): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE_CURRENT): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE_REVISION): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE_AGE): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE): use libtool versioning scheme. --- GUILE-VERSION | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/GUILE-VERSION b/GUILE-VERSION index 55f99d9f6..5aa7e6c66 100644 --- a/GUILE-VERSION +++ b/GUILE-VERSION @@ -1,5 +1,7 @@ +# -*-shell-script-*- + GUILE_MAJOR_VERSION=1 -GUILE_MINOR_VERSION=5 +GUILE_MINOR_VERSION=7 GUILE_MICRO_VERSION=0 GUILE_VERSION=${GUILE_MAJOR_VERSION} @@ -10,14 +12,17 @@ GUILE_VERSION=${GUILE_VERSION}.${GUILE_MICRO_VERSION} VERSION=${GUILE_VERSION} PACKAGE=guile +# See libtool info pages for more information on how and when to +# change these. + # libguile.so versioning info -LIBGUILE_MAJOR_VERSION=10 -LIBGUILE_MINOR_VERSION=0 -LIBGUILE_REVISION_VERSION=0 -LIBGUILE_VERSION=${LIBGUILE_MAJOR_VERSION}.${LIBGUILE_MINOR_VERSION}.${LIBGUILE_REVISION_VERSION} +LIBGUILE_INTERFACE_CURRENT=10 +LIBGUILE_INTERFACE_REVISION=0 +LIBGUILE_INTERFACE_AGE=0 +LIBGUILE_INTERFACE="${LIBGUILE_INTERFACE_CURRENT}:${LIBGUILE_INTERFACE_REVISION}:${LIBGUILE_INTERFACE_AGE}" # libguileqthreads.so versioning info -LIBGUILEQTHREADS_MAJOR_VERSION=10 -LIBGUILEQTHREADS_MINOR_VERSION=0 -LIBGUILEQTHREADS_REVISION_VERSION=0 -LIBGUILEQTHREADS_VERSION=${LIBGUILEQTHREADS_MAJOR_VERSION}.${LIBGUILEQTHREADS_MINOR_VERSION}.${LIBGUILEQTHREADS_REVISION_VERSION} +LIBGUILEQTHREADS_INTERFACE_CURRENT=1 +LIBGUILEQTHREADS_INTERFACE_REVISION=0 +LIBGUILEQTHREADS_INTERFACE_AGE=0 +LIBGUILEQTHREADS_INTERFACE="${LIBGUILEQTHREADS_INTERFACE_CURRENT}:${LIBGUILEQTHREADS_INTERFACE_REVISION}:${LIBGUILEQTHREADS_INTERFACE_AGE}" From 9e202853dd61d3eb239464d4d5c5c7132db99382 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Thu, 16 Aug 2001 03:43:50 +0000 Subject: [PATCH 32/46] * configure.in (LIBGUILE_INTERFACE_CURRENT): use libtool versioning scheme. (LIBGUILE_INTERFACE_REVISION): use libtool versioning scheme. (LIBGUILE_INTERFACE_AGE): use libtool versioning scheme. (LIBGUILE_INTERFACE): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE_CURRENT): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE_REVISION): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE_AGE): use libtool versioning scheme. (LIBGUILEQTHREADS_INTERFACE): use libtool versioning scheme. --- configure.in | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/configure.in b/configure.in index 6bb4ef87c..5f7140345 100644 --- a/configure.in +++ b/configure.in @@ -568,10 +568,10 @@ if test "${THREAD_PACKAGE}" != "" ; then AC_CHECK_LIB(pthread, main) fi fi -AC_SUBST(LIBGUILEQTHREADS_MAJOR_VERSION) -AC_SUBST(LIBGUILEQTHREADS_MINOR_VERSION) -AC_SUBST(LIBGUILEQTHREADS_REVISION_VERSION) -AC_SUBST(LIBGUILEQTHREADS_VERSION) +AC_SUBST(LIBGUILEQTHREADS_INTERFACE_CURRENT) +AC_SUBST(LIBGUILEQTHREADS_INTERFACE_REVISION) +AC_SUBST(LIBGUILEQTHREADS_INTERFACE_AGE) +AC_SUBST(LIBGUILEQTHREADS_INTERFACE) ## If we're using GCC, ask for aggressive warnings. case "$GCC" in @@ -599,10 +599,11 @@ AC_SUBST(GUILE_MAJOR_VERSION) AC_SUBST(GUILE_MINOR_VERSION) AC_SUBST(GUILE_MICRO_VERSION) AC_SUBST(GUILE_VERSION) -AC_SUBST(LIBGUILE_MAJOR_VERSION) -AC_SUBST(LIBGUILE_MINOR_VERSION) -AC_SUBST(LIBGUILE_REVISION_VERSION) -AC_SUBST(LIBGUILE_VERSION) + +AC_SUBST(LIBGUILE_INTERFACE_CURRENT) +AC_SUBST(LIBGUILE_INTERFACE_REVISION) +AC_SUBST(LIBGUILE_INTERFACE_AGE) +AC_SUBST(LIBGUILE_INTERFACE) dnl Tell guile-config what flags guile users should link against. GUILE_LIBS="$LDFLAGS $THREAD_LIBS_INSTALLED $LIBS" From 9e86801e2fb35981081c14a1fdea08c063904446 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Thu, 16 Aug 2001 03:44:19 +0000 Subject: [PATCH 33/46] * Makefile.am (libguile_la_LDFLAGS): use libtool interface version variables. (libpath.h): change libguileversion to libguileinterface. --- libguile/Makefile.am | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libguile/Makefile.am b/libguile/Makefile.am index a97db45db..8eaa24fc5 100644 --- a/libguile/Makefile.am +++ b/libguile/Makefile.am @@ -116,7 +116,7 @@ noinst_HEADERS = coop-threads.c coop-threads.h coop.c num2integral.i.c libguile_la_DEPENDENCIES = @LIBLOBJS@ libguile_la_LIBADD = @LIBLOBJS@ $(LIBLTDL) -libguile_la_LDFLAGS = -version-info @LIBGUILE_MAJOR_VERSION@:@LIBGUILE_MINOR_VERSION@:@LIBGUILE_REVISION_VERSION@ -export-dynamic +libguile_la_LDFLAGS = -version-info @LIBGUILE_INTERFACE_CURRENT@:@LIBGUILE_INTERFACE_REVISION@:@LIBGUILE_INTERFACE_AGE@ -export-dynamic # These are headers visible as pkginclude_HEADERS = gh.h @@ -181,7 +181,7 @@ libpath.h: $(srcdir)/Makefile.in $(top_builddir)/config.status @echo ' { "pkgincludedir", "$(includedir)/@PACKAGE@" }, \' \ >> libpath.tmp @echo ' { "guileversion", "@GUILE_VERSION@" }, \' >> libpath.tmp - @echo ' { "libguileversion", "@LIBGUILE_VERSION@" }, \' >> libpath.tmp + @echo ' { "libguileinterface", "@LIBGUILE_INTERFACE@" }, \' >> libpath.tmp @echo ' { "LIBS", "@GUILE_LIBS@" }, \' >> libpath.tmp @echo '}' >> libpath.tmp @mv libpath.tmp libpath.h From ab4cd34b26e3605127b3e52b12ce5770eba39268 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Thu, 16 Aug 2001 03:44:29 +0000 Subject: [PATCH 34/46] *** empty log message *** --- ChangeLog | 23 +++++++ HACKING | 146 ++++++++++++++++++++++++++++++++++++++++++++- README | 4 +- RELEASE | 114 ++++++++++++++++++++++++++--------- libguile/ChangeLog | 6 ++ qt/ChangeLog | 5 ++ 6 files changed, 267 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2f5f0ce81..36c92fbe7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2001-08-15 Rob Browning + + * configure.in + (LIBGUILE_INTERFACE_CURRENT): use libtool versioning scheme. + (LIBGUILE_INTERFACE_REVISION): use libtool versioning scheme. + (LIBGUILE_INTERFACE_AGE): use libtool versioning scheme. + (LIBGUILE_INTERFACE): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE_CURRENT): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE_REVISION): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE_AGE): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE): use libtool versioning scheme. + + * GUILE-VERSION (GUILE_MINOR_VERSION): bump for new unstable. + (GUILE_MICRO_VERSION): reset for new unstable. + (LIBGUILE_INTERFACE_CURRENT): use libtool versioning scheme. + (LIBGUILE_INTERFACE_REVISION): use libtool versioning scheme. + (LIBGUILE_INTERFACE_AGE): use libtool versioning scheme. + (LIBGUILE_INTERFACE): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE_CURRENT): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE_REVISION): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE_AGE): use libtool versioning scheme. + (LIBGUILEQTHREADS_INTERFACE): use libtool versioning scheme. + 2001-08-07 Marius Vollmer * Makefile.am (EXTRA_DIST, SUBDIRS): Move test-suite from diff --git a/HACKING b/HACKING index 12ed66312..431c1ea55 100644 --- a/HACKING +++ b/HACKING @@ -1,3 +1,4 @@ +-*-text-*- Guile Hacking Guide Copyright (c) 1996, 1997, 1998, 1999, 2000, 2001 Free software Foundation, Inc. @@ -42,7 +43,7 @@ Autoconf 2.50 --- a system for automatically generating `configure' program would like to use. Available in "ftp://ftp.gnu.org/pub/gnu/autoconf" -Automake 1.4-p2 --- a system for automatically generating Makefiles that +Automake 1.4-p4 --- a system for automatically generating Makefiles that conform to the (rather Byzantine) GNU coding standards. The nice thing is that it takes care of hairy targets like 'make dist' and 'make distclean', and automatically generates @@ -112,9 +113,147 @@ The Guile sources live in several modules: - guile-rgx-ctax --- the Guile/Rx interface, and the ctax implementation - guile-scsh --- the port of SCSH to guile, talk to Gary Houston - guile-www --- A Guile module for making HTTP requests. + - guile-statprof --- an experimental statistical profiler. There is a mailing list for CVS commit messages; see README for details. +- The guile-core tree is now versioned similarly to the Linux kernel. +Guile now always uses three numbers to represent the version, +i.e. "1.6.5". The first number, 1, is the major version number, the +second number, 6, is the minor version number, and the third number, +5, is the micro version number. Changes in major version number +indicate major changes in Guile. + +Minor version numbers that are even denote stable releases, and odd +minor version numbers denote development versions (which may be +unstable). The micro version number indicates a minor sub-revision of +a given MAJOR.MINOR release. + +- A default CVS checkout will get the current unstable development +tree. However, for each stable release, a CVS branch is created so +that release (and ongoing maintenance) of the stable version can +proceed independent of the development of the next unstable version. +To check out a particular stable branch, you just need to specify "-r +branch_release-X-Y" to your CVS checkout command (or to any update). +For example, if you wanted to check out the 1.6 stable branch, you +would specify "-r branch_release-1-6". + +So, for example, during a normal development cycle, work will proceed +on an unstable version, say 1.5.X, until it is decided that it's time +for a stable release. At that point, a branch named +branch_release-1-6 will be created, and the version numbers on the +HEAD of the CVS tree (the trunk, i.e. what you get by default), will +be changed to reflect the new unstable version 1.7.X. Then unstable +development will proceed on the unstable version, while the stable +1.5.X branch is fixed up for the eventual 1.6.0 release. + +Anytime you want to yank an existing checked out tree to the stable +branch, you can run a command like this: + + cvs -z3 update -r branch_release-1-6 -Pd + +This will yank the working directory over on to the stable release +branch. Note that this directory will track that branch from then on +unless you do something to yank it back to the main (unstable) trunk. + +To go back to the unstable branch, you can use + + cvs -z3 update -A -Pd + +Note that in either case, you should probably make sure you've +commited or removed all local changes before running the commands or +you're likely to have some unexpected results. + +Finally note that one approach, should you need to work on both +branches, is to keep two trees checked out, one stable, the other +unstable and you can work in whichever is appropriate. + +To save some initial bandwidth, you can check out either the stable +tree or the unstable tree, and then do something like this: + + cp -a core-unstable core-1.5 + cd core-1.5 + cvs -z3 update -r branch_release-1-6 -Pd + +- The stable and unstable CVS trees are distinct, and no changes will +automatically propagate between them. If you make changes that need +to show up both places, you'll need to apply the changes both places. +You *might* be able to do this with a cvs command, but often you'll +probably need to apply the changes by hand or risk migrating +superfluous modifications between the two versions. This is +particularly important when moving a change from the unstable branch +to the stable branch. + +- In general, please don't be adventurous with the stable branch. We +mostly want bugfixes, documentation improvements, build improvements, +etc., though exceptions will doubtless exist. + +- There are a few CVS tagging conventions which follow the Scheme +convention that dashes are used to separate words within a single +symbol, and so dashes bind more tightly than underscores. This means +that foo-bar_baz-bax indicates that foo-bar is somehow separate from +baz-bax. The conventions are as follows: + + Branch root tags: + ----------------- + anytime just before you create a branch it's a good + idea to create a normal tag so that you can refer to the branch point + on the main trunk as well as on the branch. So please use a tag of + the form + + branch-root-release-1-X + + or more generally, for other non-release branches: + + branch-root_FOO + + Branch tags: + ------------ + for the branch tag itself please use + + branch_release-1-6 + + or more generally, for other non-release branches: + + branch_FOO + + Merge tags: + ----------- + Whenever you're merging a branch back into the trunk (or into another + branch repeatedly) you need to tag the branch each time you merge. If + you don't do that, you won't be able to merge repeatedly without + possibly tedious conflicts. For those tags, we suggest: + + branch-merge_SOME-FOO_to_SOME-BAR_1 + branch-merge_SOME-FOO_to_SOME-BAR_2 + .. + + As an example, SOME-BAR might be trunk, or even perhaps another branch + like branch-mvo-super-fixes :> + + More mundanely, you might have + + branch-merge_release-1-6_to_trunk_1 + + (Merging the stable branch to the trunk like this + will probably be much more common, when it happens, than the + reverse for the reasons mentioned above. + + Release tags: + ------------- + When releasing a new version of guile, please use: + + release_X-Y-Z + + i.e. + + release_1-6-0 + +- If you hack on a stable branch, please apply any relevant patches or +fixes to the current unstable version (the main CVS trunk) as well. +Similarly, please back-port any important fixes to the unstable CVS +tree to the current stable branch. + - We check Makefile.am and configure.in files into CVS, but the "autogen.sh" script must be run from the top-level to generate the actual "configure" script that then must be run to create the various @@ -167,6 +306,9 @@ GCC switches, which are the default in the current configure script: -O2 -Wall -Wpointer-arith -Wmissing-prototypes +To make sure of this, you can use the --enable-error-on-warning option +to configure. This option will make GCC fail if it hits a warning. + Note that the warnings generated vary from one version of GCC to the next, and from one architecture to the next (apparently). To provide a concrete common standard, Guile should compile without warnings from @@ -234,7 +376,7 @@ Sat Aug 3 01:27:14 1996 Gary Houston * * fports.c (scm_open_file): don't return #f, throw error. When you've written a NEWS entry and updated the documentation, go -ahead and remove the asterisk. I will use the asterisks to find and +ahead and remove the asterisk. The asterisks are used to find and document changes that haven't been dealt with before a release. - Please write log entries for functions written in C under the diff --git a/README b/README index 68313686f..47f0db224 100644 --- a/README +++ b/README @@ -3,7 +3,7 @@ anonymous CVS or as a nightly snapshot at some random time after the Guile 1.4 release. If this were a Guile release, you would not see this message. !!! [fixme: zonk on release] -This is a 1.5 development version of Guile, Project GNU's extension +This is a 1.7 development version of Guile, Project GNU's extension language library. Guile is an interpreter for Scheme, packaged as a library that you can link into your applications to give them their own scripting language. Guile will eventually support other languages @@ -14,7 +14,7 @@ Guile versions with an odd middle number, i.e. 1.5.* are unstable development versions. Even middle numbers indicate stable versions. This has been the case since the 1.3.* series. -The next stable release will be version 1.6.0. +The next stable release will be version 1.8.0. Please send bug reports to bug-guile@gnu.org. diff --git a/RELEASE b/RELEASE index cbd264cf8..76ab6f9c3 100644 --- a/RELEASE +++ b/RELEASE @@ -1,3 +1,4 @@ +-*-text-*- This is a checklist for making Guile releases. It's specific to the FSF's development environment; please don't put it in the distribution. @@ -43,7 +44,9 @@ Perry Metzger Release Checklists =================================================== -There are basically two phases to doing a release: +There are basically three phases to doing a release: + +* "BRANCHING": Creating a stable development branch in CVS. * "SPIFFING": Updating NEWS, README, INSTALL. Running tests. Getting people to try builds on various machines. Getting everything @@ -53,18 +56,37 @@ There are basically two phases to doing a release: the FSF to put the disty on ftp.gnu.org. Posting announcements. The "Spiffing" phase you might go through several times as you -discover problems. The "Punting" phase you do only once. +discover problems. The "Branching" and "Punting" phases you do only +once. +Branching checklist: -Spiffing checklist (NOTE: these instructions are out of date now that -we're using cvs branches for stable vs unstable). +* Announce when you're about to make the branch so that you have a + greater chance of people holding off on edits during the short + period while you're branching. + +* Make sure you're on the main trunk (see HACKING), and then create + the branch-root tag. i.e. -r branch-root_release-1-6. (Add the + exact command here next time I do it.) + +* Now create the branch with the branch tag. i.e. -r + branch_release-1-6. (Add exact command here next time I do it.) + +* Change the version numbers in GUILE-VERSION and README on the main + branch to reflect the new unstable version i.e. 1.7.0, if you're + currently creating the 1.6.X branch. + +Spiffing checklist: + +* Make sure you're working on the stable branch (see HACKING for + details). Note that after following the branch checklist above, you + won't necessarily be. -* Do a `cvs update -A', to get rid of any sticky tags in your working - directory. * Check for files that have changed a lot, but do not have up-to-date copyright notices. This can be as simple as doing: grep 'Copyright' * | grep -v 1999 and looking for files you know you've worked on a lot. + * Make sure NEWS, INSTALL, AUTHORS and THANKS and the docs are up to date: + Scan the ChangeLogs for user-visible changes, marked with an asterisk at the left margin. @@ -75,24 +97,30 @@ we're using cvs branches for stable vs unstable). + Fact-check INSTALL. + Make sure AUTHORS and THANKS are up-to-date (see also TODO). + Remove finished items from TODO (those marked w/ "+"). + * Make sure the downloading addresses and filenames in README are current. (But don't bump the version number yet. We do that below.) + * Check that the versions of aclocal, automake, autoconf, and autoheader in your PATH match those given in HACKING. Note that the `make dist' process always invokes these tools, even when all the generated files are up to date. Make specifically sure that the files in libltdl are generated using the same tools as the rest. + * Rebuild all generated files in the source tree: - + Install the .m4 files where aclocal will find them. - + Run aclocal. - + Run autoconf. - + Run autoheader. - + Run automake. + + run ./autogen.sh + * Verify that Guile builds and runs in your working directory. -* Run the test suite, in guile-core/test-suite. + +* Run a "make check". + * Commit all changes to the CVS repository. + * Build a test distribution. + + update GUILE-VERSION each time you make a test distribution. For + example, just before the 1.6.0 release, we went through some + number of 1.5.X test releases. + BEFORE doing 'make dist', configure the source tree for build in the same tree with configuration options --enable-maintainer-mode --enable-debug-malloc --with-threads. @@ -105,6 +133,7 @@ we're using cvs branches for stable vs unstable). (We currently use a kludge which edits the dependencies generated by automake so that Guile can be built in a directory separate from the source tree also with non-GNU make programs.) + * Give the test disty to various people to try. Here's what you should do: + Unset GUILE_LOAD_PATH. + Remove automake and autoconf from your path, or turn off their @@ -117,39 +146,70 @@ we're using cvs branches for stable vs unstable). Once you've got a disty that seems pretty solid: -* Choose new interface numbers for shared libraries. -* Update the version numbers in GUILE-VERSION and README. (There are - many places in README that need updating!) The Guile version - number should have one of the following forms: - N.M - a major release - N.M.L, where L is even - a minor release - N.M.L, where L is odd - sources from CVS or nightly snapshot +* Make sure the shared library libtool versioning numbers are correct, + but first make sure you understand "Libtool's versioning system" in + the libtool info pages. Guile is going to be versioning it's shared + libraries independently, so follow the libtool rules for choosing + version numbers, but make sure to keep in mind that not everyone is + as good about this as they should be. If a library even changes the + layout of a data structure that's part of it's API in a backward + incompatible way, even if that data structure is handled as an + opaque object in the API, that library is probably no longer + compatible with previous versions. + + A canonical ugly problem is this. Imagine you have libfoo and + libbar that both are linked against libbaz. Now imagine that you + create a libwhatever that uses both libfoo and libbar. What you + don't want to have happen is libfoo and libbar to be linked against + different versions of libbaz that produce incompatible instances of + the "same" data structure, and then have libwhatever get one version + of this data structure from libbaz via libfoo, and pass it back to a + different version of libbaz via libbar, a version of libbaz that + can't handle the newer/older struct from the other libbaz. + +* In general, there will be a number of libraries in guile that will + have to be versioned, and it would be best if the people who know + the most about the individual libs decide what the apropriate + CURRENT, REVISION, and AGE numbers for each one are. In general, + though, you have to be conservative. If no one is sure that the + libs are still compatible, then you *must* make the appropriate + changes under the assumption that they're not. Getting this wrong + is very BAD(TM). + +* Make the final update to the version numbers in GUILE-VERSION and + README. (There are many places in README that need updating!). See + HACKING for more information on how the version numbers are to be + chosen. + * Reformat the names in THANKS. -* Do a `cvs update -A' of the whole tree, to look for any stray + +* Do a `cvs -z3 update -Pd' of the whole tree, to look for any stray uncommitted or accidental changes. + * Commit your changes. + * Make one last test distribution. Punting checklist: * Add "Guile N.M released." entry to the top-level ChangeLog, and commit it. -* Tag the entire source tree with a tag of the form "release_N_M" - or "release_N_M_L". + +* Tag the entire source tree with a tag of the form "release_X-Y-Z", + i.e for release 1.6.0, use release_1-6-0 + * Do a 'make dist'. + * Put the distribution up for FTP somewhere, and send mail to ftp-upload@gnu.org, asking them to put it on prep. + * Send an announcement message to gnu-announce@gnu.org. Put a brief summary of the changes in this release first, then "Obtaining Guile", "Thanks", "About This Distribution," and "Nightly Snapshots." If I remember correctly, the moderator will delay it until the distribution appears on ftp.gnu.org. The announcement text should be mostly taken from Guile's README file. + * Notify freshmeat.net, although they're probably watching anyway. (They got the 1.3 release just fine.) I have no idea if www.bowerbird.com.au will be something anyone refers to, but Guile does have an entry there. -* Tweak the version numbers in GUILE-VERSION, and README to indicate - that the sources are a snapshot again. Snapshots should have - version numbers of the form "N.M.L", where L is odd. -* Start a new section of the NEWS file. -* Start a new THANKS file. diff --git a/libguile/ChangeLog b/libguile/ChangeLog index f46645a44..d7420768d 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,9 @@ +2001-08-15 Rob Browning + + * Makefile.am (libguile_la_LDFLAGS): use libtool interface version + variables. + (libpath.h): change libguileversion to libguileinterface. + 2001-08-07 Marius Vollmer * Makefile.am (EXTRA_DIST): Distribute ChangeLog-1996-1999 and diff --git a/qt/ChangeLog b/qt/ChangeLog index 93ef31ee8..2550d9d59 100644 --- a/qt/ChangeLog +++ b/qt/ChangeLog @@ -1,3 +1,8 @@ +2001-08-15 Rob Browning + + * Makefile.am (libqthreads_la_LDFLAGS): use libtool interface version + variables. + 2000-06-12 Mikael Djurfeldt * Makefile.am (OMIT_DEPENDENCIES): Defined to contain the list of From 65e43ca6d385f646f1d3b5b9ba9116c541ddff6e Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Thu, 16 Aug 2001 03:44:36 +0000 Subject: [PATCH 35/46] * Makefile.am (libqthreads_la_LDFLAGS): use libtool interface version variables. --- qt/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/Makefile.am b/qt/Makefile.am index 2ba31b93e..ab0aa3cb6 100644 --- a/qt/Makefile.am +++ b/qt/Makefile.am @@ -34,7 +34,7 @@ INCLUDES = -I.. -I$(srcdir)/.. libqthreads_la_SOURCES = qt.c copyright.h libqthreads_la_LIBADD = qtmds.lo qtmdc.lo libqthreads_la_DEPENDENCIES = qtmds.lo qtmdc.lo -libqthreads_la_LDFLAGS = -rpath $(libdir) +libqthreads_la_LDFLAGS = -rpath $(libdir) -version-info @LIBGUILEQTHREADS_INTERFACE_CURRENT@:@LIBGUILEQTHREADS_INTERFACE_REVISION@:@LIBGUILEQTHREADS_INTERFACE_AGE@ -export-dynamic OMIT_DEPENDENCIES = axp.h hppa.h i386.h ksr.h m88k.h mips.h sparc.h vax.h From eae3393547e5df6ab3dd0cceadce455ef9569ec2 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Fri, 17 Aug 2001 23:45:29 +0000 Subject: [PATCH 36/46] Fix omission bug: Add `heap_segment' forward decl (proto) in the case when either `GUILE_DEBUG' or `GUILE_DEBUG_FREELIST' preprocessor symbols are defined. (map_free_list): Fix typo: Ref `f' correctly. Thanks to Chris Cramer. --- libguile/gc.c | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/libguile/gc.c b/libguile/gc.c index 83b9263e6..b7a0defbf 100644 --- a/libguile/gc.c +++ b/libguile/gc.c @@ -102,7 +102,7 @@ unsigned int scm_gc_running_p = 0; scm_t_bits scm_tc16_allocated; -/* Set this to != 0 if every cell that is accessed shall be checked: +/* Set this to != 0 if every cell that is accessed shall be checked: */ unsigned int scm_debug_cell_accesses_p = 1; @@ -172,7 +172,7 @@ scm_assert_cell_valid (SCM cell) if (debug_cells_gc_interval) { static unsigned int counter = 0; - + if (counter != 0) { --counter; @@ -528,6 +528,8 @@ clear_mark_space () #if defined (GUILE_DEBUG) || defined (GUILE_DEBUG_FREELIST) +static long int heap_segment (SCM obj); /* forw decl: non-debugging func */ + static void map_free_list (scm_t_freelist *master, SCM freelist) { @@ -540,9 +542,9 @@ map_free_list (scm_t_freelist *master, SCM freelist) if (this_seg == -1) { - fprintf (stderr, + fprintf (stderr, "map_free_list: can't find segment containing cell %lux\n", - (unsigned long int) SCM_UNPACK (cell)); + (unsigned long int) SCM_UNPACK (f)); abort (); } else if (this_seg != last_seg) @@ -656,7 +658,7 @@ SCM_DEFINE (scm_free_list_length, "free-list-length", 0, 0, 0, } #undef FUNC_NAME -#endif +#endif /* defined (GUILE_DEBUG) || defined (GUILE_DEBUG_FREELIST) */ #ifdef GUILE_DEBUG_FREELIST @@ -1185,7 +1187,7 @@ MARK (SCM p) #else /* go through the usual marking, but not for self-cycles. */ # define RECURSE(x) do { if ((x) != p) scm_gc_mark (x); } while (0) -#endif +#endif ptr = p; #ifdef MARK_DEPENDENCIES @@ -1208,7 +1210,7 @@ gc_mark_loop: return; gc_mark_nimp: - + #ifdef MARK_DEPENDENCIES if (SCM_EQ_P (ptr, p)) return; @@ -1230,10 +1232,10 @@ gc_mark_loop_first_time: #endif #ifndef MARK_DEPENDENCIES - + if (SCM_GCMARKP (ptr)) return; - + SCM_SETGCMARK (ptr); #endif @@ -1275,7 +1277,7 @@ gc_mark_loop_first_time: if (len) { long x; - + for (x = 0; x < len - 2; x += 2, ++struct_data) if (fields_desc[x] == 'p') RECURSE (SCM_PACK (*struct_data)); @@ -1451,7 +1453,7 @@ gc_mark_loop_first_time: * Thus, no conservative scanning for free cells is necessary, but * instead cells of type scm_tc16_allocated have to be scanned * conservatively. This is done in the mark function of the - * scm_tc16_allocated smob type. */ + * scm_tc16_allocated smob type. */ #endif break; case scm_tc16_big: @@ -1908,7 +1910,7 @@ scm_gc_sweep () scm_cells_allocated = (SCM_HEAP_SIZE - scm_gc_cells_collected); scm_gc_yield -= scm_cells_allocated; - + if (scm_mallocated < m) /* The byte count of allocated objects has underflowed. This is probably because you forgot to report the sizes of objects you @@ -1974,7 +1976,7 @@ scm_must_malloc (size_t size, const char *what) scm_igc (what); nm = scm_mallocated + size; - + if (nm < size) /* The byte count of allocated objects has overflowed. This is probably because you forgot to report the correct size of freed @@ -2130,7 +2132,7 @@ scm_done_malloc (long size) memory in some of your smob free methods. */ abort (); } - + scm_mallocated += size; if (scm_mallocated > scm_mtrigger) @@ -2239,7 +2241,7 @@ init_heap_seg (SCM_CELLPTR seg_org, size_t size, scm_t_freelist *freelist) /* Find the right place and insert the segment record. */ new_seg_index = 0; - while (new_seg_index < scm_n_heap_segs + while (new_seg_index < scm_n_heap_segs && SCM_PTR_LE (scm_heap_table[new_seg_index].bounds[0], seg_org)) new_seg_index++; @@ -2627,7 +2629,7 @@ scm_gc_register_root (SCM *p) { SCM handle; SCM key = scm_long2num ((long) p); - + /* This critical section barrier will be replaced by a mutex. */ SCM_REDEFER_INTS; @@ -2877,7 +2879,7 @@ mark_gc_async (void * hook_data SCM_UNUSED, * the execution of the next gc. Then, guile would keep executing the * after-gc-hook over and over again, and would never come to do other * things. - * + * * To overcome this problem, if cell access debugging with additional * garbage collections is enabled, the after-gc-hook is never run by the * garbage collecter. When running guile with cell access debugging and the From 43b83b541d7e1b05dfc1356e6e4afe75649b0f97 Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Fri, 17 Aug 2001 23:50:02 +0000 Subject: [PATCH 37/46] *** empty log message *** --- libguile/ChangeLog | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/libguile/ChangeLog b/libguile/ChangeLog index d7420768d..20191a9bd 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,13 @@ +2001-08-17 Thien-Thi Nguyen + + * gc.c: Fix omission bug: Add `heap_segment' forward decl + (proto) in the case when either `GUILE_DEBUG' or + `GUILE_DEBUG_FREELIST' preprocessor symbols are defined. + + (map_free_list): Fix typo: Ref `f' correctly. + + Thanks to Chris Cramer. + 2001-08-15 Rob Browning * Makefile.am (libguile_la_LDFLAGS): use libtool interface version @@ -82,7 +92,7 @@ 2001-07-29 Marius Vollmer Removed vcell slot from structs. - + * struct.h (scm_vtable_index_vcell): Removed. Renumbered subsequent indices. @@ -104,7 +114,7 @@ 2001-07-26 Marius Vollmer "Glocs" have been removed. - + * tags.h: Update tag system docs. (scm_tc3_cons_gloc): Renamed to scm_tc3_struct. Changed all uses. (scm_tcs_cons_gloc): Renamed to scm_tcs_struct. Changed all uses. @@ -117,7 +127,7 @@ * print.c (scm_iprin1): Remove printing of glocs. Do not try to tell glocs from structs. - + * gc.c (scm_gc_mark, scm_gc_sweep): Remove handling of glocs. * eval.c (scm_m_atbind): Make a list of variables, not glocs. @@ -130,7 +140,7 @@ (scm_m_atfop): Memoize as a variable, not as a gloc. (scm_eval_args, scm_deval_args): Do not handle glocs. (scm_ceval, scm_deval): Likewise. - + * eval.h (SCM_XEVALCAR): Do not test for glocs. (SCM_GLOC_VAR, SCM_GLOC_VAL, SCM_GLOC_SET_VAL, SCM_GLOC_VAL_LOC): Removed. @@ -143,10 +153,10 @@ * __scm.h (SCM_CAUTIOS, SCM_RECKLESS): Update comments. - + * gc_os_dep.c (GC_noop1): Moved into the same #if/#endif context where it is needed. - + 2001-07-25 Gary Houston * numbers.c (scm_logand, scm_logior, scm_logxor): adjusted the @@ -186,7 +196,7 @@ (variable_equal_p): Removed. (make_variable): Construct a tc7 object instead of a smob. (scm_init_variable): Do not register smob. - + 2001-07-22 Marius Vollmer * tags.h: Include inttypes.h when we have it. @@ -196,7 +206,7 @@ * tags.h (SCM_UNBOUND): Make it the 34th isym/iflag, the 33th slot is taken by the new SCM_IM_CALL_WITH_VALUES. * print.c (scm_isymnames): Update table accordingly. - + 2001-07-22 Gary Houston * regex-posix.c (s_scm_regexp_exec): use scm_long2num not From a786db16b20bbd6cedaf4249f7584f6d0861a5b5 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Sat, 18 Aug 2001 03:06:09 +0000 Subject: [PATCH 38/46] * .cvsignore: rename stamp-vti1 to stamp-vti.1. Of course this only matters once you fix the bug in automake. --- doc/.cvsignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/.cvsignore b/doc/.cvsignore index a73aeda2b..8eaa8267a 100644 --- a/doc/.cvsignore +++ b/doc/.cvsignore @@ -1,7 +1,7 @@ Makefile Makefile.in stamp-vti -stamp-vti1 +stamp-vti.1 *.log *.dvi *.aux From 8098fca9318e5fd1fbb0aa9ebf18c1d395ad8a0c Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Sat, 18 Aug 2001 03:06:18 +0000 Subject: [PATCH 39/46] *** empty log message *** --- RELEASE | 13 +++++++++++-- doc/ChangeLog | 8 ++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/RELEASE b/RELEASE index 76ab6f9c3..8289964da 100644 --- a/RELEASE +++ b/RELEASE @@ -118,17 +118,26 @@ Spiffing checklist: * Commit all changes to the CVS repository. * Build a test distribution. + + update GUILE-VERSION each time you make a test distribution. For example, just before the 1.6.0 release, we went through some number of 1.5.X test releases. + + BEFORE doing 'make dist', configure the source tree for build - in the same tree with configuration options - --enable-maintainer-mode --enable-debug-malloc --with-threads. + in the same tree with these configuration options: + --enable-maintainer-mode + --enable-debug-malloc + --with-threads + --enable-error-on-warning + + Make sure that readline was enabled correctly. + + Build the tree. (If the above steps are not done, the dependencies won't be properly included in the generated Makefile.in files.) + + Then do 'make dist'. + + Check that the dependencies in guile-readline/Makefile look OK. (We currently use a kludge which edits the dependencies generated by automake so that Guile can be built in a directory separate diff --git a/doc/ChangeLog b/doc/ChangeLog index 3d6210db9..14763185a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,11 @@ +2001-08-17 Rob Browning + + * Makefile.am (guile_tut_TEXINFOS): remove guile-tut.texi. It's + already in info_TEXINFOS. + + * .cvsignore: rename stamp-vti1 to stamp-vti.1. Of course this + only matters once you fix the bug in automake. + 2001-08-02 Neil Jerram * scheme-debug.texi (Debugging): Improve `make-stack' doc by From 59cd9b0f6755bd000747950af8fd25212f514446 Mon Sep 17 00:00:00 2001 From: Rob Browning Date: Sat, 18 Aug 2001 03:06:26 +0000 Subject: [PATCH 40/46] * Makefile.am (guile_tut_TEXINFOS): remove guile-tut.texi. It's already in info_TEXINFOS. --- doc/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index c5b7156f3..edd481f66 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -38,7 +38,7 @@ guile_TEXINFOS = preface.texi intro.texi scheme-intro.texi \ extend.texi repl-modules.texi srfi-modules.texi misc-modules.texi \ AUTHORS -guile_tut_TEXINFOS = guile-tut.texi AUTHORS +guile_tut_TEXINFOS = AUTHORS goops_TEXINFOS = goops-tutorial.texi hierarchy.eps hierarchy.txt AUTHORS From cf504ee0cf7b5d3ebd28db334c1ccedab077b57a Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Sat, 18 Aug 2001 16:32:04 +0000 Subject: [PATCH 41/46] * Fix spelling mistake in comment. --- libguile/ChangeLog | 4 ++++ libguile/__scm.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libguile/ChangeLog b/libguile/ChangeLog index 20191a9bd..e19afc953 100644 --- a/libguile/ChangeLog +++ b/libguile/ChangeLog @@ -1,3 +1,7 @@ +2001-08-18 Neil Jerram + + * __scm.h (SCM_ENABLE_VCELLS): Fix spelling mistake in comment. + 2001-08-17 Thien-Thi Nguyen * gc.c: Fix omission bug: Add `heap_segment' forward decl diff --git a/libguile/__scm.h b/libguile/__scm.h index 2e1e3b611..bda6326f2 100644 --- a/libguile/__scm.h +++ b/libguile/__scm.h @@ -237,7 +237,7 @@ #endif /* If SCM_ENABLE_VCELLS is set to 1, a couple of functions that deal - * with vcells are defined for compatability reasons. Supporting + * with vcells are defined for compatibility reasons. Supporting * vcells reduces performance however. * * We use a dedicated macro instead of just SCM_DEBUG_DEPRECATED so From 88176879bff0b24f67bb995495c461a104b39281 Mon Sep 17 00:00:00 2001 From: Mikael Djurfeldt Date: Wed, 22 Aug 2001 09:57:35 +0000 Subject: [PATCH 42/46] * scheme-options.texi (Evaluator trap options): Splitted section "Evaluator options". * scheme-evaluation.texi (Evaluator Behaviour): Typo "reader options" --> "evaluator options". --- doc/ChangeLog | 8 + doc/scheme-evaluation.texi | 419 ------------------------------------- doc/scheme-options.texi | 342 ------------------------------ 3 files changed, 8 insertions(+), 761 deletions(-) diff --git a/doc/ChangeLog b/doc/ChangeLog index 14763185a..2f3cd2d11 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,11 @@ +2001-08-22 Mikael Djurfeldt + + * scheme-options.texi (Evaluator trap options): Splitted + section "Evaluator options". + + * scheme-evaluation.texi (Evaluator Behaviour): Typo "reader + options" --> "evaluator options". + 2001-08-17 Rob Browning * Makefile.am (guile_tut_TEXINFOS): remove guile-tut.texi. It's diff --git a/doc/scheme-evaluation.texi b/doc/scheme-evaluation.texi index 5a0f861ff..e69de29bb 100644 --- a/doc/scheme-evaluation.texi +++ b/doc/scheme-evaluation.texi @@ -1,419 +0,0 @@ -@page -@node Read/Load/Eval -@chapter Reading and Evaluating Scheme Code - -This chapter describes Guile functions that are concerned with reading, -loading and evaluating Scheme code at run time. - -@menu -* Scheme Syntax:: Standard and extended Scheme syntax. -* Scheme Read:: Reading Scheme code. -* Fly Evaluation:: Procedures for on the fly evaluation. -* Loading:: Loading Scheme code from file. -* Delayed Evaluation:: Postponing evaluation until it is needed. -* Local Evaluation:: Evaluation in a local environment. -* Evaluator Behaviour:: Modifying Guile's evaluator. -@end menu - - -@node Scheme Syntax -@section Scheme Syntax: Standard and Guile Extensions - -@menu -* Expression Syntax:: -* Comments:: -* Block Comments:: -* Case Sensitivity:: -* Keyword Syntax:: -* Reader Extensions:: -@end menu - - -@node Expression Syntax -@subsection Expression Syntax - - -@node Comments -@subsection Comments - -@c FIXME::martin: Review me! - -Comments in Scheme source files are written by starting them with a -semicolon character (@code{;}). The comment then reaches up to the end -of the line. Comments can begin at any column, and the may be inserted -on the same line as Scheme code. - -@lisp -; Comment -;; Comment too -(define x 1) ; Comment after expression -(let ((y 1)) - ;; Display something. - (display y) -;;; Comment at left margin. - (display (+ y 1))) -@end lisp - -It is common to use a single semicolon for comments following -expressions on a line, to use two semicolons for comments which are -indented like code, and three semicolons for comments which start at -column 0, even if they are inside an indented code block. This -convention is used when indenting code in Emacs' Scheme mode. - - -@node Block Comments -@subsection Block Comments - -@c FIXME::martin: Review me! - -@cindex multiline comments -In addition to the standard line comments defined by R5RS, Guile has -another comment type for multiline comments, called @dfn{block -comments}. This type of comment begins with the character sequence -@code{#!} and ends with the characters @code{!#}, which must appear on a -line of their own. These comments are compatible with the block -comments in the Scheme Shell @file{scsh} (@pxref{The Scheme shell -(scsh)}). The characters @code{#!} were chosen because they are the -magic characters used in shell scripts for indicating that the name of -the program for executing the script follows on the same line. - -Thus a Guile script often starts like this. - -@lisp -#! /usr/local/bin/guile -s -!# -@end lisp - -More details on Guile scripting can be found in the scripting section -(@pxref{Guile Scripting}). - - -@node Case Sensitivity -@subsection Case Sensitivity - -@c FIXME::martin: Review me! - -Scheme as defined in R5RS is not case sensitive when reading symbols. -Guile, on the contrary is case sensitive by default, so the identifiers - -@lisp -guile-whuzzy -Guile-Whuzzy -@end lisp - -are the same in R5RS Scheme, but are different in Guile. - -It is possible to turn off case sensitivity in Guile by setting the -reader option @code{case-insensitive}. More on reader options can be -found at (@pxref{Reader options}). - -@lisp -(read-enable 'case-insensitive) -@end lisp - -Note that this is seldom a problem, because Scheme programmers tend not -to use uppercase letters in their identifiers anyway. - - -@node Keyword Syntax -@subsection Keyword Syntax - - -@node Reader Extensions -@subsection Reader Extensions - -@deffn primitive read-hash-extend chr proc -Install the procedure @var{proc} for reading expressions -starting with the character sequence @code{#} and @var{chr}. -@var{proc} will be called with two arguments: the character -@var{chr} and the port to read further data from. The object -returned will be the return value of @code{read}. -@end deffn - - -@node Scheme Read -@section Reading Scheme Code - -@rnindex read -@deffn primitive read [port] -Read an s-expression from the input port @var{port}, or from -the current input port if @var{port} is not specified. -Any whitespace before the next token is discarded. -@end deffn - -The behaviour of Guile's Scheme reader can be modified by manipulating -its read options. For more information about options, @xref{General -option interface}. If you want to know which reader options are -available, @xref{Reader options}. - -@c FIXME::martin: This is taken from libguile/options.c. Is there -@c actually a difference between 'help and 'full? - -@deffn procedure read-options [setting] -Display the current settings of the read options. If @var{setting} is -omitted, only a short form of the current read options is printed. -Otherwise, @var{setting} should be one of the following symbols: -@table @code -@item help -Display the complete option settings. -@item full -Like @code{help}, but also print programmer options. -@end table -@end deffn - -@deffn procedure read-enable option-name -@deffnx procedure read-disable option-name -@deffnx procedure read-set! option-name value -Modify the read options. @code{read-enable} should be used with boolean -options and switches them on, @code{read-disable} switches them off. -@code{read-set!} can be used to set an option to a specific value. -@end deffn - -@deffn primitive read-options-interface [setting] -Option interface for the read options. Instead of using -this procedure directly, use the procedures @code{read-enable}, -@code{read-disable}, @code{read-set!} and @code{read-options}. -@end deffn - - -@node Fly Evaluation -@section Procedures for On the Fly Evaluation - -@rnindex eval -@c ARGFIXME environment/environment specifier -@deffn primitive eval exp environment -Evaluate @var{exp}, a list representing a Scheme expression, in the -environment given by @var{environment specifier}. -@end deffn - -@rnindex interaction-environment -@deffn primitive interaction-environment -Return a specifier for the environment that contains -implementation--defined bindings, typically a superset of those -listed in the report. The intent is that this procedure will -return the environment in which the implementation would -evaluate expressions dynamically typed by the user. -@end deffn - -@deffn primitive eval-string string -Evaluate @var{string} as the text representation of a Scheme -form or forms, and return whatever value they produce. -Evaluation takes place in the environment returned by the -procedure @code{interaction-environment}. -@end deffn - -@deffn primitive apply:nconc2last lst -Given a list (@var{arg1} @dots{} @var{args}), this function -conses the @var{arg1} @dots{} arguments onto the front of -@var{args}, and returns the resulting list. Note that -@var{args} is a list; thus, the argument to this function is -a list whose last element is a list. -Note: Rather than do new consing, @code{apply:nconc2last} -destroys its argument, so use with care. -@end deffn - -@rnindex apply -@deffn primitive apply proc arg1 @dots{} args -@var{proc} must be a procedure and @var{args} must be a list. Call -@var{proc} with the elements of the list @code{(append (list @var{arg1} -@dots{}) @var{args})} as the actual arguments. -@end deffn - -@deffn primitive primitive-eval exp -Evaluate @var{exp} in the top-level environment specified by -the current module. -@end deffn - -@deffn primitive eval2 obj env_thunk -Evaluate @var{exp}, a Scheme expression, in the environment -designated by @var{lookup}, a symbol-lookup function. -Do not use this version of eval, it does not play well -with the module system. Use @code{eval} or -@code{primitive-eval} instead. -@end deffn - -@deffn primitive read-and-eval! [port] -Read a form from @var{port} (standard input by default), and evaluate it -(memoizing it in the process) in the top-level environment. If no data -is left to be read from @var{port}, an @code{end-of-file} error is -signalled. -@end deffn - - -@node Loading -@section Loading Scheme Code from File - -@rnindex load -@deffn procedure load filename -Load @var{filename} and evaluate its contents in the top-level -environment. The load paths are not searched. If the variable -@code{%load-hook} is defined, it should be bound to a procedure that -will be called before any code is loaded. See documentation for -@code{%load-hook} later in this section. -@end deffn - -@deffn procedure load-from-path filename -Similar to @code{load}, but searches for @var{filename} in the load -paths. -@end deffn - -@deffn primitive primitive-load filename -Load the file named @var{filename} and evaluate its contents in -the top-level environment. The load paths are not searched; -@var{filename} must either be a full pathname or be a pathname -relative to the current directory. If the variable -@code{%load-hook} is defined, it should be bound to a procedure -that will be called before any code is loaded. See the -documentation for @code{%load-hook} later in this section. -@end deffn - -@deffn primitive primitive-load-path filename -Search @var{%load-path} for the file named @var{filename} and -load it into the top-level environment. If @var{filename} is a -relative pathname and is not found in the list of search paths, -an error is signalled. -@end deffn - -@deffn primitive %search-load-path filename -Search @var{%load-path} for the file named @var{filename}, -which must be readable by the current user. If @var{filename} -is found in the list of paths to search or is an absolute -pathname, return its full pathname. Otherwise, return -@code{#f}. Filenames may have any of the optional extensions -in the @code{%load-extensions} list; @code{%search-load-path} -will try each extension automatically. -@end deffn - -@defvar %load-hook -A procedure to be run whenever @code{primitive-load} is called. If this -procedure is defined, it will be called with the filename argument that -was passed to @code{primitive-load}. - -@example -(define %load-hook (lambda (file) - (display "Loading ") - (display file) - (write-line "...."))) @result{} undefined -(load-from-path "foo.scm") -@print{} Loading /usr/local/share/guile/site/foo.scm.... -@end example - -@end defvar - -@deffn primitive current-load-port -Return the current-load-port. -The load port is used internally by @code{primitive-load}. -@end deffn - -@defvar %load-extensions -A list of default file extensions for files containing Scheme code. -@code{%search-load-path} tries each of these extensions when looking for -a file to load. By default, @code{%load-extensions} is bound to the -list @code{("" ".scm")}. -@end defvar - - -@node Delayed Evaluation -@section Delayed Evaluation - -[delay] - -@deffn primitive promise? obj -Return true if @var{obj} is a promise, i.e. a delayed computation -(@pxref{Delayed evaluation,,,r5rs.info,The Revised^5 Report on Scheme}). -@end deffn - -@rnindex force -@deffn primitive force x -If the promise @var{x} has not been computed yet, compute and -return @var{x}, otherwise just return the previously computed -value. -@end deffn - - -@node Local Evaluation -@section Local Evaluation - -[the-environment] - -@deffn primitive local-eval exp [env] -Evaluate @var{exp} in its environment. If @var{env} is supplied, -it is the environment in which to evaluate @var{exp}. Otherwise, -@var{exp} must be a memoized code object (in which case, its environment -is implicit). -@end deffn - - -@node Evaluator Behaviour -@section Evaluator Behaviour - -@c FIXME::martin: Maybe this node name is bad, but the old name clashed with -@c `Evaluator options' under `Options and Config'. - -The behaviour of Guile's evaluator can be modified by manipulating the -evaluator options. For more information about options, @xref{General -option interface}. If you want to know which reader options are -available, @xref{Evaluator options}. - -@c FIXME::martin: This is taken from libguile/options.c. Is there -@c actually a difference between 'help and 'full? - -@deffn procedure eval-options [setting] -Display the current settings of the evaluator options. If @var{setting} -is omitted, only a short form of the current evaluator options is -printed. Otherwise, @var{setting} should be one of the following -symbols: -@table @code -@item help -Display the complete option settings. -@item full -Like @code{help}, but also print programmer options. -@end table -@end deffn - -@deffn procedure eval-enable option-name -@deffnx procedure eval-disable option-name -@deffnx procedure eval-set! option-name value -Modify the evaluator options. @code{eval-enable} should be used with boolean -options and switches them on, @code{eval-disable} switches them off. -@code{eval-set!} can be used to set an option to a specific value. -@end deffn - -@deffn primitive eval-options-interface [setting] -Option interface for the evaluation options. Instead of using -this procedure directly, use the procedures @code{eval-enable}, -@code{eval-disable}, @code{eval-set!} and @code{eval-options}. -@end deffn - -@c FIXME::martin: Why aren't these procedure named like the other options -@c procedures? - -@deffn procedure traps [setting] -Display the current settings of the evaluator traps options. If -@var{setting} is omitted, only a short form of the current evaluator -traps options is printed. Otherwise, @var{setting} should be one of the -following symbols: -@table @code -@item help -Display the complete option settings. -@item full -Like @code{help}, but also print programmer options. -@end table -@end deffn - -@deffn procedure trap-enable option-name -@deffnx procedure trap-disable option-name -@deffnx procedure trap-set! option-name value -Modify the evaluator options. @code{trap-enable} should be used with boolean -options and switches them on, @code{trap-disable} switches them off. -@code{trap-set!} can be used to set an option to a specific value. -@end deffn - -@deffn primitive evaluator-traps-interface [setting] -Option interface for the evaluator trap options. -@end deffn - - -@c Local Variables: -@c TeX-master: "guile.texi" -@c End: diff --git a/doc/scheme-options.texi b/doc/scheme-options.texi index 4e711764a..e69de29bb 100644 --- a/doc/scheme-options.texi +++ b/doc/scheme-options.texi @@ -1,342 +0,0 @@ -@page -@node Options and Config -@chapter Runtime Options and Configuration - -Guile's behaviour can be modified by setting options. For example, is -the language that Guile accepts case sensitive, or should the debugger -automatically show a backtrace on error? - -Guile has two levels of interface for managing options: a low-level -control interface, and a user-level interface which allows the enabling -or disabling of options. - -Moreover, the options are classified in groups according to whether they -configure @emph{reading}, @emph{printing}, @emph{debugging} or -@emph{evaluating}. - -@menu -* General option interface:: -* Reader options:: -* Printing options:: -* Debugger options:: -* Evaluator options:: -* Examples of option use:: -* Install Config:: Installation and configuration data. -@end menu - -@node General option interface -@section General option interface - -We will use the expression @code{} to represent @code{read}, -@code{print}, @code{debug} or @code{evaluator}. - -@subheading Low level - -@c NJFIXME -@deffn primitive -options-interface -@deffnx primitive read-options-interface [SOME-INT] -@deffnx primitive print-options-interface [SOME-INT] -@deffnx primitive evaluator-traps-interface [SOME-INT] -@deffnx primitive read-options-interface [SOME-INT] -[FIXME: I have just taken the comments for C routine scm_options that -implements all of these. It needs to be presented better.] - -If scm_options is called without arguments, the current option setting -is returned. If the argument is an option setting, options are altered -and the old setting is returned. If the argument isn't a list, a list -of sublists is returned, where each sublist contains option name, value -and documentation string. -@end deffn - - -@subheading User level - -@c @deftp {Data type} scm_option -@c @code{scm_option} is used to represent run time options. It can be a -@c @emph{boolean} type, in which case the option will be set by the strings -@c @code{"yes"} and @code{"no"}. It can be a -@c @end deftp - -@c NJFIXME -@deffn procedure -options [arg] -@deffnx procedure read-options [arg] -@deffnx procedure print-options [arg] -@deffnx procedure debug-options [arg] -@deffnx procedure traps [arg] -These functions list the options in their group. The optional argument -@var{arg} is a symbol which modifies the form in which the options are -presented. - -With no arguments, @code{-options} returns the values of the -options in that particular group. If @var{arg} is @code{'help}, a -description of each option is given. If @var{arg} is @code{'full}, -programmers' options are also shown. - -@var{arg} can also be a list representing the state of all options. In -this case, the list contains single symbols (for enabled boolean -options) and symbols followed by values. -@end deffn -[FIXME: I don't think 'full is ever any different from 'help. What's -up?] - -@c NJFIXME -@deffn procedure -enable option-symbol -@deffnx procedure read-enable option-symbol -@deffnx procedure print-enable option-symbol -@deffnx procedure debug-enable option-symbol -@deffnx procedure trap-enable option-symbol -These functions set the specified @var{option-symbol} in their options -group. They only work if the option is boolean, and throw an error -otherwise. -@end deffn - -@c NJFIXME -@deffn procedure -disable option-symbol -@deffnx procedure read-disable option-symbol -@deffnx procedure print-disable option-symbol -@deffnx procedure debug-disable option-symbol -@deffnx procedure trap-disable option-symbol -These functions turn off the specified @var{option-symbol} in their -options group. They only work if the option is boolean, and throw an -error otherwise. -@end deffn - -@c NJFIXME -@deffn syntax -set! option-symbol value -@deffnx syntax read-set! option-symbol value -@deffnx syntax print-set! option-symbol value -@deffnx syntax debug-set! option-symbol value -@deffnx syntax trap-set! option-symbol value -These functions set a non-boolean @var{option-symbol} to the specified -@var{value}. -@end deffn - - -@node Reader options -@section Reader options -@cindex options - read -@cindex read options - -Here is the list of reader options generated by typing -@code{(read-options 'full)} in Guile. You can also see the default -values. - -@smalllisp -keywords #f Style of keyword recognition: #f or 'prefix -case-insensitive no Convert symbols to lower case. -positions yes Record positions of source code expressions. -copy no Copy source code expressions. -@end smalllisp - -Notice that while Standard Scheme is case insensitive, to ease -translation of other Lisp dialects, notably Emacs Lisp, into Guile, -Guile is case-sensitive by default. - -To make Guile case insensitive, you can type - -@smalllisp -(read-enable 'case-insensitive) -@end smalllisp - -@node Printing options -@section Printing options - -Here is the list of print options generated by typing -@code{(print-options 'full)} in Guile. You can also see the default -values. - -@smallexample -source no Print closures with source. -closure-hook #f Hook for printing closures. -@end smallexample - - -@node Evaluator options -@section Evaluator options - -These are the evaluator options with their default values, as they are -printed by typing @code{(eval-options 'full)} in Guile. - -@smallexample -stack 22000 Size of thread stacks (in machine words). -@end smallexample - -Here is the list of evaluator trap options generated by typing -@code{(traps 'full)} in Guile. You can also see the default values. - -@smallexample -exit-frame no Trap when exiting eval or apply. -apply-frame no Trap when entering apply. -enter-frame no Trap when eval enters new frame. -@end smallexample - - -@node Debugger options -@section Debugger options - -Here is the list of print options generated by typing -@code{(debug-options 'full)} in Guile. You can also see the default -values. - -@smallexample -stack 20000 Stack size limit (0 = no check). -debug yes Use the debugging evaluator. -backtrace no Show backtrace on error. -depth 20 Maximal length of printed backtrace. -maxdepth 1000 Maximal number of stored backtrace frames. -frames 3 Maximum number of tail-recursive frames in backtrace. -indent 10 Maximal indentation in backtrace. -backwards no Display backtrace in anti-chronological order. -procnames yes Record procedure names at definition. -trace no *Trace mode. -breakpoints no *Check for breakpoints. -cheap yes *Flyweight representation of the stack at traps. -@end smallexample - - -@node Examples of option use -@section Examples of option use - -Here is an example of a session in which some read and debug option -handling procedures are used. In this example, the user - -@enumerate -@item -Notices that the symbols @code{abc} and @code{aBc} are not the same -@item -Examines the @code{read-options}, and sees that @code{case-insensitive} -is set to ``no''. -@item -Enables @code{case-insensitive} -@item -Verifies that now @code{aBc} and @code{abc} are the same -@item -Disables @code{case-insensitive} and enables debugging @code{backtrace} -@item -Reproduces the error of displaying @code{aBc} with backtracing enabled -[FIXME: this last example is lame because there is no depth in the -backtrace. Need to give a better example, possibly putting debugging -option examples in a separate session.] -@end enumerate - - -@smalllisp -guile> (define abc "hello") -guile> abc -"hello" -guile> aBc -ERROR: In expression aBc: -ERROR: Unbound variable: aBc -ABORT: (misc-error) - -Type "(backtrace)" to get more information. -guile> (read-options 'help) -keywords #f Style of keyword recognition: #f or 'prefix -case-insensitive no Convert symbols to lower case. -positions yes Record positions of source code expressions. -copy no Copy source code expressions. -guile> (debug-options 'help) -stack 20000 Stack size limit (0 = no check). -debug yes Use the debugging evaluator. -backtrace no Show backtrace on error. -depth 20 Maximal length of printed backtrace. -maxdepth 1000 Maximal number of stored backtrace frames. -frames 3 Maximum number of tail-recursive frames in backtrace. -indent 10 Maximal indentation in backtrace. -backwards no Display backtrace in anti-chronological order. -procnames yes Record procedure names at definition. -trace no *Trace mode. -breakpoints no *Check for breakpoints. -cheap yes *Flyweight representation of the stack at traps. -guile> (read-enable 'case-insensitive) -(keywords #f case-insensitive positions) -guile> aBc -"hello" -guile> (read-disable 'case-insensitive) -(keywords #f positions) -guile> (debug-enable 'backtrace) -(stack 20000 debug backtrace depth 20 maxdepth 1000 frames 3 indent 10 procnames cheap) -guile> aBc - -Backtrace: -0* aBc - -ERROR: In expression aBc: -ERROR: Unbound variable: aBc -ABORT: (misc-error) -guile> -@end smalllisp - - -@node Install Config -@section Installation and Configuration Data - -It is often useful to have site-specific information about the current -Guile installation. This chapter describes how to find out about -Guile's configuration at run time. - -@deffn primitive version -@deffnx primitive major-version -@deffnx primitive minor-version -@deffnx primitive micro-version -Return a string describing Guile's version number, or its major or minor -version numbers, respectively. - -@lisp -(version) @result{} "1.6.5" -(major-version) @result{} "1" -(minor-version) @result{} "6" -(micro-version) @result{} "5" -@end lisp -@end deffn - -@c NJFIXME not in libguile! -@deffn primitive libguile-config-stamp -Return a string describing the date on which @code{libguile} was -configured. This is used to determine whether the Guile core -interpreter and the ice-9 runtime have grown out of date with one -another. -@end deffn - -@deffn primitive %package-data-dir -Return the name of the directory where Scheme packages, modules and -libraries are kept. On most Unix systems, this will be -@samp{/usr/local/share/guile}. -@end deffn - -@deffn primitive %library-dir -Return the directory where the Guile Scheme library files are installed. -E.g., may return "/usr/share/guile/1.3.5". -@end deffn - -@deffn primitive %site-dir -Return the directory where the Guile site files are installed. -E.g., may return "/usr/share/guile/site". -@end deffn - -@deffn primitive parse-path path [tail] -Parse @var{path}, which is expected to be a colon-separated -string, into a list and return the resulting list with -@var{tail} appended. If @var{path} is @code{#f}, @var{tail} -is returned. -@end deffn - -@deffn primitive search-path path filename [extensions] -Search @var{path} for a directory containing a file named -@var{filename}. The file must be readable, and not a directory. -If we find one, return its full filename; otherwise, return -@code{#f}. If @var{filename} is absolute, return it unchanged. -If given, @var{extensions} is a list of strings; for each -directory in @var{path}, we search for @var{filename} -concatenated with each @var{extension}. -@end deffn - -@defvar %load-path -Return the list of directories which should be searched for Scheme -modules and libraries. -@end defvar - - -@c Local Variables: -@c TeX-master: "guile.texi" -@c End: From 80fdeb4e5a869726da90c88ddce377f599515ee8 Mon Sep 17 00:00:00 2001 From: Mikael Djurfeldt Date: Wed, 22 Aug 2001 12:00:06 +0000 Subject: [PATCH 43/46] * tests/srfi-13.test (string-map): Swapped order of string and proc args to conform with the srfi. (Thanks to Alex Shinn.) * srfi-13.c (string-map): Swapped order of string and proc args to conform with the srfi. (Thanks to Alex Shinn.) --- srfi/ChangeLog | 5 +++++ srfi/srfi-13.c | 12 ++++++------ test-suite/ChangeLog | 5 +++++ test-suite/tests/srfi-13.test | 13 ++++++++++++- 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/srfi/ChangeLog b/srfi/ChangeLog index d2e94bbe5..e2286b8b7 100644 --- a/srfi/ChangeLog +++ b/srfi/ChangeLog @@ -1,3 +1,8 @@ +2001-08-22 Mikael Djurfeldt + + * srfi-13.c (string-map): Swapped order of string and proc args to + conform with the srfi. (Thanks to Alex Shinn.) + 2001-08-05 Gary Houston * srfi-1.scm (check-arg-type, non-negative-integer?): a couple of new diff --git a/srfi/srfi-13.c b/srfi/srfi-13.c index acd043b9c..a54dfbc1a 100644 --- a/srfi/srfi-13.c +++ b/srfi/srfi-13.c @@ -2400,7 +2400,7 @@ SCM_DEFINE (scm_string_concatenate_reverse_shared, "string-concatenate-reverse/s SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0, - (SCM s, SCM proc, SCM start, SCM end), + (SCM proc, SCM s, SCM start, SCM end), "@var{proc} is a char->char procedure, it is mapped over\n" "@var{s}. The order in which the procedure is applied to the\n" "string elements is not specified.") @@ -2410,10 +2410,10 @@ SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0, int cstart, cend; SCM result; - SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr, + SCM_VALIDATE_PROC (1, proc); + SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr, 3, start, cstart, 4, end, cend); - SCM_VALIDATE_PROC (2, proc); result = scm_allocate_string (cend - cstart); p = SCM_STRING_CHARS (result); while (cstart < cend) @@ -2430,7 +2430,7 @@ SCM_DEFINE (scm_string_map, "string-map", 2, 2, 0, SCM_DEFINE (scm_string_map_x, "string-map!", 2, 2, 0, - (SCM s, SCM proc, SCM start, SCM end), + (SCM proc, SCM s, SCM start, SCM end), "@var{proc} is a char->char procedure, it is mapped over\n" "@var{s}. The order in which the procedure is applied to the\n" "string elements is not specified. The string @var{s} is\n" @@ -2440,10 +2440,10 @@ SCM_DEFINE (scm_string_map_x, "string-map!", 2, 2, 0, char * cstr, *p; int cstart, cend; - SCM_VALIDATE_SUBSTRING_SPEC_COPY (1, s, cstr, + SCM_VALIDATE_PROC (1, proc); + SCM_VALIDATE_SUBSTRING_SPEC_COPY (2, s, cstr, 3, start, cstart, 4, end, cend); - SCM_VALIDATE_PROC (2, proc); p = SCM_STRING_CHARS (s) + cstart; while (cstart < cend) { diff --git a/test-suite/ChangeLog b/test-suite/ChangeLog index e0d6c6716..d12e6fdc1 100644 --- a/test-suite/ChangeLog +++ b/test-suite/ChangeLog @@ -1,3 +1,8 @@ +2001-08-22 Mikael Djurfeldt + + * tests/srfi-13.test (string-map): Swapped order of string and + proc args to conform with the srfi. (Thanks to Alex Shinn.) + 2001-08-12 Thien-Thi Nguyen * tests/getopt-long.test (exception:no-such-option, diff --git a/test-suite/tests/srfi-13.test b/test-suite/tests/srfi-13.test index b55472b75..37ecfa5af 100644 --- a/test-suite/tests/srfi-13.test +++ b/test-suite/tests/srfi-13.test @@ -18,7 +18,7 @@ ;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330, ;;;; Boston, MA 02111-1307 USA -(use-modules (srfi srfi-13) (srfi srfi-14)) +(use-modules (srfi srfi-13) (srfi srfi-14) (test-suite lib)) ;;; This kludge is needed, because SRFI-13 redefines some bindings in ;;; the core. @@ -1010,3 +1010,14 @@ (pass-if "pred, start and end index" (string=? "" (string-delete ".foo.bar." char-alphabetic? 2 4)))) + +(with-test-prefix "string-map" + + (pass-if "constant" + (string=? "xxx" (string-map (lambda (c) #\x) "foo"))) + + (pass-if "identity" + (string=? "foo" (string-map identity "foo"))) + + (pass-if "upcase" + (string=? "FOO" (string-map char-upcase "foo")))) From a0e07ba4ec86e4df014fee0666f18ece5a4d2471 Mon Sep 17 00:00:00 2001 From: Neil Jerram Date: Fri, 24 Aug 2001 09:40:29 +0000 Subject: [PATCH 44/46] * Organize documentation into per-manual directories (halfway point commit). --- doc/ChangeLog-guile-doc-ref | 0 doc/ChangeLog-guile-doc-tutorial | 0 doc/api.txt | 0 doc/deprecated.texi | 0 doc/expect.texi | 0 doc/extend.texi | 0 doc/format.texi | 0 doc/gh.texi | 0 doc/goops-tutorial.texi | 0 doc/goops.texi | 0 doc/goops/.cvsignore | 23 + doc/goops/goops-tutorial.texi | 810 ++ doc/goops/goops.texi | 2788 +++++++ doc/goops/hierarchy.eps | 127 + doc/goops/hierarchy.txt | 14 + doc/goops/mop.text | 66 + doc/guile-tut.texi | 0 doc/hierarchy.eps | 0 doc/hierarchy.txt | 0 doc/indices.texi | 0 doc/misc-modules.texi | 0 doc/mop.text | 0 doc/new-docstrings.texi | 0 doc/posix.texi | 0 doc/preface.texi | 0 doc/r5rs.texi | 0 doc/r5rs/.cvsignore | 23 + doc/r5rs/r5rs.texi | 8538 +++++++++++++++++++++ doc/ref/.cvsignore | 23 + doc/ref/ChangeLog-guile-doc-ref | 890 +++ doc/ref/api.txt | 185 + doc/{ => ref}/appendices.texi | 0 doc/{ => ref}/data-rep.texi | 2 +- doc/ref/deprecated.texi | 138 + doc/ref/expect.texi | 142 + doc/ref/extend.texi | 44 + doc/ref/gh.texi | 1164 +++ doc/{ => ref}/guile.texi | 2 +- doc/ref/indices.texi | 54 + doc/{ => ref}/intro.texi | 2 +- doc/ref/misc-modules.texi | 291 + doc/ref/new-docstrings.texi | 532 ++ doc/ref/posix.texi | 2328 ++++++ doc/ref/preface.texi | 182 + doc/ref/repl-modules.texi | 131 + doc/ref/scheme-binding.texi | 242 + doc/ref/scheme-control.texi | 823 ++ doc/ref/scheme-data.texi | 5230 +++++++++++++ doc/ref/scheme-debug.texi | 187 + doc/ref/scheme-evaluation.texi | 419 + doc/ref/scheme-ideas.texi | 1458 ++++ doc/ref/scheme-indices.texi | 17 + doc/ref/scheme-intro.texi | 55 + doc/ref/scheme-io.texi | 826 ++ doc/ref/scheme-memory.texi | 222 + doc/ref/scheme-modules.texi | 826 ++ doc/ref/scheme-options.texi | 398 + doc/ref/scheme-procedures.texi | 778 ++ doc/ref/scheme-reading.texi | 27 + doc/ref/scheme-scheduling.texi | 435 ++ doc/ref/scheme-translation.texi | 44 + doc/ref/scheme-utility.texi | 295 + doc/ref/scm.texi | 458 ++ doc/ref/script-getopt.texi | 435 ++ doc/ref/scripts.texi | 213 + doc/ref/scsh.texi | 25 + doc/ref/slib.texi | 105 + doc/ref/srfi-modules.texi | 2241 ++++++ doc/ref/tcltk.texi | 3 + doc/repl-modules.texi | 0 doc/scheme-binding.texi | 0 doc/scheme-control.texi | 0 doc/scheme-data.texi | 0 doc/scheme-debug.texi | 0 doc/scheme-evaluation.texi | 0 doc/scheme-ideas.texi | 0 doc/scheme-indices.texi | 0 doc/scheme-intro.texi | 0 doc/scheme-io.texi | 0 doc/scheme-memory.texi | 0 doc/scheme-modules.texi | 0 doc/scheme-options.texi | 0 doc/scheme-procedures.texi | 0 doc/scheme-reading.texi | 0 doc/scheme-scheduling.texi | 0 doc/scheme-translation.texi | 0 doc/scheme-utility.texi | 0 doc/scm.texi | 0 doc/script-getopt.texi | 0 doc/scripts.texi | 0 doc/scsh.texi | 0 doc/slib.texi | 0 doc/{ => sources}/env.texi | 2 +- doc/sources/format.texi | 434 ++ doc/srfi-modules.texi | 0 doc/tcltk.texi | 0 doc/tutorial/.cvsignore | 23 + doc/tutorial/ChangeLog-guile-doc-tutorial | 16 + doc/tutorial/guile-tut.texi | 1334 ++++ 99 files changed, 36066 insertions(+), 4 deletions(-) delete mode 100644 doc/ChangeLog-guile-doc-ref delete mode 100644 doc/ChangeLog-guile-doc-tutorial delete mode 100644 doc/api.txt delete mode 100644 doc/deprecated.texi delete mode 100644 doc/expect.texi delete mode 100644 doc/extend.texi delete mode 100644 doc/format.texi delete mode 100644 doc/gh.texi delete mode 100644 doc/goops-tutorial.texi delete mode 100644 doc/goops.texi create mode 100644 doc/goops/.cvsignore create mode 100644 doc/goops/goops-tutorial.texi create mode 100644 doc/goops/goops.texi create mode 100644 doc/goops/hierarchy.eps create mode 100644 doc/goops/hierarchy.txt create mode 100644 doc/goops/mop.text delete mode 100644 doc/guile-tut.texi delete mode 100644 doc/hierarchy.eps delete mode 100644 doc/hierarchy.txt delete mode 100644 doc/indices.texi delete mode 100644 doc/misc-modules.texi delete mode 100644 doc/mop.text delete mode 100644 doc/new-docstrings.texi delete mode 100644 doc/posix.texi delete mode 100644 doc/preface.texi delete mode 100644 doc/r5rs.texi create mode 100644 doc/r5rs/.cvsignore create mode 100644 doc/r5rs/r5rs.texi create mode 100644 doc/ref/.cvsignore create mode 100644 doc/ref/ChangeLog-guile-doc-ref create mode 100644 doc/ref/api.txt rename doc/{ => ref}/appendices.texi (100%) rename doc/{ => ref}/data-rep.texi (99%) create mode 100644 doc/ref/deprecated.texi create mode 100644 doc/ref/expect.texi create mode 100644 doc/ref/extend.texi create mode 100644 doc/ref/gh.texi rename doc/{ => ref}/guile.texi (99%) create mode 100644 doc/ref/indices.texi rename doc/{ => ref}/intro.texi (99%) create mode 100644 doc/ref/misc-modules.texi create mode 100644 doc/ref/new-docstrings.texi create mode 100644 doc/ref/posix.texi create mode 100644 doc/ref/preface.texi create mode 100644 doc/ref/repl-modules.texi create mode 100644 doc/ref/scheme-binding.texi create mode 100644 doc/ref/scheme-control.texi create mode 100755 doc/ref/scheme-data.texi create mode 100644 doc/ref/scheme-debug.texi create mode 100644 doc/ref/scheme-evaluation.texi create mode 100644 doc/ref/scheme-ideas.texi create mode 100644 doc/ref/scheme-indices.texi create mode 100644 doc/ref/scheme-intro.texi create mode 100644 doc/ref/scheme-io.texi create mode 100644 doc/ref/scheme-memory.texi create mode 100644 doc/ref/scheme-modules.texi create mode 100644 doc/ref/scheme-options.texi create mode 100644 doc/ref/scheme-procedures.texi create mode 100644 doc/ref/scheme-reading.texi create mode 100644 doc/ref/scheme-scheduling.texi create mode 100644 doc/ref/scheme-translation.texi create mode 100644 doc/ref/scheme-utility.texi create mode 100644 doc/ref/scm.texi create mode 100644 doc/ref/script-getopt.texi create mode 100644 doc/ref/scripts.texi create mode 100644 doc/ref/scsh.texi create mode 100644 doc/ref/slib.texi create mode 100644 doc/ref/srfi-modules.texi create mode 100644 doc/ref/tcltk.texi delete mode 100644 doc/repl-modules.texi delete mode 100644 doc/scheme-binding.texi delete mode 100644 doc/scheme-control.texi delete mode 100755 doc/scheme-data.texi delete mode 100644 doc/scheme-debug.texi delete mode 100644 doc/scheme-evaluation.texi delete mode 100644 doc/scheme-ideas.texi delete mode 100644 doc/scheme-indices.texi delete mode 100644 doc/scheme-intro.texi delete mode 100644 doc/scheme-io.texi delete mode 100644 doc/scheme-memory.texi delete mode 100644 doc/scheme-modules.texi delete mode 100644 doc/scheme-options.texi delete mode 100644 doc/scheme-procedures.texi delete mode 100644 doc/scheme-reading.texi delete mode 100644 doc/scheme-scheduling.texi delete mode 100644 doc/scheme-translation.texi delete mode 100644 doc/scheme-utility.texi delete mode 100644 doc/scm.texi delete mode 100644 doc/script-getopt.texi delete mode 100644 doc/scripts.texi delete mode 100644 doc/scsh.texi delete mode 100644 doc/slib.texi rename doc/{ => sources}/env.texi (99%) create mode 100644 doc/sources/format.texi delete mode 100644 doc/srfi-modules.texi delete mode 100644 doc/tcltk.texi create mode 100644 doc/tutorial/.cvsignore create mode 100644 doc/tutorial/ChangeLog-guile-doc-tutorial create mode 100644 doc/tutorial/guile-tut.texi diff --git a/doc/ChangeLog-guile-doc-ref b/doc/ChangeLog-guile-doc-ref deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/ChangeLog-guile-doc-tutorial b/doc/ChangeLog-guile-doc-tutorial deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/api.txt b/doc/api.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/deprecated.texi b/doc/deprecated.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/expect.texi b/doc/expect.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/extend.texi b/doc/extend.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/format.texi b/doc/format.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/gh.texi b/doc/gh.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/goops-tutorial.texi b/doc/goops-tutorial.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/goops.texi b/doc/goops.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/goops/.cvsignore b/doc/goops/.cvsignore new file mode 100644 index 000000000..8eaa8267a --- /dev/null +++ b/doc/goops/.cvsignore @@ -0,0 +1,23 @@ +Makefile +Makefile.in +stamp-vti +stamp-vti.1 +*.log +*.dvi +*.aux +*.toc +*.cp +*.fn +*.vr +*.tp +*.ky +*.pg +*.cps +*.fns +*.tps +*.vrs +*.ps +*.info* +*.html +version.texi +version-tutorial.texi diff --git a/doc/goops/goops-tutorial.texi b/doc/goops/goops-tutorial.texi new file mode 100644 index 000000000..7ab6ebcf0 --- /dev/null +++ b/doc/goops/goops-tutorial.texi @@ -0,0 +1,810 @@ +@c Original attribution: + +@c +@c STk Reference manual (Appendix: An Introduction to STklos) +@c +@c Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI +@c Permission to use, copy, modify, distribute,and license this +@c software and its documentation for any purpose is hereby granted, +@c provided that existing copyright notices are retained in all +@c copies and that this notice is included verbatim in any +@c distributions. No written agreement, license, or royalty fee is +@c required for any of the authorized uses. +@c This software is provided ``AS IS'' without express or implied +@c warranty. +@c + +@c Adapted for use in Guile with the authors permission + +@c @macro goops @c was {\stklos} +@c GOOPS +@c @end macro + +@c @macro guile @c was {\stk} +@c Guile +@c @end macro + +This is chapter was originally written by Erick Gallesio as an appendix +for the STk reference manual, and subsequently adapted to @goops{}. + +@menu +* Copyright:: +* Intro:: +* Class definition and instantiation:: +* Inheritance:: +* Generic functions:: +@end menu + +@node Copyright, Intro, Tutorial, Tutorial +@section Copyright + +Original attribution: + +STk Reference manual (Appendix: An Introduction to STklos) + +Copyright © 1993-1999 Erick Gallesio - I3S-CNRS/ESSI +Permission to use, copy, modify, distribute,and license this +software and its documentation for any purpose is hereby granted, +provided that existing copyright notices are retained in all +copies and that this notice is included verbatim in any +distributions. No written agreement, license, or royalty fee is +required for any of the authorized uses. +This software is provided ``AS IS'' without express or implied +warranty. + +Adapted for use in Guile with the authors permission + +@node Intro, Class definition and instantiation, Copyright, Tutorial +@section Introduction + +@goops{} is the object oriented extension to @guile{}. Its +implementation is derived from @w{STk-3.99.3} by Erick Gallesio and +version 1.3 of the Gregor Kiczales @cite{Tiny-Clos}. It is very close +to CLOS, the Common Lisp Object System (@cite{CLtL2}) but is adapted for +the Scheme language. + +Briefly stated, the @goops{} extension gives the user a full object +oriented system with multiple inheritance and generic functions with +multi-method dispatch. Furthermore, the implementation relies on a true +meta object protocol, in the spirit of the one defined for CLOS +(@cite{Gregor Kiczales: A Metaobject Protocol}). + +The purpose of this tutorial is to introduce briefly the @goops{} +package and in no case will it replace the @goops{} reference manual +(which needs to be urgently written now@ @dots{}). + +Note that the operations described in this tutorial resides in modules +that may need to be imported before being available. The main module is +imported by evaluating: + +@lisp +(use-modules (oop goops)) +@end lisp +@findex (oop goops) +@cindex main module +@cindex loading +@cindex preparing + +@node Class definition and instantiation, Inheritance, Intro, Tutorial +@section Class definition and instantiation + +@menu +* Class definition:: +@end menu + +@node Class definition, , Class definition and instantiation, Class definition and instantiation +@subsection Class definition + +A new class is defined with the @code{define-class}@footnote{Don't +forget to import the @code{(oop goops)} module} macro. The syntax of +@code{define-class} is close to CLOS @code{defclass}: + +@findex define-class +@cindex class +@lisp +(define-class @var{class} (@var{superclass} @dots{}) + @var{slot-description} @dots{} + @var{class-option} @dots{}) +@end lisp + +Class options will not be discussed in this tutorial. The list of +@var{superclass}es specifies which classes to inherit properties from +@var{class} (see @ref{Inheritance} for more details). A +@var{slot-description} gives the name of a slot and, eventually, some +``properties'' of this slot (such as its initial value, the function +which permit to access its value, @dots{}). Slot descriptions will be +discussed in @ref{Slot description}. +@cindex slot + +As an example, let us define a type for representation of complex +numbers in terms of real numbers. This can be done with the following +class definition: + +@lisp +(define-class () + r i) +@end lisp + +This binds the variable @code{}@footnote{@code{} is in +fact a builtin class in GOOPS. Because of this, GOOPS will create a new +class. The old class will still serve as the type for Guile's native +complex numbers.} to a new class whose instances contain two +slots. These slots are called @code{r} an @code{i} and we suppose here +that they contain respectively the real part and the imaginary part of a +complex number. Note that this class inherits from @code{} which +is a pre-defined class. (@code{} is the direct super class of +the pre-defined class @code{} which, in turn, is the super +class of @code{} which is the super of +@code{}.)@footnote{With the new definition of @code{}, +a @code{} is not a @code{} since @code{} inherits +from @code{ } rather than @code{}. In practice, +inheritance could be modified @emph{a posteriori}, if needed. However, +this necessitates some knowledge of the meta object protocol and it will +not be shown in this document}. + +@node Inheritance, Generic functions, Class definition and instantiation, Tutorial +@section Inheritance +@c \label{inheritance} + +@menu +* Class hierarchy and inheritance of slots:: +* Instance creation and slot access:: +* Slot description:: +* Class precedence list:: +@end menu + +@node Class hierarchy and inheritance of slots, Instance creation and slot access, Inheritance, Inheritance +@subsection Class hierarchy and inheritance of slots +Inheritance is specified upon class definition. As said in the +introduction, @goops{} supports multiple inheritance. Here are some +class definitions: + +@lisp +(define-class A () a) +(define-class B () b) +(define-class C () c) +(define-class D (A B) d a) +(define-class E (A C) e c) +(define-class F (D E) f) +@end lisp + +@code{A}, @code{B}, @code{C} have a null list of super classes. In this +case, the system will replace it by the list which only contains +@code{}, the root of all the classes defined by +@code{define-class}. @code{D}, @code{E}, @code{F} use multiple +inheritance: each class inherits from two previously defined classes. +Those class definitions define a hierarchy which is shown in Figure@ 1. +In this figure, the class @code{} is also shown; this class is the +super class of all Scheme objects. In particular, @code{} is the +super class of all standard Scheme types. + +@example +@group +@image{hierarchy} +@center @emph{Fig 1: A class hierarchy} +@iftex +@emph{(@code{} which is the direct subclass of @code{} +and the direct superclass of @code{} has been omitted in this +figure.)} +@end iftex +@end group +@end example + +The set of slots of a given class is calculated by taking the union of the +slots of all its super class. For instance, each instance of the class +D, defined before will have three slots (@code{a}, @code{b} and +@code{d}). The slots of a class can be obtained by the @code{class-slots} +primitive. For instance, + +@lisp +(class-slots A) @result{} ((a)) +(class-slots E) @result{} ((a) (e) (c)) +(class-slots F) @result{} ((e) (c) (b) (d) (a) (f)) +@c used to be ((d) (a) (b) (c) (f)) +@end lisp + +@emph{Note: } The order of slots is not significant. + +@node Instance creation and slot access, Slot description, Class hierarchy and inheritance of slots, Inheritance +@subsection Instance creation and slot access + +Creation of an instance of a previously defined +class can be done with the @code{make} procedure. This +procedure takes one mandatory parameter which is the class of the +instance which must be created and a list of optional +arguments. Optional arguments are generally used to initialize some +slots of the newly created instance. For instance, the following form + +@findex make +@cindex instance +@lisp +(define c (make )) +@end lisp + +will create a new @code{} object and will bind it to the @code{c} +Scheme variable. + +Accessing the slots of the new complex number can be done with the +@code{slot-ref} and the @code{slot-set!} primitives. @code{Slot-set!} +primitive permits to set the value of an object slot and @code{slot-ref} +permits to get its value. + +@findex slot-set! +@findex slot-ref +@lisp +@group +(slot-set! c 'r 10) +(slot-set! c 'i 3) +(slot-ref c 'r) @result{} 10 +(slot-ref c 'i) @result{} 3 +@end group +@end lisp + +Using the @code{describe} function is a simple way to see all the +slots of an object at one time: this function prints all the slots of an +object on the standard output. + +First load the module @code{(oop goops describe)}: + +@example +@code{(use-modules (oop goops describe))} +@end example + +The expression + +@smalllisp +(describe c) +@end smalllisp + +will now print the following information on the standard output: + +@lisp +#< 401d8638> is an instance of class +Slots are: + r = 10 + i = 3 +@end lisp + +@node Slot description, Class precedence list, Instance creation and slot access, Inheritance +@subsection Slot description +@c \label{slot-description} + +When specifying a slot, a set of options can be given to the +system. Each option is specified with a keyword. The list of authorized +keywords is given below: + +@cindex keyword +@itemize @bullet +@item +@code{#:init-value} permits to supply a default value for the slot. This +default value is obtained by evaluating the form given after the +@code{#:init-form} in the global environment, at class definition time. +@cindex default slot value +@findex #:init-value +@cindex top level environment + +@item +@code{#:init-thunk} permits to supply a thunk that will provide a +default value for the slot. The value is obtained by evaluating the +thunk a instance creation time. +@c CHECKME: in the global environment? +@findex default slot value +@findex #:init-thunk +@cindex top level environment + +@item +@code{#:init-keyword} permits to specify the keyword for initializing a +slot. The init-keyword may be provided during instance creation (i.e. in +the @code{make} optional parameter list). Specifying such a keyword +during instance initialization will supersede the default slot +initialization possibly given with @code{#:init-form}. +@findex #:init-keyword + +@item +@code{#:getter} permits to supply the name for the +slot getter. The name binding is done in the +environment of the @code{define-class} macro. +@findex #:getter +@cindex top level environment +@cindex getter + +@item +@code{#:setter} permits to supply the name for the +slot setter. The name binding is done in the +environment of the @code{define-class} macro. +@findex #:setter +@cindex top level environment +@cindex setter + +@item +@code{#:accessor} permits to supply the name for the +slot accessor. The name binding is done in the global +environment. An accessor permits to get and +set the value of a slot. Setting the value of a slot is done with the extended +version of @code{set!}. +@findex set! +@findex #:accessor +@cindex top level environment +@cindex accessor + +@item +@code{#:allocation} permits to specify how storage for +the slot is allocated. Three kinds of allocation are provided. +They are described below: + +@itemize @minus +@item +@code{#:instance} indicates that each instance gets its own storage for +the slot. This is the default. +@item +@code{#:class} indicates that there is one storage location used by all +the direct and indirect instances of the class. This permits to define a +kind of global variable which can be accessed only by (in)direct +instances of the class which defines this slot. +@item +@code{#:each-subclass} indicates that there is one storage location used +by all the direct instances of the class. In other words, if two classes +are not siblings in the class hierarchy, they will not see the same +value. +@item +@code{#:virtual} indicates that no storage will be allocated for this +slot. It is up to the user to define a getter and a setter function for +this slot. Those functions must be defined with the @code{#:slot-ref} +and @code{#:slot-set!} options. See the example below. +@findex #:slot-set! +@findex #:slot-ref +@findex #:virtual +@findex #:class +@findex #:each-subclass +@findex #:instance +@findex #:allocation +@end itemize +@end itemize + +To illustrate slot description, we shall redefine the @code{} class +seen before. A definition could be: + +@lisp +(define-class () + (r #:init-value 0 #:getter get-r #:setter set-r! #:init-keyword #:r) + (i #:init-value 0 #:getter get-i #:setter set-i! #:init-keyword #:i)) +@end lisp + +With this definition, the @code{r} and @code{i} slot are set to 0 by +default. Value of a slot can also be specified by calling @code{make} +with the @code{#:r} and @code{#:i} keywords. Furthermore, the generic +functions @code{get-r} and @code{set-r!} (resp. @code{get-i} and +@code{set-i!}) are automatically defined by the system to read and write +the @code{r} (resp. @code{i}) slot. + +@lisp +(define c1 (make #:r 1 #:i 2)) +(get-r c1) @result{} 1 +(set-r! c1 12) +(get-r c1) @result{} 12 +(define c2 (make #:r 2)) +(get-r c2) @result{} 2 +(get-i c2) @result{} 0 +@end lisp + +Accessors provide an uniform access for reading and writing an object +slot. Writing a slot is done with an extended form of @code{set!} +which is close to the Common Lisp @code{setf} macro. So, another +definition of the previous @code{} class, using the +@code{#:accessor} option, could be: + +@findex set! +@lisp +(define-class () + (r #:init-value 0 #:accessor real-part #:init-keyword #:r) + (i #:init-value 0 #:accessor imag-part #:init-keyword #:i)) +@end lisp + +Using this class definition, reading the real part of the @code{c} +complex can be done with: +@lisp +(real-part c) +@end lisp +and setting it to the value contained in the @code{new-value} variable +can be done using the extended form of @code{set!}. +@lisp +(set! (real-part c) new-value) +@end lisp + +Suppose now that we have to manipulate complex numbers with rectangular +coordinates as well as with polar coordinates. One solution could be to +have a definition of complex numbers which uses one particular +representation and some conversion functions to pass from one +representation to the other. A better solution uses virtual slots. A +complete definition of the @code{} class using virtual slots is +given in Figure@ 2. + +@example +@group +@lisp +(define-class () + ;; True slots use rectangular coordinates + (r #:init-value 0 #:accessor real-part #:init-keyword #:r) + (i #:init-value 0 #:accessor imag-part #:init-keyword #:i) + ;; Virtual slots access do the conversion + (m #:accessor magnitude #:init-keyword #:magn + #:allocation #:virtual + #:slot-ref (lambda (o) + (let ((r (slot-ref o 'r)) (i (slot-ref o 'i))) + (sqrt (+ (* r r) (* i i))))) + #:slot-set! (lambda (o m) + (let ((a (slot-ref o 'a))) + (slot-set! o 'r (* m (cos a))) + (slot-set! o 'i (* m (sin a)))))) + (a #:accessor angle #:init-keyword #:angle + #:allocation #:virtual + #:slot-ref (lambda (o) + (atan (slot-ref o 'i) (slot-ref o 'r))) + #:slot-set! (lambda(o a) + (let ((m (slot-ref o 'm))) + (slot-set! o 'r (* m (cos a))) + (slot-set! o 'i (* m (sin a))))))) + +@end lisp +@center @emph{Fig 2: A @code{} number class definition using virtual slots} +@end group +@end example + +@sp 3 +This class definition implements two real slots (@code{r} and +@code{i}). Values of the @code{m} and @code{a} virtual slots are +calculated from real slot values. Reading a virtual slot leads to the +application of the function defined in the @code{#:slot-ref} +option. Writing such a slot leads to the application of the function +defined in the @code{#:slot-set!} option. For instance, the following +expression + +@findex #:slot-set! +@findex #:slot-ref +@lisp +(slot-set! c 'a 3) +@end lisp + +permits to set the angle of the @code{c} complex number. This expression +conducts, in fact, to the evaluation of the following expression + +@lisp +((lambda o m) + (let ((m (slot-ref o 'm))) + (slot-set! o 'r (* m (cos a))) + (slot-set! o 'i (* m (sin a)))) + c 3) +@end lisp + +A more complete example is given below: + +@example +@group +@lisp +(define c (make #:r 12 #:i 20)) +(real-part c) @result{} 12 +(angle c) @result{} 1.03037682652431 +(slot-set! c 'i 10) +(set! (real-part c) 1) +(describe c) @result{} + #< 401e9b58> is an instance of class + Slots are: + r = 1 + i = 10 + m = 10.0498756211209 + a = 1.47112767430373 +@end lisp +@end group +@end example + +Since initialization keywords have been defined for the four slots, we +can now define the @code{make-rectangular} and @code{make-polar} standard +Scheme primitives. + +@lisp +(define make-rectangular + (lambda (x y) (make #:r x #:i y))) + +(define make-polar + (lambda (x y) (make #:magn x #:angle y))) +@end lisp + +@node Class precedence list, , Slot description, Inheritance +@subsection Class precedence list + +A class may have more than one superclass. @footnote{This section is an +adaptation of Jeff Dalton's (J.Dalton@@ed.ac.uk) @cite{Brief +introduction to CLOS}} With single inheritance (one superclass), it is +easy to order the super classes from most to least specific. This is the +rule: + +@display +@cartouche +Rule 1: Each class is more specific than its superclasses.@c was \bf +@end cartouche +@end display + +With multiple inheritance, ordering is harder. Suppose we have + +@lisp +(define-class X () + (x #:init-value 1)) + +(define-class Y () + (x #:init-value 2)) + +(define-class Z (X Y) + (@dots{})) +@end lisp + +In this case, the @code{Z} class is more specific than the @code{X} or +@code{Y} class for instances of @code{Z}. However, the @code{#:init-value} +specified in @code{X} and @code{Y} leads to a problem: which one +overrides the other? The rule in @goops{}, as in CLOS, is that the +superclasses listed earlier are more specific than those listed later. +So: + +@display +@cartouche +Rule 2: For a given class, superclasses listed earlier are more + specific than those listed later. +@end cartouche +@end display + +These rules are used to compute a linear order for a class and all its +superclasses, from most specific to least specific. This order is +called the ``class precedence list'' of the class. Given these two +rules, we can claim that the initial form for the @code{x} slot of +previous example is 1 since the class @code{X} is placed before @code{Y} +in class precedence list of @code{Z}. + +These two rules are not always enough to determine a unique order, +however, but they give an idea of how things work. Taking the @code{F} +class shown in Figure@ 1, the class precedence list is + +@example +(f d e a c b ) +@end example + +However, it is usually considered a bad idea for programmers to rely on +exactly what the order is. If the order for some superclasses is important, +it can be expressed directly in the class definition. + +The precedence list of a class can be obtained by the function +@code{class-precedence-list}. This function returns a ordered +list whose first element is the most specific class. For instance, + +@lisp +(class-precedence-list B) @result{} (#< B 401b97c8> + #< 401e4a10> + #< 4026a9d8>) +@end lisp + +However, this result is not too much readable; using the function +@code{class-name} yields a clearer result: + +@lisp +(map class-name (class-precedence-list B)) @result{} (B ) +@end lisp + +@node Generic functions, , Inheritance, Tutorial +@section Generic functions + +@menu +* Generic functions and methods:: +* Next-method:: +* Example:: +@end menu + +@node Generic functions and methods, Next-method, Generic functions, Generic functions +@subsection Generic functions and methods + +@c \label{gf-n-methods} +Neither @goops{} nor CLOS use the message mechanism for methods as most +Object Oriented language do. Instead, they use the notion of +@dfn{generic functions}. A generic function can be seen as a methods +``tanker''. When the evaluator requested the application of a generic +function, all the methods of this generic function will be grabbed and +the most specific among them will be applied. We say that a method +@var{M} is @emph{more specific} than a method @var{M'} if the class of +its parameters are more specific than the @var{M'} ones. To be more +precise, when a generic function must be ``called'' the system will: + +@cindex generic function +@enumerate +@item +search among all the generic function those which are applicable +@item +sort the list of applicable methods in the ``most specific'' order +@item +call the most specific method of this list (i.e. the first method of +the sorted methods list). +@end enumerate + +The definition of a generic function is done with the +@code{define-generic} macro. Definition of a new method is done with the +@code{define-method} macro. Note that @code{define-method} automatically +defines the generic function if it has not been defined +before. Consequently, most of the time, the @code{define-generic} needs +not be used. +@findex define-generic +@findex define-method +Consider the following definitions: + +@lisp +(define-generic G) +(define-method (G (a ) b) 'integer) +(define-method (G (a ) b) 'real) +(define-method (G a b) 'top) +@end lisp + +The @code{define-generic} call defines @var{G} as a generic +function. Note that the signature of the generic function is not given +upon definition, contrarily to CLOS. This will permit methods with +different signatures for a given generic function, as we shall see +later. The three next lines define methods for the @var{G} generic +function. Each method uses a sequence of @dfn{parameter specializers} +that specify when the given method is applicable. A specializer permits +to indicate the class a parameter must belong to (directly or +indirectly) to be applicable. If no specializer is given, the system +defaults it to @code{}. Thus, the first method definition is +equivalent to + +@cindex parameter specializers +@lisp +(define-method (G (a ) (b )) 'integer) +@end lisp + +Now, let us look at some possible calls to generic function @var{G}: + +@lisp +(G 2 3) @result{} integer +(G 2 #t) @result{} integer +(G 1.2 'a) @result{} real +@c (G #3 'a) @result{} real @c was {\sharpsign} +(G #t #f) @result{} top +(G 1 2 3) @result{} error (since no method exists for 3 parameters) +@end lisp + +The preceding methods use only one specializer per parameter list. Of +course, each parameter can use a specializer. In this case, the +parameter list is scanned from left to right to determine the +applicability of a method. Suppose we declare now + +@lisp +(define-method (G (a ) (b )) 'integer-number) +(define-method (G (a ) (b )) 'integer-real) +(define-method (G (a ) (b )) 'integer-integer) +(define-method (G a (b )) 'top-number) +@end lisp + +In this case, + +@lisp +(G 1 2) @result{} integer-integer +(G 1 1.0) @result{} integer-real +(G 1 #t) @result{} integer +(G 'a 1) @result{} top-number +@end lisp + +@node Next-method, Example, Generic functions and methods, Generic functions +@subsection Next-method + +When a generic function is called, the list of applicable methods is +built. As mentioned before, the most specific method of this list is +applied (see@ @ref{Generic functions and methods}). This method may call +the next method in the list of applicable methods. This is done by using +the special form @code{next-method}. Consider the following definitions + +@lisp +(define-method (Test (a )) (cons 'integer (next-method))) +(define-method (Test (a )) (cons 'number (next-method))) +(define-method (Test a) (list 'top)) +@end lisp + +With those definitions, + +@lisp +(Test 1) @result{} (integer number top) +(Test 1.0) @result{} (number top) +(Test #t) @result{} (top) +@end lisp + +@node Example, , Next-method, Generic functions +@subsection Example + +In this section we shall continue to define operations on the @code{} +class defined in Figure@ 2. Suppose that we want to use it to implement +complex numbers completely. For instance a definition for the addition of +two complexes could be + +@lisp +(define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) (real-part b)) + (+ (imag-part a) (imag-part b)))) +@end lisp + +To be sure that the @code{+} used in the method @code{new-+} is the standard +addition we can do: + +@lisp +(define-generic new-+) + +(let ((+ +)) + (define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) (real-part b)) + (+ (imag-part a) (imag-part b))))) +@end lisp + +The @code{define-generic} ensures here that @code{new-+} will be defined +in the global environment. Once this is done, we can add methods to the +generic function @code{new-+} which make a closure on the @code{+} +symbol. A complete writing of the @code{new-+} methods is shown in +Figure@ 3. + +@example +@group +@lisp +(define-generic new-+) + +(let ((+ +)) + + (define-method (new-+ (a ) (b )) (+ a b)) + + (define-method (new-+ (a ) (b )) + (make-rectangular (+ a (real-part b)) (imag-part b))) + + (define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) b) (imag-part a))) + + (define-method (new-+ (a ) (b )) + (make-rectangular (+ (real-part a) (real-part b)) + (+ (imag-part a) (imag-part b)))) + + (define-method (new-+ (a )) a) + + (define-method (new-+) 0) + + (define-method (new-+ . args) + (new-+ (car args) + (apply new-+ (cdr args))))) + +(set! + new-+) +@end lisp + +@center @emph{Fig 3: Extending @code{+} for dealing with complex numbers} +@end group +@end example + +@sp 3 +We use here the fact that generic function are not obliged to have the +same number of parameters, contrarily to CLOS. The four first methods +implement the dyadic addition. The fifth method says that the addition +of a single element is this element itself. The sixth method says that +using the addition with no parameter always return 0. The last method +takes an arbitrary number of parameters@footnote{The parameter list for +a @code{define-method} follows the conventions used for Scheme +procedures. In particular it can use the dot notation or a symbol to +denote an arbitrary number of parameters}. This method acts as a kind +of @code{reduce}: it calls the dyadic addition on the @emph{car} of the +list and on the result of applying it on its rest. To finish, the +@code{set!} permits to redefine the @code{+} symbol to our extended +addition. + +@sp 3 +To terminate our implementation (integration?) of complex numbers, we can +redefine standard Scheme predicates in the following manner: + +@lisp +(define-method (complex? c ) #t) +(define-method (complex? c) #f) + +(define-method (number? n ) #t) +(define-method (number? n) #f) +@dots{} +@dots{} +@end lisp + +Standard primitives in which complex numbers are involved could also be +redefined in the same manner. + diff --git a/doc/goops/goops.texi b/doc/goops/goops.texi new file mode 100644 index 000000000..ac08a2625 --- /dev/null +++ b/doc/goops/goops.texi @@ -0,0 +1,2788 @@ +\input texinfo +@c -*-texinfo-*- +@c %**start of header +@setfilename goops.info +@settitle Goops Manual +@set goops +@setchapternewpage odd +@paragraphindent 0 +@c %**end of header + +@set VERSION 0.3 + +@dircategory The Algorithmic Language Scheme +@direntry +* GOOPS: (goops). The GOOPS reference manual. +@end direntry + +@macro goops +GOOPS +@end macro + +@macro guile +Guile +@end macro + +@ifinfo +This file documents GOOPS, an object oriented extension for Guile. + +Copyright (C) 1999, 2000, 2001 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@end ifinfo + +@c This title page illustrates only one of the +@c two methods of forming a title page. + +@titlepage +@title Goops Manual +@subtitle For use with GOOPS @value{VERSION} +@include AUTHORS + +@c The following two commands +@c start the copyright page. +@page +@vskip 0pt plus 1filll +Copyright @copyright{} 1999 Free Software Foundation + +Permission is granted to make and distribute verbatim copies of +this manual provided the copyright notice and this permission notice +are preserved on all copies. + +@end titlepage + +@node Top, Introduction, (dir), (dir) + +@menu +[When the manual is completed, this will be a flat index in the style of + the Emacs manual. More nodes will turn up under parts I-III.] + +Part I: Preliminaries + +* Introduction:: +* Getting Started:: + +Part II: Reference Manual + +* Reference Manual:: + +Part III: GOOPS Meta Object Protocol + +* MOP Specification:: + +The GOOPS tutorial + +* Tutorial:: + +* Index:: +* Concept Index:: +* Function and Variable Index:: +@end menu + +@iftex +@chapter Preliminaries +@end iftex + +@node Introduction, Getting Started, Top, Top +@section Introduction + +@goops{} is the object oriented extension to @guile{}. Its +implementation is derived from @w{STk-3.99.3} by Erick Gallesio and +version 1.3 of Gregor Kiczales @cite{Tiny-Clos}. It is very close in +spirit to CLOS, the Common Lisp Object System (@cite{CLtL2}) but is +adapted for the Scheme language. While GOOPS is not compatible with any +of these systems, GOOPS contains a compatibility module which allows for +execution of STKlos programs. + +Briefly stated, the @goops{} extension gives the user a full object +oriented system with multiple inheritance and generic functions with +multi-method dispatch. Furthermore, the implementation relies on a true +meta object protocol, in the spirit of the one defined for CLOS +(@cite{Gregor Kiczales: A Metaobject Protocol}). + +@node Getting Started, Reference Manual, Introduction, Top +@section Getting Started + +@menu +* Running GOOPS:: + +Examples of some basic GOOPS functionality. + +* Methods:: +* User-defined types:: +* Asking for the type of an object:: + +See further in the GOOPS tutorial available in this distribution in +info (goops.info) and texinfo format. +@end menu + +@node Running GOOPS, Methods, Getting Started, Getting Started +@subsection Running GOOPS + +@enumerate +@item +Type + +@smalllisp +guile-oops +@end smalllisp + +You should now be at the Guile prompt ("guile> "). + +@item +Type + +@smalllisp +(use-modules (oop goops)) +@end smalllisp + +to load GOOPS. (If your system supports dynamic loading, you +should be able to do this not only from `guile-oops' but from an +arbitrary Guile interpreter.) +@end enumerate + +We're now ready to try some basic GOOPS functionality. + +@node Methods, User-defined types, Running GOOPS, Getting Started +@subsection Methods + +@smalllisp +@group +(define-method (+ (x ) (y )) + (string-append x y)) + +(+ 1 2) --> 3 +(+ "abc" "de") --> "abcde" +@end group +@end smalllisp + +@node User-defined types, Asking for the type of an object, Methods, Getting Started +@subsection User-defined types + +@smalllisp +(define-class <2D-vector> () + (x #:init-value 0 #:accessor x-component #:init-keyword #:x) + (y #:init-value 0 #:accessor y-component #:init-keyword #:y)) + +@group +(use-modules (ice-9 format)) + +(define-method (write (obj <2D-vector>) port) + (display (format #f "<~S, ~S>" (x-component obj) (y-component obj)) + port)) + +(define v (make <2D-vector> #:x 3 #:y 4)) + +v --> <3, 4> +@end group + +@group +(define-method (+ (x <2D-vector>) (y <2D-vector>)) + (make <2D-vector> + #:x (+ (x-component x) (x-component y)) + #:y (+ (y-component x) (y-component y)))) + +(+ v v) --> <6, 8> +@end group +@end smalllisp + +@node Asking for the type of an object, , User-defined types, Getting Started +@subsection Types + +@example +(class-of v) --> #< <2D-vector> 40241ac0> +<2D-vector> --> #< <2D-vector> 40241ac0> +(class-of 1) --> #< 401b2a98> + --> #< 401b2a98> + +(is-a? v <2D-vector>) --> #t +@end example + +@node Reference Manual, MOP Specification, Getting Started, Top +@chapter Reference Manual + +This chapter is the GOOPS reference manual. It aims to describe all the +syntax, procedures, options and associated concepts that a typical +application author would need to understand in order to use GOOPS +effectively in their application. It also describes what is meant by +the GOOPS ``metaobject protocol'' (aka ``MOP''), and indicates how +authors can use the metaobject protocol to customize the behaviour of +GOOPS itself. + +For a detailed specification of the GOOPS metaobject protocol, see +@ref{MOP Specification}. + +@menu +* Introductory Remarks:: +* Defining New Classes:: +* Creating Instances:: +* Accessing Slots:: +* Creating Generic Functions:: +* Adding Methods to Generic Functions:: +* Invoking Generic Functions:: +* Redefining a Class:: +* Changing the Class of an Instance:: +* Introspection:: +* Miscellaneous Functions:: +@end menu + +@node Introductory Remarks +@section Introductory Remarks + +GOOPS is an object-oriented programming system based on a ``metaobject +protocol'' derived from the ones used in CLOS (the Common Lisp Object +System), tiny-clos (a small Scheme implementation of a subset of CLOS +functionality) and STKlos. + +GOOPS can be used by application authors at a basic level without any +need to understand what the metaobject protocol (aka ``MOP'') is and how +it works. On the other hand, the MOP underlies even the customizations +that application authors are likely to make use of very quickly --- such +as defining an @code{initialize} method to customize the initialization +of instances of an application-defined class --- and an understanding of +the MOP makes it much easier to explain such customizations in a precise +way. And in the long run, understanding the MOP is the key both to +understanding GOOPS at a deeper level and to taking full advantage of +GOOPS' power, by customizing the behaviour of GOOPS itself. + +Each of the following sections of the reference manual is arranged +such that the most basic usage is introduced first, and then subsequent +subsections discuss the related internal functions and metaobject +protocols, finishing with a description of how to customize that area of +functionality. + +These introductory remarks continue with a few words about metaobjects +and the MOP. Readers who do not want to be bothered yet with the MOP +and customization could safely skip this subsection on a first reading, +and should correspondingly skip subsequent subsections that are +concerned with internals and customization. + +In general, this reference manual assumes familiarity with standard +object oriented concepts and terminology. However, some of the terms +used in GOOPS is less well known, so the Terminology subsection +provides definitions for these terms. + +@menu +* Metaobjects and the Metaobject Protocol:: +* Terminology:: +@end menu + +@node Metaobjects and the Metaobject Protocol +@subsection Metaobjects and the Metaobject Protocol + +The conceptual building blocks of GOOPS are classes, slot definitions, +instances, generic functions and methods. A class is a grouping of +inheritance relations and slot definitions. An instance is an object +with slots that are allocated following the rules implied by its class's +superclasses and slot definitions. A generic function is a collection +of methods and rules for determining which of those methods to apply +when the generic function is invoked. A method is a procedure and a set +of specializers that specify the type of arguments to which the +procedure is applicable. + +Of these entities, GOOPS represents classes, generic functions and +methods as ``metaobjects''. In other words, the values in a GOOPS +program that describe classes, generic functions and methods, are +themselves instances (or ``objects'') of special GOOPS classes that +encapsulate the behaviour, respectively, of classes, generic functions, +and methods. + +(The other two entities are slot definitions and instances. Slot +definitions are not strictly instances, but every slot definition is +associated with a GOOPS class that specifies the behaviour of the slot +as regards accessibility and protection from garbage collection. +Instances are of course objects in the usual sense, and there is no +benefit from thinking of them as metaobjects.) + +The ``metaobject protocol'' (aka ``MOP'') is the specification of the +generic functions which determine the behaviour of these metaobjects and +the circumstances in which these generic functions are invoked. + +For a concrete example of what this means, consider how GOOPS calculates +the set of slots for a class that is being defined using +@code{define-class}. The desired set of slots is the union of the new +class's direct slots and the slots of all its superclasses. But +@code{define-class} itself does not perform this calculation. Instead, +there is a method of the @code{initialize} generic function that is +specialized for instances of type @code{}, and it is this method +that performs the slot calculation. + +@code{initialize} is a generic function which GOOPS calls whenever a new +instance is created, immediately after allocating memory for a new +instance, in order to initialize the new instance's slots. The sequence +of steps is as follows. + +@itemize @bullet +@item +@code{define-class} uses @code{make} to make a new instance of the +@code{}, passing as initialization arguments the superclasses, +slot definitions and class options that were specified in the +@code{define-class} form. + +@item +@code{make} allocates memory for the new instance, and then invokes the +@code{initialize} generic function to initialize the new instance's +slots. + +@item +The @code{initialize} generic function applies the method that is +specialized for instances of type @code{}, and this method +performs the slot calculation. +@end itemize + +In other words, rather than being hardcoded in @code{define-class}, the +behaviour of class definition is encapsulated by generic function +methods that are specialized for the class @code{}. + +It is possible to create a new class that inherits from @code{}, +which is called a ``metaclass'', and to write a new @code{initialize} +method that is specialized for instances of the new metaclass. Then, if +the @code{define-class} form includes a @code{#:metaclass} class option +whose value is the new metaclass, the class that is defined by the +@code{define-class} form will be an instance of the new metaclass rather +than of the default @code{}, and will be defined in accordance +with the new @code{initialize} method. Thus the default slot +calculation, as well as any other aspect of the new class's relationship +with its superclasses, can be modified or overridden. + +In a similar way, the behaviour of generic functions can be modified or +overridden by creating a new class that inherits from the standard +generic function class @code{}, writing appropriate methods +that are specialized to the new class, and creating new generic +functions that are instances of the new class. + +The same is true for method metaobjects. And the same basic mechanism +allows the application class author to write an @code{initialize} method +that is specialized to their application class, to initialize instances +of that class. + +Such is the power of the MOP. Note that @code{initialize} is just one +of a large number of generic functions that can be customized to modify +the behaviour of application objects and classes and of GOOPS itself. +Each subsequent section of the reference manual covers a particular area +of GOOPS functionality, and describes the generic functions that are +relevant for customization of that area. + +We conclude this subsection by emphasizing a point that may seem +obvious, but contrasts with the corresponding situation in some other +MOP implementations, such as CLOS. The point is simply that an +identifier which represents a GOOPS class or generic function is a +variable with a first-class value, the value being an instance of class +@code{} or @code{}. (In CLOS, on the other hand, a +class identifier is a symbol that indexes the corresponding class +metaobject in a separate namespace for classes.) This is, of course, +simply an extension of the tendency in Scheme to avoid the unnecessary +use of, on the one hand, syntactic forms that require unevaluated +arguments and, on the other, separate identifier namespaces (e.g. for +class names), but it is worth noting that GOOPS conforms fully to this +Schemely principle. + +@node Terminology +@subsection Terminology + +It is assumed that the reader is already familiar with standard object +orientation concepts such as classes, objects/instances, +inheritance/subclassing, generic functions and methods, encapsulation +and polymorphism. + +This section explains some of the less well known concepts and +terminology that GOOPS uses, which are assumed by the following sections +of the reference manual. + +@menu +* Metaclass:: +* Class Precedence List:: +* Accessor:: +@end menu + +@node Metaclass +@subsubsection Metaclass + +A @dfn{metaclass} is the class of an object which represents a GOOPS +class. Put more succinctly, a metaclass is a class's class. + +Most GOOPS classes have the metaclass @code{} and, by default, +any new class that is created using @code{define-class} has the +metaclass @code{}. + +But what does this really mean? To find out, let's look in more detail +at what happens when a new class is created using @code{define-class}: + +@example +(define-class () . slots) +@end example + +GOOPS actually expands the @code{define-class} form to something like +this + +@example +(define (class () . slots)) +@end example + +and thence to + +@example +(define + (make #:supers (list ) #:slots slots)) +@end example + +In other words, the value of @code{} is in fact an instance of +the class @code{} with slot values specifying the superclasses +and slot definitions for the class @code{}. (@code{#:supers} +and @code{#:slots} are initialization keywords for the @code{dsupers} +and @code{dslots} slots of the @code{} class.) + +In order to take advantage of the full power of the GOOPS metaobject +protocol (@pxref{MOP Specification}), it is sometimes desirable to +create a new class with a metaclass other than the default +@code{}. This is done by writing: + +@example +(define-class () + slot @dots{} + #:metaclass ) +@end example + +GOOPS expands this to something like: + +@example +(define + (make #:supers (list ) #:slots slots)) +@end example + +In this case, the value of @code{} is an instance of the more +specialized class @code{}. Note that +@code{} itself must previously have been defined as a +subclass of @code{}. For a full discussion of when and how it is +useful to define new metaclasses, see @ref{MOP Specification}. + +Now let's make an instance of @code{}: + +@example +(define my-object (make ...)) +@end example + +All of the following statements are correct expressions of the +relationships between @code{my-object}, @code{}, +@code{} and @code{}. + +@itemize @bullet +@item +@code{my-object} is an instance of the class @code{}. + +@item +@code{} is an instance of the class @code{}. + +@item +@code{} is an instance of the class @code{}. + +@item +The class of @code{my-object} is @code{}. + +@item +The metaclass of @code{my-object} is @code{}. + +@item +The class of @code{} is @code{}. + +@item +The metaclass of @code{} is @code{}. + +@item +The class of @code{} is @code{}. + +@item +The metaclass of @code{} is @code{}. + +@item +@code{} is not a metaclass, since it is does not inherit from +@code{}. + +@item +@code{} is a metaclass, since it inherits from +@code{}. +@end itemize + +@node Class Precedence List +@subsubsection Class Precedence List + +The @dfn{class precedence list} of a class is the list of all direct and +indirect superclasses of that class, including the class itself. + +In the absence of multiple inheritance, the class precedence list is +ordered straightforwardly, beginning with the class itself and ending +with @code{}. + +For example, given this inheritance hierarchy: + +@example +(define-class () @dots{}) +(define-class () @dots{}) +(define-class () @dots{}) +@end example + +the class precedence list of would be + +@example +( ) +@end example + +With multiple inheritance, the algorithm is a little more complicated. +A full description is provided by the GOOPS Tutorial: see @ref{Class +precedence list}. + +``Class precedence list'' is often abbreviated, in documentation and +Scheme variable names, to @dfn{cpl}. + +@node Accessor +@subsubsection Accessor + +An @dfn{accessor} is a generic function with both reference and setter +methods. + +@example +(define-accessor perimeter) +@end example + +Reference methods for an accessor are defined in the same way as generic +function methods. + +@example +(define-method (perimeter (s )) + (* 4 (side-length s))) +@end example + +Setter methods for an accessor are defined by specifying ``(setter +)'' as the first parameter of the @code{define-method} +call. + +@example +(define-method ((setter perimeter) (s ) (n )) + (set! (side-length s) (/ n 4))) +@end example + +Once an appropriate setter method has been defined in this way, it can +be invoked using the generalized @code{set!} syntax, as in: + +@example +(set! (perimeter s1) 18.3) +@end example + +@node Defining New Classes +@section Defining New Classes + +[ *fixme* Somewhere in this manual there needs to be an introductory +discussion about GOOPS classes, generic functions and methods, covering + +@itemize @bullet +@item +how classes encapsulate related items of data in @dfn{slots} + +@item +why it is that, unlike in C++ and Java, a class does not encapsulate the +methods that act upon the class (at least not in the C++/Java sense) + +@item +how generic functions provide a more general solution that provides for +dispatch on all argument types, and avoids idiosyncracies like C++'s +friend classes + +@item +how encapsulation in the sense of data- and code-hiding, or of +distinguishing interface from implementation, is treated in Guile as an +orthogonal concept to object orientation, and is the responsibility of +the module system. +@end itemize + +Some of this is covered in the Tutorial chapter, in @ref{Generic +functions and methods} - perhaps the best solution would be to expand +the discussion there. ] + +@menu +* Basic Class Definition:: +* Class Options:: +* Slot Options:: +* Class Definition Internals:: +* Customizing Class Definition:: +* STKlos Compatibility:: +@end menu + +@node Basic Class Definition +@subsection Basic Class Definition + +New classes are defined using the @code{define-class} syntax, with +arguments that specify the classes that the new class should inherit +from, the direct slots of the new class, and any required class options. + +@deffn syntax define-class name (super @dots{}) slot-definition @dots{} . options +Define a class called @var{name} that inherits from @var{super}s, with +direct slots defined by @var{slot-definition}s and class options +@var{options}. The newly created class is bound to the variable name +@var{name} in the current environment. + +Each @var{slot-definition} is either a symbol that names the slot or a +list, + +@example +(@var{slot-name-symbol} . @var{slot-options}) +@end example + +where @var{slot-name-symbol} is a symbol and @var{slot-options} is a +list with an even number of elements. The even-numbered elements of +@var{slot-options} (counting from zero) are slot option keywords; the +odd-numbered elements are the corresponding values for those keywords. + +@var{options} is a similarly structured list containing class option +keywords and corresponding values. +@end deffn + +The standard GOOPS class and slot options are described in the following +subsections: see @ref{Class Options} and @ref{Slot Options}. + +Example 1. Define a class that combines two pre-existing classes by +inheritance but adds no new slots. + +@example +(define-class ( )) +@end example + +Example 2. Define a @code{regular-polygon} class with slots for side +length and number of sides that have default values and can be accessed +via the generic functions @code{side-length} and @code{num-sides}. + +@example +(define-class () + (sl #:init-value 1 #:accessor side-length) + (ns #:init-value 5 #:accessor num-sides)) +@end example + +Example 3. Define a class whose behavior (and that of its instances) is +customized via an application-defined metaclass. + +@example +(define-class () + (s #:init-value #f #:accessor state) + ... + #:metaclass ) +@end example + +@node Class Options +@subsection Class Options + +@deffn {class option} #:metaclass metaclass +The @code{#:metaclass} class option specifies the metaclass of the class +being defined. @var{metaclass} must be a class that inherits from +@code{}. For an introduction to the use of metaclasses, see +@ref{Metaobjects and the Metaobject Protocol} and @ref{Metaclass}. + +If the @code{#:metaclass} option is absent, GOOPS reuses or constructs a +metaclass for the new class by calling @code{ensure-metaclass} +(@pxref{Class Definition Internals,, ensure-metaclass}). +@end deffn + +@deffn {class option} #:name name +The @code{#:name} class option specifies the new class's name. This +name is used to identify the class whenever related objects - the class +itself, its instances and its subclasses - are printed. + +If the @code{#:name} option is absent, GOOPS uses the first argument to +@code{define-class} as the class name. +@end deffn + +@deffn {class option} #:environment environment +*fixme* Not sure about this one, but I think that the +@code{#:environment} option specifies the environment in which the +class's getters and setters are computed and evaluated. + +If the @code{#:environment} option is not specified, the class's +environment defaults to the top-level environment in which the +@code{define-class} form appears. +@end deffn + +@node Slot Options +@subsection Slot Options + +@deffn {slot option} #:allocation allocation +The @code{#:allocation} option tells GOOPS how to allocate storage for +the slot. Possible values for @var{allocation} are + +@itemize @bullet +@item @code{#:instance} + +Indicates that GOOPS should create separate storage for this slot in +each new instance of the containing class (and its subclasses). + +@item @code{#:class} + +Indicates that GOOPS should create storage for this slot that is shared +by all instances of the containing class (and its subclasses). In other +words, a slot in class @var{C} with allocation @code{#:class} is shared +by all @var{instance}s for which @code{(is-a? @var{instance} @var{c})}. + +@item @code{#:each-subclass} + +Indicates that GOOPS should create storage for this slot that is shared +by all @emph{direct} instances of the containing class, and that +whenever a subclass of the containing class is defined, GOOPS should +create a new storage for the slot that is shared by all @emph{direct} +instances of the subclass. In other words, a slot with allocation +@code{#:each-subclass} is shared by all instances with the same +@code{class-of}. + +@item @code{#:virtual} + +Indicates that GOOPS should not allocate storage for this slot. The +slot definition must also include the @code{#:slot-ref} and +@code{#:slot-set!} options to specify how to reference and set the value +for this slot. +@end itemize + +The default value is @code{#:instance}. + +Slot allocation options are processed when defining a new class by the +generic function @code{compute-get-n-set}, which is specialized by the +class's metaclass. Hence new types of slot allocation can be +implemented by defining a new metaclass and a method for +@code{compute-get-n-set} that is specialized for the new metaclass. For +an example of how to do this, see @ref{Customizing Class Definition}. +@end deffn + +@deffn {slot option} #:slot-ref getter +@deffnx {slot option} #:slot-set! setter +The @code{#:slot-ref} and @code{#:slot-set!} options must be specified +if the slot allocation is @code{#:virtual}, and are ignored otherwise. + +@var{getter} should be a closure taking a single @var{instance} parameter +that returns the current slot value. @var{setter} should be a closure +taking two parameters - @var{instance} and @var{new-val} - that sets the +slot value to @var{new-val}. +@end deffn + +@deffn {slot option} #:getter getter +@deffnx {slot option} #:setter setter +@deffnx {slot option} #:accessor accessor +These options, if present, tell GOOPS to create generic function and +method definitions that can be used to get and set the slot value more +conveniently than by using @code{slot-ref} and @code{slot-set!}. + +@var{getter} specifies a generic function to which GOOPS will add a +method for getting the slot value. @var{setter} specifies a generic +function to which GOOPS will add a method for setting the slot value. +@var{accessor} specifies an accessor to which GOOPS will add methods for +both getting and setting the slot value. + +So if a class includes a slot definition like this: + +@example +(c #:getter get-count #:setter set-count #:accessor count) +@end example + +GOOPS defines generic function methods such that the slot value can be +referenced using either the getter or the accessor - + +@example +(let ((current-count (get-count obj))) @dots{}) +(let ((current-count (count obj))) @dots{}) +@end example + +- and set using either the setter or the accessor - + +@example +(set-count obj (+ 1 current-count)) +(set! (count obj) (+ 1 current-count)) +@end example + +Note that + +@itemize @bullet +@item +with an accessor, the slot value is set using the generalized +@code{set!} syntax + +@item +in practice, it is unusual for a slot to use all three of these options: +read-only, write-only and read-write slots would typically use only +@code{#:getter}, @code{#:setter} and @code{#:accessor} options +respectively. +@end itemize + +If the specified names are already bound in the top-level environment to +values that cannot be upgraded to generic functions, those values are +overwritten during evaluation of the @code{define-class} that contains +the slot definition. For details, see @ref{Generic Function Internals,, +ensure-generic}. +@end deffn + +@deffn {slot option} #:init-value init-value +@deffnx {slot option} #:init-form init-form +@deffnx {slot option} #:init-thunk init-thunk +@deffnx {slot option} #:init-keyword init-keyword +These options provide various ways to specify how to initialize the +slot's value at instance creation time. @var{init-value} is a fixed +value. @var{init-thunk} is a procedure of no arguments that is called +when a new instance is created and should return the desired initial +slot value. @var{init-form} is an unevaluated expression that gets +evaluated when a new instance is created and should return the desired +initial slot value. @var{init-keyword} is a keyword that can be used to +pass an initial slot value to @code{make} when creating a new instance. + +If more than one of these options is specified for the same slot, the +order of precedence, highest first is + +@itemize @bullet +@item +@code{#:init-keyword}, if @var{init-keyword} is present in the options +passed to @code{make} + +@item +@code{#:init-thunk}, @code{#:init-form} or @code{#:init-value}. +@end itemize + +If the slot definition contains more than one initialization option of +the same precedence, the later ones are ignored. If a slot is not +initialized at all, its value is unbound. + +In general, slots that are shared between more than one instance are +only initialized at new instance creation time if the slot value is +unbound at that time. However, if the new instance creation specifies +a valid init keyword and value for a shared slot, the slot is +re-initialized regardless of its previous value. + +Note, however, that the power of GOOPS' metaobject protocol means that +everything written here may be customized or overridden for particular +classes! The slot initializations described here are performed by the least +specialized method of the generic function @code{initialize}, whose +signature is + +@example +(define-method (initialize (object ) initargs) ...) +@end example + +The initialization of instances of any given class can be customized by +defining a @code{initialize} method that is specialized for that class, +and the author of the specialized method may decide to call +@code{next-method} - which will result in a call to the next less +specialized @code{initialize} method - at any point within the +specialized code, or maybe not at all. In general, therefore, the +initialization mechanisms described here may be modified or overridden by +more specialized code, or may not be supported at all for particular +classes. +@end deffn + +@node Class Definition Internals +@subsection Class Definition Internals + +Implementation notes: @code{define-class} expands to an expression which + +@itemize @bullet +@item +checks that it is being evaluated only at top level + +@item +defines any accessors that are implied by the @var{slot-definition}s + +@item +uses @code{class} to create the new class (@pxref{Class Definition +Internals,, class}) + +@item +checks for a previous class definition for @var{name} and, if found, +handles the redefinition by invoking @code{class-redefinition} +(@pxref{Redefining a Class}). +@end itemize + +@deffn syntax class name (super @dots{}) slot-definition @dots{} . options +Return a newly created class that inherits from @var{super}s, with +direct slots defined by @var{slot-definition}s and class options +@var{options}. For the format of @var{slot-definition}s and +@var{options}, see @ref{Basic Class Definition,, define-class}. +@end deffn + +Implementation notes: @code{class} expands to an expression which + +@itemize @bullet +@item +processes the class and slot definition options to check that they are +well-formed, to convert the @code{#:init-form} option to an +@code{#:init-thunk} option, to supply a default environment parameter +(the current top-level environment) and to evaluate all the bits that +need to be evaluated + +@item +calls @code{make-class} to create the class with the processed and +evaluated parameters. +@end itemize + +@deffn procedure make-class supers slots . options +Return a newly created class that inherits from @var{supers}, with +direct slots defined by @var{slots} and class options @var{options}. +For the format of @var{slots} and @var{options}, see @ref{Basic Class +Definition,, define-class}, except note that for @code{make-class}, +@var{slots} and @var{options} are separate list parameters: @var{slots} +here is a list of slot definitions. +@end deffn + +Implementation notes: @code{make-class} + +@itemize @bullet +@item +adds @code{} to the @var{supers} list if @var{supers} is empty +or if none of the classes in @var{supers} have @code{} in their +class precedence list + +@item +defaults the @code{#:environment}, @code{#:name} and @code{#:metaclass} +options, if they are not specified by @var{options}, to the current +top-level environment, the unbound value, and @code{(ensure-metaclass +@var{supers})} respectively (@pxref{Class Definition Internals,, +ensure-metaclass}) + +@item +checks for duplicate classes in @var{supers} and duplicate slot names in +@var{slots}, and signals an error if there are any duplicates + +@item +calls @code{make}, passing the metaclass as the first parameter and all +other parameters as option keywords with values. +@end itemize + +@deffn procedure ensure-metaclass supers env +Return a metaclass suitable for a class that inherits from the list of +classes in @var{supers}. The returned metaclass is the union by +inheritance of the metaclasses of the classes in @var{supers}. + +In the simplest case, where all the @var{supers} are straightforward +classes with metaclass @code{}, the returned metaclass is just +@code{}. + +For a more complex example, suppose that @var{supers} contained one +class with metaclass @code{} and one with metaclass +@code{}. Then the returned metaclass would be a +class that inherits from both @code{} and +@code{}. + +If @var{supers} is the empty list, @code{ensure-metaclass} returns the +default GOOPS metaclass @code{}. + +GOOPS keeps a list of the metaclasses created by +@code{ensure-metaclass}, so that each required type of metaclass only +has to be created once. + +The @code{env} parameter is ignored. +@end deffn + +@deffn procedure ensure-metaclass-with-supers meta-supers +@code{ensure-metaclass-with-supers} is an internal procedure used by +@code{ensure-metaclass} (@pxref{Class Definition Internals,, +ensure-metaclass}). It returns a metaclass that is the union by +inheritance of the metaclasses in @var{meta-supers}. +@end deffn + +The internals of @code{make}, which is ultimately used to create the new +class object, are described in @ref{Customizing Instance Creation}, +which covers the creation and initialization of instances in general. + +@node Customizing Class Definition +@subsection Customizing Class Definition + +During the initialization of a new class, GOOPS calls a number of generic +functions with the newly allocated class instance as the first +argument. Specifically, GOOPS calls the generic function + +@itemize @bullet +@item +(initialize @var{class} @dots{}) +@end itemize + +where @var{class} is the newly allocated class instance, and the default +@code{initialize} method for arguments of type @code{} calls the +generic functions + +@itemize @bullet +@item +(compute-cpl @var{class}) + +@item +(compute-slots @var{class}) + +@item +(compute-get-n-set @var{class} @var{slot-def}), for each of the slot +definitions returned by @code{compute-slots} + +@item +(compute-getter-method @var{class} @var{slot-def}), for each of the +slot definitions returned by @code{compute-slots} that includes a +@code{#:getter} or @code{#:accessor} slot option + +@item +(compute-setter-method @var{class} @var{slot-def}), for each of the +slot definitions returned by @code{compute-slots} that includes a +@code{#:setter} or @code{#:accessor} slot option. +@end itemize + +If the metaclass of the new class is something more specialized than the +default @code{}, then the type of @var{class} in the calls above +is more specialized than @code{}, and hence it becomes possible +to define generic function methods, specialized for the new class's +metaclass, that can modify or override the default behaviour of +@code{initialize}, @code{compute-cpl} or @code{compute-get-n-set}. + +@code{compute-cpl} computes the class precedence list (``CPL'') for the +new class (@pxref{Class precedence list}), and returns it as a list of +class objects. The CPL is important because it defines a superclass +ordering that is used, when a generic function is invoked upon an +instance of the class, to decide which of the available generic function +methods is the most specific. Hence @code{compute-cpl} could be +customized in order to modify the CPL ordering algorithm for all classes +with a special metaclass. + +The default CPL algorithm is encapsulated by the @code{compute-std-cpl} +procedure, which is in turn called by the default @code{compute-cpl} +method. + +@deffn procedure compute-std-cpl class +Compute and return the class precedence list for @var{class} according +to the algorithm described in @ref{Class precedence list}. +@end deffn + +@code{compute-slots} computes and returns a list of all slot definitions +for the new class. By default, this list includes the direct slot +definitions from the @code{define-class} form, plus the slot definitions +that are inherited from the new class's superclasses. The default +@code{compute-slots} method uses the CPL computed by @code{compute-cpl} +to calculate this union of slot definitions, with the rule that slots +inherited from superclasses are shadowed by direct slots with the same +name. One possible reason for customizing @code{compute-slots} would be +to implement an alternative resolution strategy for slot name conflicts. + +@code{compute-get-n-set} computes the low-level closures that will be +used to get and set the value of a particular slot, and returns them in +a list with two elements. + +The closures returned depend on how storage for that slot is allocated. +The standard @code{compute-get-n-set} method, specialized for classes of +type @code{}, handles the standard GOOPS values for the +@code{#:allocation} slot option (@pxref{Slot Options,, allocation}). By +defining a new @code{compute-get-n-set} method for a more specialized +metaclass, it is possible to support new types of slot allocation. + +Suppose you wanted to create a large number of instances of some class +with a slot that should be shared between some but not all instances of +that class - say every 10 instances should share the same slot storage. +The following example shows how to implement and use a new type of slot +allocation to do this. + +@example +(define-class ()) + +(let ((batch-allocation-count 0) + (batch-get-n-set #f)) + (define-method (compute-get-n-set (class ) s) + (case (slot-definition-allocation s) + ((#:batched) + ;; If we've already used the same slot storage for 10 instances, + ;; reset variables. + (if (= batch-allocation-count 10) + (begin + (set! batch-allocation-count 0) + (set! batch-get-n-set #f))) + ;; If we don't have a current pair of get and set closures, + ;; create one. make-closure-variable returns a pair of closures + ;; around a single Scheme variable - see goops.scm for details. + (or batch-get-n-set + (set! batch-get-n-set (make-closure-variable))) + ;; Increment the batch allocation count. + (set! batch-allocation-count (+ batch-allocation-count 1)) + batch-get-n-set) + + ;; Call next-method to handle standard allocation types. + (else (next-method))))) + +(define-class () + ... + (c #:allocation #:batched) + ... + #:metaclass ) +@end example + +The usage of @code{compute-getter-method} and @code{compute-setter-method} +is described in @ref{MOP Specification}. + +@code{compute-cpl} and @code{compute-get-n-set} are called by the +standard @code{initialize} method for classes whose metaclass is +@code{}. But @code{initialize} itself can also be modified, by +defining an @code{initialize} method specialized to the new class's +metaclass. Such a method could complete override the standard +behaviour, by not calling @code{(next-method)} at all, but more +typically it would perform additional class initialization steps before +and/or after calling @code{(next-method)} for the standard behaviour. + +@node STKlos Compatibility +@subsection STKlos Compatibility + +If the STKlos compatibility module is loaded, @code{define-class} is +overwritten by a STKlos-specific definition; the standard GOOPS +definition of @code{define-class} remains available in +@code{standard-define-class}. + +@deffn syntax standard-define-class name (super @dots{}) slot-definition @dots{} . options +@code{standard-define-class} is equivalent to the standard GOOPS +@code{define-class}. +@end deffn + +@node Creating Instances +@section Creating Instances + +@menu +* Basic Instance Creation:: +* Customizing Instance Creation:: +@end menu + +@node Basic Instance Creation +@subsection Basic Instance Creation + +To create a new instance of any GOOPS class, use the generic function +@code{make} or @code{make-instance}, passing the required class and any +appropriate instance initialization arguments as keyword and value +pairs. Note that @code{make} and @code{make-instances} are aliases for +each other - their behaviour is identical. + +@deffn generic make +@deffnx method make (class ) . initargs +Create and return a new instance of class @var{class}, initialized using +@var{initargs}. + +In theory, @var{initargs} can have any structure that is understood by +whatever methods get applied when the @code{initialize} generic function +is applied to the newly allocated instance. + +In practice, specialized @code{initialize} methods would normally call +@code{(next-method)}, and so eventually the standard GOOPS +@code{initialize} methods are applied. These methods expect +@var{initargs} to be a list with an even number of elements, where +even-numbered elements (counting from zero) are keywords and +odd-numbered elements are the corresponding values. + +GOOPS processes initialization argument keywords automatically for slots +whose definition includes the @code{#:init-keyword} option (@pxref{Slot +Options,, init-keyword}). Other keyword value pairs can only be +processed by an @code{initialize} method that is specialized for the new +instance's class. Any unprocessed keyword value pairs are ignored. +@end deffn + +@deffn generic make-instance +@deffnx method make-instance (class ) . initargs +@code{make-instance} is an alias for @code{make}. +@end deffn + +@node Customizing Instance Creation +@subsection Customizing Instance Creation + +@code{make} itself is a generic function. Hence the @code{make} +invocation itself can be customized in the case where the new instance's +metaclass is more specialized than the default @code{}, by +defining a @code{make} method that is specialized to that metaclass. + +Normally, however, the method for classes with metaclass @code{} +will be applied. This method calls two generic functions: + +@itemize @bullet +@item +(allocate-instance @var{class} . @var{initargs}) + +@item +(initialize @var{instance} . @var{initargs}) +@end itemize + +@code{allocate-instance} allocates storage for and returns the new +instance, uninitialized. You might customize @code{allocate-instance}, +for example, if you wanted to provide a GOOPS wrapper around some other +object programming system. + +To do this, you would create a specialized metaclass, which would act as +the metaclass for all classes and instances from the other system. Then +define an @code{allocate-instance} method, specialized to that +metaclass, which calls a Guile primitive C function, which in turn +allocates the new instance using the interface of the other object +system. + +In this case, for a complete system, you would also need to customize a +number of other generic functions like @code{make} and +@code{initialize}, so that GOOPS knows how to make classes from the +other system, access instance slots, and so on. + +@code{initialize} initializes the instance that is returned by +@code{allocate-instance}. The standard GOOPS methods perform +initializations appropriate to the instance class. + +@itemize @bullet +@item +At the least specialized level, the method for instances of type +@code{} performs internal GOOPS instance initialization, and +initializes the instance's slots according to the slot definitions and +any slot initialization keywords that appear in @var{initargs}. + +@item +The method for instances of type @code{} calls +@code{(next-method)}, then performs the class initializations described +in @ref{Customizing Class Definition}. + +@item +and so on for generic functions, method, operator classes @dots{} +@end itemize + +Similarly, you can customize the initialization of instances of any +application-defined class by defining an @code{initialize} method +specialized to that class. + +Imagine a class whose instances' slots need to be initialized at +instance creation time by querying a database. Although it might be +possible to achieve this a combination of @code{#:init-thunk} keywords +and closures in the slot definitions, it is neater to write an +@code{initialize} method for the class that queries the database once +and initializes all the dependent slot values according to the results. + +@node Accessing Slots +@section Accessing Slots + +The definition of a slot contains at the very least a slot name, and may +also contain various slot options, including getter, setter and/or +accessor functions for the slot. + +It is always possible to access slots by name, using the various +``slot-ref'' and ``slot-set!'' procedures described in the following +subsections. For example, + +@example +(define-class () ;; Define a class with slots + (count #:init-value 0) ;; named "count" and "cache". + (cache #:init-value '()) + @dots{}) + +(define inst (make )) ;; Make an instance of this class. + +(slot-set! inst 'count 5) ;; Set the value of the "count" + ;; slot to 5. + +(slot-set! inst 'cache ;; Modify the value of the + (cons (cons "^it" "It") ;; "cache" slot. + (slot-ref inst 'cache))) +@end example + +If a slot definition includes a getter, setter or accessor function, +these can be used instead of @code{slot-ref} and @code{slot-set!} to +access the slot. + +@example +(define-class () ;; Define a new class whose slots + (count #:setter set-count) ;; use a getter, a setter and + (cache #:accessor cache) ;; an accessor. + (csize #:getter cache-size) + @dots{}) + +(define inst (make )) ;; Make an instance of this class. + +(set-count inst 5) ;; Set the value of the "count" + ;; slot to 5. + +(set! (cache inst) ;; Modify the value of the + (cons (cons "^it" "It") ;; "cache" slot. + (cache inst))) + +(let ((size (cache-size inst))) ;; Get the value of the "csize" + @dots{}) ;; slot. +@end example + +Whichever of these methods is used to access slots, GOOPS always calls +the low-level @dfn{getter} and @dfn{setter} closures for the slot to get +and set its value. These closures make sure that the slot behaves +according to the @code{#:allocation} type that was specified in the slot +definition (@pxref{Slot Options,, allocation}). (For more about these +closures, see @ref{Customizing Class Definition,, compute-get-n-set}.) + +@menu +* Instance Slots:: +* Class Slots:: +* Handling Slot Access Errors:: +@end menu + +@node Instance Slots +@subsection Instance Slots + +Any slot, regardless of its allocation, can be queried, referenced and +set using the following four primitive procedures. + +@deffn {primitive procedure} slot-exists? obj slot-name +Return @code{#t} if @var{obj} has a slot with name @var{slot-name}, +otherwise @code{#f}. +@end deffn + +@deffn {primitive procedure} slot-bound? obj slot-name +Return @code{#t} if the slot named @var{slot-name} in @var{obj} has a +value, otherwise @code{#f}. + +@code{slot-bound?} calls the generic function @code{slot-missing} if +@var{obj} does not have a slot called @var{slot-name} (@pxref{Handling +Slot Access Errors, slot-missing}). +@end deffn + +@deffn {primitive procedure} slot-ref obj slot-name +Return the value of the slot named @var{slot-name} in @var{obj}. + +@code{slot-ref} calls the generic function @code{slot-missing} if +@var{obj} does not have a slot called @var{slot-name} (@pxref{Handling +Slot Access Errors, slot-missing}). + +@code{slot-ref} calls the generic function @code{slot-unbound} if the +named slot in @var{obj} does not have a value (@pxref{Handling Slot +Access Errors, slot-unbound}). +@end deffn + +@deffn {primitive procedure} slot-set! obj slot-name value +Set the value of the slot named @var{slot-name} in @var{obj} to @var{value}. + +@code{slot-set!} calls the generic function @code{slot-missing} if +@var{obj} does not have a slot called @var{slot-name} (@pxref{Handling +Slot Access Errors, slot-missing}). +@end deffn + +GOOPS stores information about slots in class metaobjects. Internally, +all of these procedures work by looking up the slot definition for the +slot named @var{slot-name} in the class metaobject for @code{(class-of +@var{obj})}, and then using the slot definition's ``getter'' and +``setter'' closures to get and set the slot value. + +The next four procedures differ from the previous ones in that they take +the class metaobject as an explicit argument, rather than assuming +@code{(class-of @var{obj})}. Therefore they allow you to apply the +``getter'' and ``setter'' closures of a slot definition in one class to +an instance of a different class. + +[ *fixme* I have no idea why this is useful! Perhaps when a slot in +@code{(class-of @var{obj})} shadows a slot with the same name in one of +its superclasses? There should be an enlightening example here. ] + +@deffn {primitive procedure} slot-exists-using-class? class obj slot-name +Return @code{#t} if the class metaobject @var{class} has a slot +definition for a slot with name @var{slot-name}, otherwise @code{#f}. +@end deffn + +@deffn {primitive procedure} slot-bound-using-class? class obj slot-name +Return @code{#t} if applying @code{slot-ref-using-class} to the same +arguments would call the generic function @code{slot-unbound}, otherwise +@code{#f}. + +@code{slot-bound-using-class?} calls the generic function +@code{slot-missing} if @var{class} does not have a slot definition for a +slot called @var{slot-name} (@pxref{Handling Slot Access Errors, +slot-missing}). +@end deffn + +@deffn {primitive procedure} slot-ref-using-class class obj slot-name +Apply the ``getter'' closure for the slot named @var{slot-name} in +@var{class} to @var{obj}, and return its result. + +@code{slot-ref-using-class} calls the generic function +@code{slot-missing} if @var{class} does not have a slot definition for a +slot called @var{slot-name} (@pxref{Handling Slot Access Errors, +slot-missing}). + +@code{slot-ref-using-class} calls the generic function +@code{slot-unbound} if the application of the ``getter'' closure to +@var{obj} returns an unbound value (@pxref{Handling Slot Access Errors, +slot-unbound}). +@end deffn + +@deffn {primitive procedure} slot-set-using-class! class obj slot-name value +Apply the ``setter'' closure for the slot named @var{slot-name} in +@var{class} to @var{obj} and @var{value}. + +@code{slot-set-using-class!} calls the generic function +@code{slot-missing} if @var{class} does not have a slot definition for a +slot called @var{slot-name} (@pxref{Handling Slot Access Errors, +slot-missing}). +@end deffn + +@node Class Slots +@subsection Class Slots + +Slots whose allocation is per-class rather than per-instance can be +referenced and set without needing to specify any particular instance. + +@deffn procedure class-slot-ref class slot-name +Return the value of the slot named @var{slot-name} in class @var{class}. +The named slot must have @code{#:class} or @code{#:each-subclass} +allocation (@pxref{Slot Options,, allocation}). + +If there is no such slot with @code{#:class} or @code{#:each-subclass} +allocation, @code{class-slot-ref} calls the @code{slot-missing} generic +function with arguments @var{class} and @var{slot-name}. Otherwise, if +the slot value is unbound, @code{class-slot-ref} calls the +@code{slot-missing} generic function, with the same arguments. +@end deffn + +@deffn procedure class-slot-set! class slot-name value +Set the value of the slot named @var{slot-name} in class @var{class} to +@var{value}. The named slot must have @code{#:class} or +@code{#:each-subclass} allocation (@pxref{Slot Options,, allocation}). + +If there is no such slot with @code{#:class} or @code{#:each-subclass} +allocation, @code{class-slot-ref} calls the @code{slot-missing} generic +function with arguments @var{class} and @var{slot-name}. +@end deffn + +@node Handling Slot Access Errors +@subsection Handling Slot Access Errors + +GOOPS calls one of the following generic functions when a ``slot-ref'' +or ``slot-set!'' call specifies a non-existent slot name, or tries to +reference a slot whose value is unbound. + +@deffn generic slot-missing +@deffnx method slot-missing (class ) slot-name +@deffnx method slot-missing (class ) (object ) slot-name +@deffnx method slot-missing (class ) (object ) slot-name value +When an application attempts to reference or set a class or instance +slot by name, and the slot name is invalid for the specified @var{class} +or @var{object}, GOOPS calls the @code{slot-missing} generic function. + +The default methods all call @code{goops-error} with an appropriate +message. +@end deffn + +@deffn generic slot-unbound +@deffnx method slot-unbound (object ) +@deffnx method slot-unbound (class ) slot-name +@deffnx method slot-unbound (class ) (object ) slot-name +When an application attempts to reference a class or instance slot, and +the slot's value is unbound, GOOPS calls the @code{slot-unbound} generic +function. + +The default methods all call @code{goops-error} with an appropriate +message. +@end deffn + +@node Creating Generic Functions +@section Creating Generic Functions + +A generic function is a collection of methods, with rules for +determining which of the methods should be applied for any given +invocation of the generic function. + +GOOPS represents generic functions as metaobjects of the class +@code{} (or one of its subclasses). + +@menu +* Basic Generic Function Creation:: +* Generic Function Internals:: +* Extending Guiles Primitives:: +@end menu + +@node Basic Generic Function Creation +@subsection Basic Generic Function Creation + +The following forms may be used to bind a variable to a generic +function. Depending on that variable's pre-existing value, the generic +function may be created empty - with no methods - or it may contain +methods that are inferred from the pre-existing value. + +It is not, in general, necessary to use @code{define-generic} or +@code{define-accessor} before defining methods for the generic function +using @code{define-method}, since @code{define-method} will +automatically interpolate a @code{define-generic} call, or upgrade an +existing generic to an accessor, if that is implied by the +@code{define-method} call. Note in particular that, +if the specified variable already has a @emph{generic function} value, +@code{define-generic} and @code{define-accessor} will @emph{discard} it! +Obviously it is application-dependent whether this is desirable or not. + +If, for example, you wanted to extend @code{+} for a class representing +a new numerical type, you probably want to inherit any existing methods +for @code{+} and so should not use @code{define-generic}. If, on the +other hand, you do not want to risk inheriting methods whose behaviour +might surprise you, you can use @code{define-generic} or +@code{define-accessor} to wipe the slate clean. + +@deffn syntax define-generic symbol +Create a generic function with name @var{symbol} and bind it to the +variable @var{symbol}. + +If the variable @var{symbol} was previously bound to a Scheme procedure +(or procedure-with-setter), the old procedure (and setter) is +incorporated into the new generic function as its default procedure (and +setter). Any other previous value that was bound to @var{symbol}, +including an existing generic function, is overwritten by the new +generic function. +@end deffn + +@deffn syntax define-accessor symbol +Create an accessor with name @var{symbol} and bind it to the variable +@var{symbol}. + +If the variable @var{symbol} was previously bound to a Scheme procedure +(or procedure-with-setter), the old procedure (and setter) is +incorporated into the new accessor as its default procedure (and +setter). Any other previous value that was bound to @var{symbol}, +including an existing generic function or accessor, is overwritten by +the new definition. +@end deffn + +@node Generic Function Internals +@subsection Generic Function Internals + +@code{define-generic} calls @code{ensure-generic} to upgrade a +pre-existing procedure value, or @code{make} with metaclass +@code{} to create a new generic function. + +@code{define-accessor} calls @code{ensure-accessor} to upgrade a +pre-existing procedure value, or @code{make-accessor} to create a new +accessor. + +@deffn procedure ensure-generic old-definition [name] +Return a generic function with name @var{name}, if possible by using or +upgrading @var{old-definition}. If unspecified, @var{name} defaults to +@code{#f}. + +If @var{old-definition} is already a generic function, it is returned +unchanged. + +If @var{old-definition} is a Scheme procedure or procedure-with-setter, +@code{ensure-generic} returns a new generic function that uses +@var{old-definition} for its default procedure and setter. + +Otherwise @code{ensure-generic} returns a new generic function with no +defaults and no methods. +@end deffn + +@deffn procedure make-generic [name] +Return a new generic function with name @code{(car @var{name})}. If +unspecified, @var{name} defaults to @code{#f}. +@end deffn + +@code{ensure-generic} calls @code{make} with metaclasses +@code{} and @code{}, depending on the +previous value of the variable that it is trying to upgrade. + +@code{make-generic} is a simple wrapper for @code{make} with metaclass +@code{}. + +@deffn procedure ensure-accessor proc [name] +Return an accessor with name @var{name}, if possible by using or +upgrading @var{proc}. If unspecified, @var{name} defaults to @code{#f}. + +If @var{proc} is already an accessor, it is returned unchanged. + +If @var{proc} is a Scheme procedure, procedure-with-setter or generic +function, @code{ensure-accessor} returns an accessor that reuses the +reusable elements of @var{proc}. + +Otherwise @code{ensure-accessor} returns a new accessor with no defaults +and no methods. +@end deffn + +@deffn procedure make-accessor [name] +Return a new accessor with name @code{(car @var{name})}. If +unspecified, @var{name} defaults to @code{#f}. +@end deffn + +@code{ensure-accessor} calls @code{make} with +metaclass @code{}, as well as calls to +@code{ensure-generic}, @code{make-accessor} and (tail recursively) +@code{ensure-accessor}. + +@code{make-accessor} calls @code{make} twice, first +with metaclass @code{} to create a generic function for the +setter, then with metaclass @code{} to create the +accessor, passing the setter generic function as the value of the +@code{#:setter} keyword. + +@node Extending Guiles Primitives +@subsection Extending Guile's Primitives + +When GOOPS is loaded, many of Guile's primitive procedures can be +extended by giving them a generic function definition that operates +in conjunction with their normal C-coded implementation. For +primitives that are extended in this way, the result from the user- +or application-level point of view is that the extended primitive +behaves exactly like a generic function with the C-coded implementation +as its default method. + +The @code{generic-capability?} predicate should be used to determine +whether a particular primitive is extensible in this way. + +@deffn {primitive procedure} generic-capability? primitive +Return @code{#t} if @var{primitive} can be extended by giving it a +generic function definition, otherwise @code{#f}. +@end deffn + +Even when a primitive procedure is extensible like this, its generic +function definition is not created until it is needed by a call to +@code{define-method}, or until the application explicitly requests it +by calling @code{enable-primitive-generic!}. + +@deffn {primitive procedure} enable-primitive-generic! primitive +Force the creation of a generic function definition for +@var{primitive}. +@end deffn + +Once the generic function definition for a primitive has been created, +it can be retrieved using @code{primitive-generic-generic}. + +@deffn {primitive procedure} primitive-generic-generic primitive +Return the generic function definition of @var{primitive}. + +@code{primitive-generic-generic} raises an error if @var{primitive} +is not a primitive with generic capability, or if its generic capability +has not yet been enabled, whether implicitly (by @code{define-method}) +or explicitly (by @code{enable-primitive-generic!}). +@end deffn + +Note that the distinction between, on the one hand, primitives with +additional generic function definitions and, on the other hand, generic +functions with a default method, may disappear when GOOPS is fully +integrated into the core of Guile. Consequently, the +procedures described in this section may disappear as well. + +@node Adding Methods to Generic Functions +@section Adding Methods to Generic Functions + +@menu +* Basic Method Definition:: +* Method Definition Internals:: +@end menu + +@node Basic Method Definition +@subsection Basic Method Definition + +To add a method to a generic function, use the @code{define-method} form. + +@deffn syntax define-method (generic parameter @dots{}) . body +Define a method for the generic function or accessor @var{generic} with +parameters @var{parameter}s and body @var{body}. + +@var{generic} is a generic function. If @var{generic} is a variable +which is not yet bound to a generic function object, the expansion of +@code{define-method} will include a call to @code{define-generic}. If +@var{generic} is @code{(setter @var{generic-with-setter})}, where +@var{generic-with-setter} is a variable which is not yet bound to a +generic-with-setter object, the expansion will include a call to +@code{define-accessor}. + +Each @var{parameter} must be either a symbol or a two-element list +@code{(@var{symbol} @var{class})}. The symbols refer to variables in +the @var{body} that will be bound to the parameters supplied by the +caller when calling this method. The @var{class}es, if present, +specify the possible combinations of parameters to which this method +can be applied. + +@var{body} is the body of the method definition. +@end deffn + +@code{define-method} expressions look a little like normal Scheme +procedure definitions of the form + +@example +(define (name formals @dots{}) . body) +@end example + +The most important difference is that each formal parameter, apart from the +possible ``rest'' argument, can be qualified by a class name: +@code{@var{formal}} becomes @code{(@var{formal} @var{class})}. The +meaning of this qualification is that the method being defined +will only be applicable in a particular generic function invocation if +the corresponding argument is an instance of @code{@var{class}} (or one of +its subclasses). If more than one of the formal parameters is qualified +in this way, then the method will only be applicable if each of the +corresponding arguments is an instance of its respective qualifying class. + +Note that unqualified formal parameters act as though they are qualified +by the class @code{}, which GOOPS uses to mean the superclass of +all valid Scheme types, including both primitive types and GOOPS classes. + +For example, if a generic function method is defined with +@var{parameter}s @code{((s1 ) (n ))}, that method is +only applicable to invocations of its generic function that have two +parameters where the first parameter is an instance of the +@code{} class and the second parameter is a number. + +If a generic function is invoked with a combination of parameters for which +there is no applicable method, GOOPS raises an error. For more about +invocation error handling, and generic function invocation in general, +see @ref{Invoking Generic Functions}. + +@node Method Definition Internals +@subsection Method Definition Internals + +@code{define-method} + +@itemize @bullet +@item +checks the form of the first parameter, and applies the following steps +to the accessor's setter if it has the @code{(setter @dots{})} form + +@item +interpolates a call to @code{define-generic} or @code{define-accessor} +if a generic function is not already defined with the supplied name + +@item +calls @code{method} with the @var{parameter}s and @var{body}, to make a +new method instance + +@item +calls @code{add-method!} to add this method to the relevant generic +function. +@end itemize + +@deffn syntax method (parameter @dots{}) . body +Make a method whose specializers are defined by the classes in +@var{parameter}s and whose procedure definition is constructed from the +@var{parameter} symbols and @var{body} forms. + +The @var{parameter} and @var{body} parameters should be as for +@code{define-method} (@pxref{Basic Method Definition,, define-method}). +@end deffn + +@code{method} + +@itemize @bullet +@item +extracts formals and specializing classes from the @var{parameter}s, +defaulting the class for unspecialized parameters to @code{} + +@item +creates a closure using the formals and the @var{body} forms + +@item +calls @code{make} with metaclass @code{} and the specializers +and closure using the @code{#:specializers} and @code{#:procedure} +keywords. +@end itemize + +@deffn procedure make-method specializers procedure +Make a method using @var{specializers} and @var{procedure}. + +@var{specializers} should be a list of classes that specifies the +parameter combinations to which this method will be applicable. + +@var{procedure} should be the closure that will applied to the generic +function parameters when this method is invoked. +@end deffn + +@code{make-method} is a simple wrapper around @code{make} with metaclass +@code{}. + +@deffn generic add-method! target method +Generic function for adding method @var{method} to @var{target}. +@end deffn + +@deffn method add-method! (generic ) (method ) +Add method @var{method} to the generic function @var{generic}. +@end deffn + +@deffn method add-method! (proc ) (method ) +If @var{proc} is a procedure with generic capability (@pxref{Extending +Guiles Primitives,, generic-capability?}), upgrade it to a +primitive generic and add @var{method} to its generic function +definition. +@end deffn + +@deffn method add-method! (pg ) (method ) +Add method @var{method} to the generic function definition of @var{pg}. + +Implementation: @code{(add-method! (primitive-generic-generic pg) method)}. +@end deffn + +@deffn method add-method! (whatever ) (method ) +Raise an error indicating that @var{whatever} is not a valid generic +function. +@end deffn + +@node Invoking Generic Functions +@section Invoking Generic Functions + +When a variable with a generic function definition appears as the first +element of a list that is being evaluated, the Guile evaluator tries +to apply the generic function to the arguments obtained by evaluating +the remaining elements of the list. [ *fixme* How do I put this in a +more Schemely and less Lispy way? ] + +Usually a generic function contains several method definitions, with +varying degrees of formal parameter specialization (@pxref{Basic +Method Definition,, define-method}). So it is necessary to sort these +methods by specificity with respect to the supplied arguments, and then +apply the most specific method definition. Less specific methods +may be applied subsequently if a method that is being applied calls +@code{next-method}. + +@menu +* Determining Which Methods to Apply:: +* Handling Invocation Errors:: +@end menu + +@node Determining Which Methods to Apply +@subsection Determining Which Methods to Apply + +[ *fixme* Sorry - this is the area of GOOPS that I understand least of +all, so I'm afraid I have to pass on this section. Would some other +kind person consider filling it in? ] + +@deffn generic apply-generic +@deffnx method apply-generic (gf ) args +@end deffn + +@deffn generic compute-applicable-methods +@deffnx method compute-applicable-methods (gf ) args +@end deffn + +@deffn generic sort-applicable-methods +@deffnx method sort-applicable-methods (gf ) methods args +@end deffn + +@deffn generic method-more-specific? +@deffnx method method-more-specific? (m1 ) (m2 ) args +@end deffn + +@deffn generic apply-method +@deffnx method apply-method (gf ) methods build-next args +@end deffn + +@deffn generic apply-methods +@deffnx method apply-methods (gf ) (l ) args +@end deffn + +@node Handling Invocation Errors +@subsection Handling Invocation Errors + +@deffn generic no-method +@deffnx method no-method (gf ) args +When an application invokes a generic function, and no methods at all +have been defined for that generic function, GOOPS calls the +@code{no-method} generic function. The default method calls +@code{goops-error} with an appropriate message. +@end deffn + +@deffn generic no-applicable-method +@deffnx method no-applicable-method (gf ) args +When an application applies a generic function to a set of arguments, +and no methods have been defined for those argument types, GOOPS calls +the @code{no-applicable-method} generic function. The default method +calls @code{goops-error} with an appropriate message. +@end deffn + +@deffn generic no-next-method +@deffnx method no-next-method (gf ) args +When a generic function method calls @code{(next-method)} to invoke the +next less specialized method for that generic function, and no less +specialized methods have been defined for the current generic function +arguments, GOOPS calls the @code{no-next-method} generic function. The +default method calls @code{goops-error} with an appropriate message. +@end deffn + +@node Redefining a Class +@section Redefining a Class + +Suppose that a class @code{} is defined using @code{define-class} +(@pxref{Basic Class Definition,, define-class}), with slots that have +accessor functions, and that an application has created several instances +of @code{} using @code{make} (@pxref{Basic Instance Creation,, +make}). What then happens if @code{} is redefined by calling +@code{define-class} again? + +@menu +* Default Class Redefinition Behaviour:: +* Customizing Class Redefinition:: +@end menu + +@node Default Class Redefinition Behaviour +@subsection Default Class Redefinition Behaviour + +GOOPS' default answer to this question is as follows. + +@itemize @bullet +@item +All existing direct instances of @code{} are converted to be +instances of the new class. This is achieved by preserving the values +of slots that exist in both the old and new definitions, and initializing the +values of new slots in the usual way (@pxref{Basic Instance Creation,, +make}). + +@item +All existing subclasses of @code{} are redefined, as though +the @code{define-class} expressions that defined them were re-evaluated +following the redefinition of @code{}, and the class +redefinition process described here is applied recursively to the +redefined subclasses. + +@item +Once all of its instances and subclasses have been updated, the class +metaobject previously bound to the variable @code{} is no +longer needed and so can be allowed to be garbage collected. +@end itemize + +To keep things tidy, GOOPS also needs to do a little housekeeping on +methods that are associated with the redefined class. + +@itemize @bullet +@item +Slot accessor methods for slots in the old definition should be removed +from their generic functions. They will be replaced by accessor methods +for the slots of the new class definition. + +@item +Any generic function method that uses the old @code{} metaobject +as one of its formal parameter specializers must be updated to refer to +the new @code{} metaobject. (Whenever a new generic function +method is defined, @code{define-method} adds the method to a list stored +in the class metaobject for each class used as a formal parameter +specializer, so it is easy to identify all the methods that must be +updated when a class is redefined.) +@end itemize + +If this class redefinition strategy strikes you as rather counter-intuitive, +bear in mind that it is derived from similar behaviour in other object +systems such as CLOS, and that experience in those systems has shown it to be +very useful in practice. + +Also bear in mind that, like most of GOOPS' default behaviour, it can +be customized@dots{} + +@node Customizing Class Redefinition +@subsection Customizing Class Redefinition + +When @code{define-class} notices that a class is being redefined, +it constructs the new class metaobject as usual, and then invokes the +@code{class-redefinition} generic function with the old and new classes +as arguments. Therefore, if the old or new classes have metaclasses +other than the default @code{}, class redefinition behaviour can +be customized by defining a @code{class-redefinition} method that is +specialized for the relevant metaclasses. + +@deffn generic class-redefinition +Handle the class redefinition from @var{old-class} to @var{new-class}, +and return the new class metaobject that should be bound to the +variable specified by @code{define-class}'s first argument. +@end deffn + +@deffn method class-redefinition (old-class ) (new-class ) +Implements GOOPS' default class redefinition behaviour, as described in +@ref{Default Class Redefinition Behaviour}. Returns the metaobject +for the new class definition. +@end deffn + +An alternative class redefinition strategy could be to leave all +existing instances as instances of the old class, but accepting that the +old class is now ``nameless'', since its name has been taken over by the +new definition. In this strategy, any existing subclasses could also +be left as they are, on the understanding that they inherit from a nameless +superclass. + +This strategy is easily implemented in GOOPS, by defining a new metaclass, +that will be used as the metaclass for all classes to which the strategy +should apply, and then defining a @code{class-redefinition} method that +is specialized for this metaclass: + +@example +(define-class ()) + +(define-method (class-redefinition (old ) (new )) + new) +@end example + +When customization can be as easy as this, aren't you glad that GOOPS +implements the far more difficult strategy as its default! + +Finally, note that, if @code{class-redefinition} itself is not customized, +the default @code{class-redefinition} method invokes three further +generic functions that could be individually customized: + +@itemize @bullet +@item +(remove-class-accessors! @var{old-class}) + +@item +(update-direct-method! @var{method} @var{old-class} @var{new-class}) + +@item +(update-direct-subclass! @var{subclass} @var{old-class} @var{new-class}) +@end itemize + +and the default methods for these generic functions invoke further +generic functions, and so on@dots{} The detailed protocol for all of these +is described in @ref{MOP Specification}. + +@node Changing the Class of an Instance +@section Changing the Class of an Instance + +You can change the class of an existing instance by invoking the +generic function @code{change-class} with two arguments: the instance +and the new class. + +@deffn generic change-class +@end deffn + +The default method for @code{change-class} decides how to implement the +change of class by looking at the slot definitions for the instance's +existing class and for the new class. If the new class has slots with +the same name as slots in the existing class, the values for those slots +are preserved. Slots that are present only in the existing class are +discarded. Slots that are present only in the new class are initialized +using the corresponding slot definition's init function (@pxref{Classes,, +slot-init-function}). + +@deffn {method} change-class (obj ) (new ) +Modify instance @var{obj} to make it an instance of class @var{new}. + +The value of each of @var{obj}'s slots is preserved only if a similarly named +slot exists in @var{new}; any other slot values are discarded. + +The slots in @var{new} that do not correspond to any of @var{obj}'s +pre-existing slots are initialized according to @var{new}'s slot definitions' +init functions. +@end deffn + +Customized change of class behaviour can be implemented by defining +@code{change-class} methods that are specialized either by the class +of the instances to be modified or by the metaclass of the new class. + +When a class is redefined (@pxref{Redefining a Class}), and the default +class redefinition behaviour is not overridden, GOOPS (eventually) +invokes the @code{change-class} generic function for each existing +instance of the redefined class. + +@node Introspection +@section Introspection + +@dfn{Introspection}, also known as @dfn{reflection}, is the name given +to the ability to obtain information dynamically about GOOPS metaobjects. +It is perhaps best illustrated by considering an object oriented language +that does not provide any introspection, namely C++. + +Nothing in C++ allows a running program to obtain answers to the following +types of question: + +@itemize @bullet +@item +What are the data members of this object or class? + +@item +What classes does this class inherit from? + +@item +Is this method call virtual or non-virtual? + +@item +If I invoke @code{Employee::adjustHoliday()}, what class contains the +@code{adjustHoliday()} method that will be applied? +@end itemize + +In C++, answers to such questions can only be determined by looking at +the source code, if you have access to it. GOOPS, on the other hand, +includes procedures that allow answers to these questions --- or their +GOOPS equivalents --- to be obtained dynamically, at run time. + +@menu +* Classes:: +* Slots:: +* Instances:: +* Generic Functions:: +* Generic Function Methods:: +@end menu + +@node Classes +@subsection Classes + +@deffn {primitive procedure} class-name class +Return the name of class @var{class}. +This is the value of the @var{class} metaobject's @code{name} slot. +@end deffn + +@deffn {primitive procedure} class-direct-supers class +Return a list containing the direct superclasses of @var{class}. +This is the value of the @var{class} metaobject's +@code{direct-supers} slot. +@end deffn + +@deffn {primitive procedure} class-direct-slots class +Return a list containing the slot definitions of the direct slots of +@var{class}. +This is the value of the @var{class} metaobject's @code{direct-slots} +slot. +@end deffn + +@deffn {primitive procedure} class-direct-subclasses class +Return a list containing the direct subclasses of @var{class}. +This is the value of the @var{class} metaobject's +@code{direct-subclasses} slot. +@end deffn + +@deffn {primitive procedure} class-direct-methods class +Return a list of all the generic function methods that use @var{class} +as a formal parameter specializer. +This is the value of the @var{class} metaobject's @code{direct-methods} +slot. +@end deffn + +@deffn {primitive procedure} class-precedence-list class +Return the class precedence list for class @var{class} (@pxref{Class +precedence list}). +This is the value of the @var{class} metaobject's @code{cpl} slot. +@end deffn + +@deffn {primitive procedure} class-slots class +Return a list containing the slot definitions for all @var{class}'s slots, +including any slots that are inherited from superclasses. +This is the value of the @var{class} metaobject's @code{slots} slot. +@end deffn + +@deffn {primitive procedure} class-environment class +Return the value of @var{class}'s @code{environment} slot. +[ *fixme* I don't know what this value is used for. ] +@end deffn + +@deffn procedure class-subclasses class +Return a list of all subclasses of @var{class}. +@end deffn + +@deffn procedure class-methods class +Return a list of all methods that use @var{class} or a subclass of +@var{class} as one of its formal parameter specializers. +@end deffn + +@node Slots +@subsection Slots + +@deffn procedure class-slot-definition class slot-name +Return the slot definition for the slot named @var{slot-name} in class +@var{class}. @var{slot-name} should be a symbol. +@end deffn + +@deffn procedure slot-definition-name slot-def +Extract and return the slot name from @var{slot-def}. +@end deffn + +@deffn procedure slot-definition-options slot-def +Extract and return the slot options from @var{slot-def}. +@end deffn + +@deffn procedure slot-definition-allocation slot-def +Extract and return the slot allocation option from @var{slot-def}. This +is the value of the @code{#:allocation} keyword (@pxref{Slot Options,, +allocation}), or @code{#:instance} if the @code{#:allocation} keyword is +absent. +@end deffn + +@deffn procedure slot-definition-getter slot-def +Extract and return the slot getter option from @var{slot-def}. This is +the value of the @code{#:getter} keyword (@pxref{Slot Options,, +getter}), or @code{#f} if the @code{#:getter} keyword is absent. +@end deffn + +@deffn procedure slot-definition-setter slot-def +Extract and return the slot setter option from @var{slot-def}. This is +the value of the @code{#:setter} keyword (@pxref{Slot Options,, +setter}), or @code{#f} if the @code{#:setter} keyword is absent. +@end deffn + +@deffn procedure slot-definition-accessor slot-def +Extract and return the slot accessor option from @var{slot-def}. This +is the value of the @code{#:accessor} keyword (@pxref{Slot Options,, +accessor}), or @code{#f} if the @code{#:accessor} keyword is absent. +@end deffn + +@deffn procedure slot-definition-init-value slot-def +Extract and return the slot init-value option from @var{slot-def}. This +is the value of the @code{#:init-value} keyword (@pxref{Slot Options,, +init-value}), or the unbound value if the @code{#:init-value} keyword is +absent. +@end deffn + +@deffn procedure slot-definition-init-form slot-def +Extract and return the slot init-form option from @var{slot-def}. This +is the value of the @code{#:init-form} keyword (@pxref{Slot Options,, +init-form}), or the unbound value if the @code{#:init-form} keyword is +absent. +@end deffn + +@deffn procedure slot-definition-init-thunk slot-def +Extract and return the slot init-thunk option from @var{slot-def}. This +is the value of the @code{#:init-thunk} keyword (@pxref{Slot Options,, +init-thunk}), or @code{#f} if the @code{#:init-thunk} keyword is absent. +@end deffn + +@deffn procedure slot-definition-init-keyword slot-def +Extract and return the slot init-keyword option from @var{slot-def}. +This is the value of the @code{#:init-keyword} keyword (@pxref{Slot +Options,, init-keyword}), or @code{#f} if the @code{#:init-keyword} +keyword is absent. +@end deffn + +@deffn procedure slot-init-function class slot-name +Return the initialization function for the slot named @var{slot-name} in +class @var{class}. @var{slot-name} should be a symbol. + +The returned initialization function incorporates the effects of the +standard @code{#:init-thunk}, @code{#:init-form} and @code{#:init-value} +slot options. These initializations can be overridden by the +@code{#:init-keyword} slot option or by a specialized @code{initialize} +method, so, in general, the function returned by +@code{slot-init-function} may be irrelevant. For a fuller discussion, +see @ref{Slot Options,, init-value}. +@end deffn + +@node Instances +@subsection Instances + +@deffn {primitive procedure} class-of value +Return the GOOPS class of any Scheme @var{value}. +@end deffn + +@deffn {primitive procedure} instance? object +Return @code{#t} if @var{object} is any GOOPS instance, otherwise +@code{#f}. +@end deffn + +@deffn procedure is-a? object class +Return @code{#t} if @var{object} is an instance of @var{class} or one of +its subclasses. +@end deffn + +Implementation notes: @code{is-a?} uses @code{class-of} and +@code{class-precedence-list} to obtain the class precedence list for +@var{object}. + +@node Generic Functions +@subsection Generic Functions + +@deffn {primitive procedure} generic-function-name gf +Return the name of generic function @var{gf}. +@end deffn + +@deffn {primitive procedure} generic-function-methods gf +Return a list of the methods of generic function @var{gf}. +This is the value of the @var{gf} metaobject's @code{methods} slot. +@end deffn + +@node Generic Function Methods +@subsection Generic Function Methods + +@deffn {primitive procedure} method-generic-function method +Return the generic function that @var{method} belongs to. +This is the value of the @var{method} metaobject's +@code{generic-function} slot. +@end deffn + +@deffn {primitive procedure} method-specializers method +Return a list of @var{method}'s formal parameter specializers . +This is the value of the @var{method} metaobject's +@code{specializers} slot. +@end deffn + +@deffn {primitive procedure} method-procedure method +Return the procedure that implements @var{method}. +This is the value of the @var{method} metaobject's +@code{procedure} slot. +@end deffn + +@deffn generic method-source +@deffnx method method-source (m ) +Return an expression that prints to show the definition of method +@var{m}. + +@example +(define-generic cube) + +(define-method (cube (n )) + (* n n n)) + +(map method-source (generic-function-methods cube)) +@result{} +((method ((n )) (* n n n))) +@end example +@end deffn + +@node Miscellaneous Functions +@section Miscellaneous Functions + +@menu +* Administrative Functions:: +* Error Handling:: +* Object Comparisons:: +* Cloning Objects:: +* Write and Display:: +@end menu + +@node Administrative Functions +@subsection Administration Functions + +This section describes administrative, non-technical GOOPS functions. + +@deffn primitive goops-version +Return the current GOOPS version as a string, for example ``0.2''. +@end deffn + +@node Error Handling +@subsection Error Handling + +The procedure @code{goops-error} is called to raise an appropriate error +by the default methods of the following generic functions: + +@itemize @bullet +@item +@code{slot-missing} (@pxref{Handling Slot Access Errors,, slot-missing}) + +@item +@code{slot-unbound} (@pxref{Handling Slot Access Errors,, slot-unbound}) + +@item +@code{no-method} (@pxref{Handling Invocation Errors,, no-method}) + +@item +@code{no-applicable-method} (@pxref{Handling Invocation Errors,, +no-applicable-method}) + +@item +@code{no-next-method} (@pxref{Handling Invocation Errors,, +no-next-method}) +@end itemize + +If you customize these functions for particular classes or metaclasses, +you may still want to use @code{goops-error} to signal any error +conditions that you detect. + +@deffn procedure goops-error format-string . args +Raise an error with key @code{goops-error} and error message constructed +from @var{format-string} and @var{args}. Error message formatting is +as done by @code{scm-error}. +@end deffn + +@node Object Comparisons +@subsection Object Comparisons + +@deffn generic object-eqv? +@deffnx method object-eqv? ((x ) (y )) +@deffnx generic object-equal? +@deffnx method object-equal? ((x ) (y )) +Generic functions and default (unspecialized) methods for comparing two +GOOPS objects. + +The default methods always return @code{#f}. Application class authors +may wish to define specialized methods for @code{object-eqv?} and +@code{object-equal?} that compare instances of the same class for +equality in whatever sense is useful to the application. +@end deffn + +@node Cloning Objects +@subsection Cloning Objects + +@deffn generic shallow-clone +@deffnx method shallow-clone (self ) +Return a ``shallow'' clone of @var{self}. The default method makes a +shallow clone by allocating a new instance and copying slot values from +self to the new instance. Each slot value is copied either as an +immediate value or by reference. +@end deffn + +@deffn generic deep-clone +@deffnx method deep-clone (self ) +Return a ``deep'' clone of @var{self}. The default method makes a deep +clone by allocating a new instance and copying or cloning slot values +from self to the new instance. If a slot value is an instance +(satisfies @code{instance?}), it is cloned by calling @code{deep-clone} +on that value. Other slot values are copied either as immediate values +or by reference. +@end deffn + +@node Write and Display +@subsection Write and Display + +@deffn {primitive generic} write object port +@deffnx {primitive generic} display object port +When GOOPS is loaded, @code{write} and @code{display} become generic +functions with special methods for printing + +@itemize @bullet +@item +objects - instances of the class @code{} + +@item +foreign objects - instances of the class @code{} + +@item +classes - instances of the class @code{} + +@item +generic functions - instances of the class @code{} + +@item +methods - instances of the class @code{}. +@end itemize + +@code{write} and @code{display} print non-GOOPS values in the same way +as the Guile primitive @code{write} and @code{display} functions. +@end deffn + +@node MOP Specification, Tutorial, Reference Manual, Top +@chapter MOP Specification + +For an introduction to metaobjects and the metaobject protocol, +see @ref{Metaobjects and the Metaobject Protocol}. + +The aim of the MOP specification in this chapter is to specify all the +customizable generic function invocations that can be made by the standard +GOOPS syntax, procedures and methods, and to explain the protocol for +customizing such invocations. + +A generic function invocation is customizable if the types of the arguments +to which it is applied are not all determined by the lexical context in +which the invocation appears. For example, + +@itemize @bullet +@item +the @code{(initialize @var{instance} @var{initargs})} invocation in the +default @code{make-instance} method is customizable, because the type of the +@code{@var{instance}} argument is determined by the class that was passed to +@code{make-instance}. + +@item +the @code{(make #:name ',name)} invocation in @code{define-generic} +is not customizable, because all of its arguments have lexically determined +types. +@end itemize + +When using this rule to decide whether a given generic function invocation +is customizable, we ignore arguments that are expected to be handled in +method definitions as a single ``rest'' list argument. + +For each customizable generic function invocation, the @dfn{invocation +protocol} is explained by specifying + +@itemize @bullet +@item +what, conceptually, the applied method is intended to do + +@item +what assumptions, if any, the caller makes about the applied method's side +effects + +@item +what the caller expects to get as the applied method's return value. +@end itemize + +@menu +* Class Definition:: +* Instance Creation:: +* Class Redefinition:: +* Method Definition:: +* Generic Function Invocation:: +@end menu + +@node Class Definition +@section Class Definition + +@code{define-class} (syntax) + +@itemize @bullet +@item +@code{class} (syntax) + +@itemize @bullet +@item +@code{make-class} (procedure) + +@itemize @bullet +@item +@code{make @var{metaclass} @dots{}} (generic) + +@var{metaclass} is the metaclass of the class being defined, either +taken from the @code{#:metaclass} class option or computed by +@code{ensure-metaclass}. The applied method must create and return the +fully initialized class metaobject for the new class definition. +@end itemize + +@end itemize + +@item +@code{class-redefinition @var{old-class} @var{new-class}} (generic) + +@code{define-class} calls @code{class-redefinition} if the variable +specified by its first argument already held a GOOPS class definition. +@var{old-class} and @var{new-class} are the old and new class metaobjects. +The applied method should perform whatever is necessary to handle the +redefinition, and should return the class metaobject that is to be bound +to @code{define-class}'s variable. The default class redefinition +protocol is described in @ref{Class Redefinition}. +@end itemize + +The @code{(make @var{metaclass} @dots{})} invocation above will create +an class metaobject with metaclass @var{metaclass}. By default, this +metaobject will be initialized by the @code{initialize} method that is +specialized for instances of type @code{}. + +@code{initialize @var{initargs}} (method) + +@itemize @bullet +@item +@code{compute-cpl @var{class}} (generic) + +The applied method should compute and return the class precedence list +for @var{class} as a list of class metaobjects. When @code{compute-cpl} +is called, the following @var{class} metaobject slots have all been +initialized: @code{name}, @code{direct-supers}, @code{direct-slots}, +@code{direct-subclasses} (empty), @code{direct-methods}. The value +returned by @code{compute-cpl} will be stored in the @code{cpl} slot. + +@item +@code{compute-slots @var{class}} (generic) + +The applied method should compute and return the slots (union of direct +and inherited) for @var{class} as a list of slot definitions. When +@code{compute-slots} is called, all the @var{class} metaobject slots +mentioned for @code{compute-cpl} have been initialized, plus the +following: @code{cpl}, @code{redefined} (@code{#f}), @code{environment}. +The value returned by @code{compute-slots} will be stored in the +@code{slots} slot. + +@item +@code{compute-get-n-set @var{class} @var{slot-def}} (generic) + +@code{initialize} calls @code{compute-get-n-set} for each slot computed +by @code{compute-slots}. The applied method should compute and return a +pair of closures that, respectively, get and set the value of the specified +slot. The get closure should have arity 1 and expect a single argument +that is the instance whose slot value is to be retrieved. The set closure +should have arity 2 and expect two arguments, where the first argument is +the instance whose slot value is to be set and the second argument is the +new value for that slot. The closures should be returned in a two element +list: @code{(list @var{get} @var{set})}. + +The closures returned by @code{compute-get-n-set} are stored as part of +the value of the @var{class} metaobject's @code{getters-n-setters} slot. +Specifically, the value of this slot is a list with the same number of +elements as there are slots in the class, and each element looks either like + +@example +@code{(@var{slot-name-symbol} @var{init-function} . @var{index})} +@end example + +or like + +@example +@code{(@var{slot-name-symbol} @var{init-function} @var{get} @var{set})} +@end example + +Where the get and set closures are replaced by @var{index}, the slot is +an instance slot and @var{index} is the slot's index in the underlying +structure: GOOPS knows how to get and set the value of such slots and so +does not need specially constructed get and set closures. Otherwise, +@var{get} and @var{set} are the closures returned by @code{compute-get-n-set}. + +The structure of the @code{getters-n-setters} slot value is important when +understanding the next customizable generic functions that @code{initialize} +calls@dots{} + +@item +@code{compute-getter-method @var{class} @var{gns}} (generic) + +@code{initialize} calls @code{compute-getter-method} for each of the class's +slots (as determined by @code{compute-slots}) that includes a +@code{#:getter} or @code{#:accessor} slot option. @var{gns} is the +element of the @var{class} metaobject's @code{getters-n-setters} slot that +specifies how the slot in question is referenced and set, as described +above under @code{compute-get-n-set}. The applied method should create +and return a method that is specialized for instances of type @var{class} +and uses the get closure to retrieve the slot's value. [ *fixme Need +to insert something here about checking that the value is not unbound. ] +@code{initialize} uses @code{add-method!} to add the returned method to +the generic function named by the slot definition's @code{#:getter} or +@code{#:accessor} option. + +@item +@code{compute-setter-method @var{class} @var{gns}} (generic) + +@code{compute-setter-method} is invoked with the same arguments as +@code{compute-getter-method}, for each of the class's slots that includes +a @code{#:setter} or @code{#:accessor} slot option. The applied method +should create and return a method that is specialized for instances of +type @var{class} and uses the set closure to set the slot's value. +@code{initialize} then uses @code{add-method!} to add the returned method +to the generic function named by the slot definition's @code{#:setter} +or @code{#:accessor} option. +@end itemize + +@node Instance Creation +@section Instance Creation + +@code{make . @var{initargs}} (method) + +@itemize @bullet +@item +@code{allocate-instance @var{class} @var{initargs}} (generic) + +The applied @code{allocate-instance} method should allocate storage for +a new instance of class @var{class} and return the uninitialized instance. + +@item +@code{initialize @var{instance} @var{initargs}} (generic) + +@var{instance} is the uninitialized instance returned by +@code{allocate-instance}. The applied method should initialize the new +instance in whatever sense is appropriate for its class. The method's +return value is ignored. +@end itemize + +@node Class Redefinition +@section Class Redefinition + +The default @code{class-redefinition} method, specialized for classes +with the default metaclass @code{}, has the following internal +protocol. + +[ *fixme* I'm not sure that I understand this sufficiently to explain +it. Also, the internals of the default class redefinition method are +extremely implementation-specific, and I'm not sure that there is that +much point trying to describe the internal protocol such that it could +be customized without going to look at the source code. ] + +@code{class-redefinition @var{(old )} @var{(new )}} +(method) + +@itemize @bullet +@item +@code{remove-class-accessors! @var{old}} (generic) + +@item +@code{update-direct-method! @var{method} @var{old} @var{new}} (generic) + +@item +@code{update-direct-subclass! @var{subclass} @var{old} @var{new}} (generic) +@end itemize + +The default @code{update-direct-subclass!} method invokes +@code{class-redefinition} recursively to handle the redefinition of the +subclass. + +When a class is redefined, any existing instance of the redefined class +will be modified for the new class definition before the next time that +any of the instance's slot is referenced or set. GOOPS modifies each +instance by calling the generic function @code{change-class}. [ *fixme* +Actually it sometimes calls @code{change-class} and sometimes +@code{change-object-class}, and I don't understand why. ] + +The default @code{change-class} method copies slot values from the old +to the modified instance, and initializes new slots, as described in +@ref{Changing the Class of an Instance}. After doing so, it makes a +generic function invocation that can be used to customize the instance +update algorithm. + +@code{change-class @var{(old-instance )} @var{(new )}} (method) + +@itemize @bullet +@item +@code{update-instance-for-different-class @var{old-instance} @var{new-instance}} (generic) + +@code{change-class} invokes @code{update-instance-for-different-class} +as the last thing that it does before returning. The applied method can +make any further adjustments to @var{new-instance} that are required to +complete or modify the change of class. The return value from the +applied method is ignored. + +The default @code{update-instance-for-different-class} method does +nothing. +@end itemize + +@node Method Definition +@section Method Definition + +@code{define-method} (syntax) + +@itemize @bullet +@item +@code{add-method! @var{target} @var{method}} (generic) + +@code{define-method} invokes the @code{add-method!} generic function to +handle adding the new method to a variety of possible targets. GOOPS +includes methods to handle @var{target} as + +@itemize @bullet +@item +a generic function (the most common case) + +@item +a procedure + +@item +a primitive generic (@pxref{Extending Guiles Primitives}) +@end itemize + +By defining further methods for @code{add-method!}, you can +theoretically handle adding methods to further types of target. +@end itemize + +@node Generic Function Invocation +@section Generic Function Invocation + +[ *fixme* Description required here. ] + +@code{apply-generic} + +@itemize @bullet +@item +@code{no-method} + +@item +@code{compute-applicable-methods} + +@item +@code{sort-applicable-methods} + +@item +@code{apply-methods} + +@item +@code{no-applicable-method} +@end itemize + +@code{sort-applicable-methods} + +@itemize @bullet +@item +@code{method-more-specific?} +@end itemize + +@code{apply-methods} + +@itemize @bullet +@item +@code{apply-method} +@end itemize + +@code{next-method} + +@itemize @bullet +@item +@code{no-next-method} +@end itemize + +@node Tutorial, Index, MOP Specification, Top +@chapter Tutorial +@include goops-tutorial.texi + +@node Index, Concept Index, Tutorial, Top +@chapter Index +@page +@node Concept Index, Function and Variable Index, Index, Top +@unnumberedsec Concept Index + +@printindex cp + +@node Function and Variable Index, , Concept Index, Top +@unnumberedsec Function and Variable Index + +@printindex fn + +@summarycontents +@contents +@bye diff --git a/doc/goops/hierarchy.eps b/doc/goops/hierarchy.eps new file mode 100644 index 000000000..7b1a98605 --- /dev/null +++ b/doc/goops/hierarchy.eps @@ -0,0 +1,127 @@ +%!PS-Adobe-2.0 EPSF +%%Title: /tmp/xfig-fig016295 +%%Creator: fig2dev +%%CreationDate: Fri Jun 10 23:18:16 1994 +%%For: eg@kaolin (Erick Gallesio) +%%BoundingBox: 0 0 361 217 +%%Pages: 0 +%%EndComments +/$F2psDict 200 dict def +$F2psDict begin +$F2psDict /mtrx matrix put +/l {lineto} bind def +/m {moveto} bind def +/s {stroke} bind def +/n {newpath} bind def +/gs {gsave} bind def +/gr {grestore} bind def +/clp {closepath} bind def +/graycol {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul +4 -2 roll mul setrgbcolor} bind def +/col-1 {} def +/col0 {0 0 0 setrgbcolor} bind def +/col1 {0 0 1 setrgbcolor} bind def +/col2 {0 1 0 setrgbcolor} bind def +/col3 {0 1 1 setrgbcolor} bind def +/col4 {1 0 0 setrgbcolor} bind def +/col5 {1 0 1 setrgbcolor} bind def +/col6 {1 1 0 setrgbcolor} bind def +/col7 {1 1 1 setrgbcolor} bind def + end +/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def +/$F2psEnd {$F2psEnteredState restore end} def +%%EndProlog + +$F2psBegin +0 setlinecap 0 setlinejoin +-216.0 288.0 translate 0.900 -0.900 scale +0.500 setlinewidth +n 309 159 m 309 159 l gs col-1 s gr +n 246.401 216.889 m 244.000 209.000 l 249.831 214.831 l gs 2 setlinejoin col-1 s gr +% Polyline +n 244 209 m 274 259 l gs col-1 s gr +n 298.169 214.831 m 304.000 209.000 l 301.599 216.889 l gs 2 setlinejoin col-1 s gr +% Polyline +n 304 209 m 274 259 l gs col-1 s gr +n 255.721 213.778 m 249.000 209.000 l 257.179 210.053 l gs 2 setlinejoin col-1 s gr +% Polyline +n 249 209 m 364 254 l gs col-1 s gr +n 370.312 216.376 m 374.000 209.000 l 374.217 217.243 l gs 2 setlinejoin col-1 s gr +% Polyline +n 374 209 m 364 254 l gs col-1 s gr +n 283.772 280.725 m 279.000 274.000 l 286.376 277.688 l gs 2 setlinejoin col-1 s gr +% Polyline +n 279 274 m 314 304 l gs col-1 s gr +n 351.457 272.333 m 359.000 269.000 l 353.913 275.490 l gs 2 setlinejoin col-1 s gr +% Polyline +n 359 269 m 314 304 l gs col-1 s gr +n 300.950 165.789 m 309.000 164.000 l 302.739 169.367 l gs 2 setlinejoin col-1 s gr +% Polyline +n 309 164 m 249 194 l gs col-1 s gr +n 307.000 172.000 m 309.000 164.000 l 311.000 172.000 l gs 2 setlinejoin col-1 s gr +% Polyline +n 309 164 m 309 199 l gs col-1 s gr +n 315.261 169.367 m 309.000 164.000 l 317.050 165.789 l gs 2 setlinejoin col-1 s gr +% Polyline +n 309 164 m 379 199 l gs col-1 s gr +n 406.949 101.701 m 404.000 94.000 l 410.226 99.407 l gs 2 setlinejoin col-1 s gr +% Polyline +n 404 94 m 439 144 l gs col-1 s gr +n 410.363 99.245 m 404.000 94.000 l 412.083 95.634 l gs 2 setlinejoin col-1 s gr +% Polyline +n 404 94 m 509 144 l gs col-1 s gr +n 411.173 98.068 m 404.000 94.000 l 412.243 94.214 l gs 2 setlinejoin col-1 s gr +% Polyline +n 404 94 m 584 144 l gs col-1 s gr +n 396.075 96.277 m 404.000 94.000 l 398.079 99.739 l gs 2 setlinejoin col-1 s gr +% Polyline +n 404 94 m 309 149 l gs col-1 s gr +% Polyline +n 584 229 m 584 204 l gs col-1 s gr +n 582.000 212.000 m 584.000 204.000 l 586.000 212.000 l gs 2 setlinejoin col-1 s gr +% Polyline +n 584 189 m 584 159 l gs col-1 s gr +n 582.000 167.000 m 584.000 159.000 l 586.000 167.000 l gs 2 setlinejoin col-1 s gr +/Times-Bold findfont 12.00 scalefont setfont +239 209 m +gs 1 -1 scale (A) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +274 274 m +gs 1 -1 scale (D) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +359 269 m +gs 1 -1 scale (E) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +304 209 m +gs 1 -1 scale (B) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +374 209 m +gs 1 -1 scale (C) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +314 319 m +gs 1 -1 scale (F) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +289 159 m +gs 1 -1 scale () col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +389 89 m +gs 1 -1 scale () col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +424 154 m +gs 1 -1 scale () col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +474 154 m +gs 1 -1 scale () col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +559 154 m +gs 1 -1 scale () col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +629 154 m +gs 1 -1 scale (...) col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +569 199 m +gs 1 -1 scale () col-1 show gr +/Times-Bold findfont 12.00 scalefont setfont +559 239 m +gs 1 -1 scale () col-1 show gr +$F2psEnd diff --git a/doc/goops/hierarchy.txt b/doc/goops/hierarchy.txt new file mode 100644 index 000000000..c7992df7b --- /dev/null +++ b/doc/goops/hierarchy.txt @@ -0,0 +1,14 @@ + + / \\\_____________________ + / \\___________ \ + / \ \ \ + + / | \ | + / | \ | + A B C + |\__/__ | | + \ / \ / | + D E + \ / | + F | + diff --git a/doc/goops/mop.text b/doc/goops/mop.text new file mode 100644 index 000000000..0180f2c1e --- /dev/null +++ b/doc/goops/mop.text @@ -0,0 +1,66 @@ +*** NOTE: This information needs updating! *** + +P - procedure +L - local procedure +S - syntax +G - generic +M - method + +define-class (S) + make-class (S) + ensure-metaclass (P) + ensure-metaclass-with-supers (P) + make (G) + ensure-class (P) + make (G) + class-redefinition (G) + remove-class-accessors (G) + update-direct-method (G) + update-direct-subclass (G) + +define-generic (S) + make-generic-function (S) + ensure-generic-function (P) + make (G) + +define-method (S) + ensure-method (P) + ensure-generic-function (P) + make (G) + make (G) + add-method (P) + +method (S) + ensure-method (P) + +initialize (class) (M) + compute-cpl (P) + compute-slots (G) + compute-getters-n-setters (P) + compute-slot-init-function (L) + compute-get-n-set (G) + compute-slot-accessors (P) + ensure-method (P) + %inherit-magic! (P) + %prep-layout! (P) + +initialize (generic) (M) + make (G) + +change-class (G) + change-object-class (P) + update-instance-for-different-class (G) + +make = make-instance (G) + allocate-instance (G) + %allocate-instance (P) + initialize (G) + %initialize-object (P) + +apply-generic (G) + compute-applicable-methods (G) + find-method (P) + sort-applicable-methods (G) + sort (P) + apply-methods (G) + apply-method (G) diff --git a/doc/guile-tut.texi b/doc/guile-tut.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/hierarchy.eps b/doc/hierarchy.eps deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/hierarchy.txt b/doc/hierarchy.txt deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/indices.texi b/doc/indices.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/misc-modules.texi b/doc/misc-modules.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/mop.text b/doc/mop.text deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/new-docstrings.texi b/doc/new-docstrings.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/posix.texi b/doc/posix.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/preface.texi b/doc/preface.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/r5rs.texi b/doc/r5rs.texi deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/r5rs/.cvsignore b/doc/r5rs/.cvsignore new file mode 100644 index 000000000..8eaa8267a --- /dev/null +++ b/doc/r5rs/.cvsignore @@ -0,0 +1,23 @@ +Makefile +Makefile.in +stamp-vti +stamp-vti.1 +*.log +*.dvi +*.aux +*.toc +*.cp +*.fn +*.vr +*.tp +*.ky +*.pg +*.cps +*.fns +*.tps +*.vrs +*.ps +*.info* +*.html +version.texi +version-tutorial.texi diff --git a/doc/r5rs/r5rs.texi b/doc/r5rs/r5rs.texi new file mode 100644 index 000000000..a33771190 --- /dev/null +++ b/doc/r5rs/r5rs.texi @@ -0,0 +1,8538 @@ +\input texinfo @c -*-texinfo-*- +@c %**start of header +@setfilename r5rs.info +@settitle Revised(5) Scheme + +@c This copy of r5rs.texi differs from Aubrey Jaffer's master copy +@c by a set of changes to allow the building of r5rs.dvi from r5rs.texi. +@c Aubrey Jaffer's view - which I agree with - is that, given that +@c people have the option of building r5rs.dvi from the original +@c LaTeX distribution for R5RS, it is not worth fixing his master +@c copy of r5rs.texi and the tool which autogenerates it. On the +@c other hand, it is a marginal convenience for people to be able to +@c build hardcopy from r5rs.texi, even if the results are less good +@c than with the original LaTeX. Hence the following fixes. +@c (lines 714, 725, 728, 1614, 2258): Remove invalid parentheses from +@c @deffn statements. +@c (line 2316): Change @deffnx to @deffn, and insert `@end deffn' to +@c terminate preceding @deffn. +@c (line 7320): Insert `@c ' at beginning of lines that are intended +@c to be @ignore'd. +@c +@c NJ 2001/1/26 + +@c \documentclass[twoside]{algol60} + +@c \pagestyle{headings} +@c \showboxdepth=0 + + + +@c \def\headertitle{Revised$^{5}$ Scheme} +@c \def\integerversion{5} + +@c Sizes and dimensions + +@c \topmargin -.375in % Nominal distance from top of page to top of + +@c box containing running head. +@c \headsep 15pt % Space between running head and text. + +@c \textheight 663pt % Height of text (including footnotes and figures, + +@c excluding running head and foot). + +@c \textwidth 523pt % Width of text line. +@c \columnsep 15pt % Space between columns +@c \columnseprule 0pt % Width of rule between columns. + +@c \parskip 5pt plus 2pt minus 2pt % Extra vertical space between paragraphs. +@c \parindent 0pt % Width of paragraph indentation. +@c \topsep 0pt plus 2pt % Extra vertical space, in addition to + +@c \parskip, added above and below list and + +@c paragraphing environments. + +@c \oddsidemargin -.5in % Left margin on odd-numbered pages. +@c \evensidemargin -.5in % Left margin on even-numbered pages. + +@c % End of sizes and dimensions + +@paragraphindent 0 +@c %**end of header +@c syncodeindex fn cp + +@ifinfo +@dircategory The Algorithmic Language Scheme +@direntry +* R5RS: (r5rs). The Revised(5) Report on Scheme. +@end direntry +@end ifinfo + + +@c \parindent 0pt %!! 15pt % Width of paragraph indentation. + + @b{20 February 1998} +@c \hfil \today{} + +@c @include{first} +@titlepage + +@c HTML first page +@title Scheme +@subtitle Revised(5) Report on the Algorithmic Language Scheme +@c First page + +@c \thispagestyle{empty} + +@c \todo{"another" report?} + + +@author R@sc{ICHARD} K@sc{ELSEY}, W@sc{ILLIAM} C@sc{LINGER, AND} J@sc{ONATHAN} R@sc{EES} (@i{Editors}) +@author H. A@sc{BELSON} +@author R. K. D@sc{YBVIG} +@author C. T. H@sc{AYNES} +@author G. J. R@sc{OZAS} +@author N. I. A@sc{DAMS IV} +@author D. P. F@sc{RIEDMAN} +@author E. K@sc{OHLBECKER} +@author G. L. S@sc{TEELE} J@sc{R}. +@author D. H. B@sc{ARTLEY} +@author R. H@sc{ALSTEAD} +@author D. O@sc{XLEY} +@author G. J. S@sc{USSMAN} +@author G. B@sc{ROOKS} +@author C. H@sc{ANSON} +@author K. M. P@sc{ITMAN} +@author M. W@sc{AND} +@author + + +@c {\it Dedicated to the Memory of ALGOL 60} +@i{Dedicated to the Memory of Robert Hieb} +@c [For the macros in R5RS -RK] + + + + +@unnumbered Summary + + +The report gives a defining description of the programming language +Scheme. Scheme is a statically scoped and properly tail-recursive +dialect of the Lisp programming language invented by Guy Lewis +Steele Jr.@: and Gerald Jay Sussman. It was designed to have an +exceptionally clear and simple semantics and few different ways to +form expressions. A wide variety of programming paradigms, including +imperative, functional, and message passing styles, find convenient +expression in Scheme. + +The introduction offers a brief history of the language and of +the report. + +The first three chapters present the fundamental ideas of the +language and describe the notational conventions used for describing the +language and for writing programs in the language. + +Chapters @ref{Expressions} and @ref{Program structure} describe +the syntax and semantics of expressions, programs, and definitions. + +Chapter @ref{Standard procedures} describes Scheme's built-in +procedures, which include all of the language's data manipulation and +input/output primitives. + +Chapter @ref{Formal syntax and semantics} provides a formal syntax for Scheme +written in extended BNF, along with a formal denotational semantics. +An example of the use of the language follows the formal syntax and +semantics. + +The report concludes with a list of references and an +alphabetic index. + +@ignore todo +expand the summary so that it fills up the column. +@end ignore + + +@c \vfill +@c \begin{center} +@c {\large \bf +@c *** DRAFT*** \\ +@c %August 31, 1989 +@c \today +@c }\end{center} + + + + + +@c \addvspace{3.5pt} % don't shrink this gap +@c \renewcommand{\tocshrink}{-3.5pt} % value determined experimentally + + + + + + +@page + +@end titlepage + +@c INFO first page +@ifinfo + +@c First page + +@c \thispagestyle{empty} + +@c \todo{"another" report?} + + +@node top, Introduction, (dir), (dir) +@top Revised(5) Report on the Algorithmic Language Scheme + +@sp 1 + + +@center @c begin-tabular +@quotation +@multitable @columnfractions 0.25 0.25 0.25 0.25 +@item +@center R@sc{ICHARD} K@sc{ELSEY}, W@sc{ILLIAM} C@sc{LINGER, AND} J@sc{ONATHAN} R@sc{EES} (@i{Editors}) +@item H. A@sc{BELSON} @tab R. K. D@sc{YBVIG} @tab C. T. H@sc{AYNES} @tab G. J. R@sc{OZAS} +@item N. I. A@sc{DAMS IV} @tab D. P. F@sc{RIEDMAN} @tab E. K@sc{OHLBECKER} @tab G. L. S@sc{TEELE} J@sc{R}. +@item D. H. B@sc{ARTLEY} @tab R. H@sc{ALSTEAD} @tab D. O@sc{XLEY} @tab G. J. S@sc{USSMAN} +@item G. B@sc{ROOKS} @tab C. H@sc{ANSON} @tab K. M. P@sc{ITMAN} @tab M. W@sc{AND} +@item +@end multitable +@end quotation + + +@sp 2 + +@c {\it Dedicated to the Memory of ALGOL 60} +@i{Dedicated to the Memory of Robert Hieb} +@c [For the macros in R5RS -RK] + +@sp 3 + + + + +@majorheading Summary + + +The report gives a defining description of the programming language +Scheme. Scheme is a statically scoped and properly tail-recursive +dialect of the Lisp programming language invented by Guy Lewis +Steele Jr.@: and Gerald Jay Sussman. It was designed to have an +exceptionally clear and simple semantics and few different ways to +form expressions. A wide variety of programming paradigms, including +imperative, functional, and message passing styles, find convenient +expression in Scheme. + +The introduction offers a brief history of the language and of +the report. + +The first three chapters present the fundamental ideas of the +language and describe the notational conventions used for describing the +language and for writing programs in the language. + +Chapters @ref{Expressions} and @ref{Program structure} describe +the syntax and semantics of expressions, programs, and definitions. + +Chapter @ref{Standard procedures} describes Scheme's built-in +procedures, which include all of the language's data manipulation and +input/output primitives. + +Chapter @ref{Formal syntax and semantics} provides a formal syntax for Scheme +written in extended BNF, along with a formal denotational semantics. +An example of the use of the language follows the formal syntax and +semantics. + +The report concludes with a list of references and an +alphabetic index. + +@ignore todo +expand the summary so that it fills up the column. +@end ignore + + +@c \vfill +@c \begin{center} +@c {\large \bf +@c *** DRAFT*** \\ +@c %August 31, 1989 +@c \today +@c }\end{center} + + + + + +@c \addvspace{3.5pt} % don't shrink this gap +@c \renewcommand{\tocshrink}{-3.5pt} % value determined experimentally + +@unnumbered Contents + +@menu +* Introduction:: +* Overview of Scheme:: +* Lexical conventions:: +* Basic concepts:: +* Expressions:: +* Program structure:: +* Standard procedures:: +* Formal syntax and semantics:: +* Notes:: +* Additional material:: +* Example:: +* Bibliography:: +* Index:: +@end menu + + + + + +@page + +@end ifinfo + + +@c @include{intro} +@node Introduction, Overview of Scheme, top, top +@unnumbered Introduction + +@menu +* Background:: +* Acknowledgements:: +@end menu + + + + +Programming languages should be designed not by piling feature on top of +feature, but by removing the weaknesses and restrictions that make additional +features appear necessary. Scheme demonstrates that a very small number +of rules for forming expressions, with no restrictions on how they are +composed, suffice to form a practical and efficient programming language +that is flexible enough to support most of the major programming +paradigms in use today. + +@c Scheme has influenced the evolution of Lisp. +Scheme +was one of the first programming languages to incorporate first class +procedures as in the lambda calculus, thereby proving the usefulness of +static scope rules and block structure in a dynamically typed language. +Scheme was the first major dialect of Lisp to distinguish procedures +from lambda expressions and symbols, to use a single lexical +environment for all variables, and to evaluate the operator position +of a procedure call in the same way as an operand position. By relying +entirely on procedure calls to express iteration, Scheme emphasized the +fact that tail-recursive procedure calls are essentially goto's that +pass arguments. Scheme was the first widely used programming language to +embrace first class escape procedures, from which all previously known +sequential control structures can be synthesized. A subsequent +version of Scheme introduced the concept of exact and inexact numbers, +an extension of Common Lisp's generic arithmetic. +More recently, Scheme became the first programming language to support +hygienic macros, which permit the syntax of a block-structured language +to be extended in a consistent and reliable manner. +@c A few +@c of these innovations have recently been incorporated into Common Lisp, while +@c others remain to be adopted. + +@ignore todo +Ramsdell: +I would like to make a few comments on presentation. The most +important comment is about section organization. Newspaper writers +spend most of their time writing the first three paragraphs of any +article. This part of the article is often the only part read by +readers, and is important in enticing readers to continue. In the +same way, The first page is most likely to be the only page read by +many SIGPLAN readers. If I had my choice of what I would ask them to +read, it would be the material in section 1.1, the Semantics section +that notes that scheme is lexically scoped, tail recursive, weakly +typed, ... etc. I would expand on the discussion on continuations, +as they represent one important difference between Scheme and other +languages. The introduction, with its history of scheme, its history +of scheme reports and meetings, and acknowledgements giving names of +people that the reader will not likely know, is not that one page I +would like all to read. I suggest moving the history to the back of +the report, and use the first couple of pages to convince the reader +that the language documented in this report is worth studying. + +@end ignore + + +@node Background, Acknowledgements, Introduction, Introduction +@unnumberedsec Background + + +The first description of Scheme was written in +1975 [Scheme75]. A revised report [Scheme78] +@ignore todo +italicize or not? +@end ignore + appeared in 1978, which described the evolution +of the language as its MIT implementation was upgraded to support an +innovative compiler [Rabbit]. Three distinct projects began in +1981 and 1982 to use variants of Scheme for courses at MIT, Yale, and +Indiana University [Rees82], [MITScheme], [Scheme311]. An introductory +computer science textbook using Scheme was published in +1984 [SICP]. + +@c \vest As might be expected of a language used primarily for education and +@c research, Scheme has always evolved rapidly. This was no problem when +@c Scheme was used only within MIT, but +As Scheme became more widespread, +local dialects began to diverge until students and researchers +occasionally found it difficult to understand code written at other +sites. +Fifteen representatives of the major implementations of Scheme therefore +met in October 1984 to work toward a better and more widely accepted +standard for Scheme. +@c Participating in this workshop were Hal Abelson, Norman Adams, David +@c Bartley, Gary Brooks, William Clinger, Daniel Friedman, Robert Halstead, +@c Chris Hanson, Christopher Haynes, Eugene Kohlbecker, Don Oxley, Jonathan Rees, +@c Guillermo Rozas, Gerald Jay Sussman, and Mitchell Wand. Kent Pitman +@c made valuable contributions to the agenda for the workshop but was +@c unable to attend the sessions. + +@c Subsequent electronic mail discussions and committee work completed the +@c definition of the language. +@c Gerry Sussman drafted the section on numbers, Chris Hanson drafted the +@c sections on characters and strings, and Gary Brooks and William Clinger +@c drafted the sections on input and output. +@c William Clinger recorded the decisions of the workshop and +@c compiled the pieces into a coherent document. +@c The ``Revised revised report on Scheme''~\cite{RRRS} +Their report [RRRS] +was published at MIT and Indiana University in the summer of 1985. +Further revision took place in the spring of 1986 [R3RS], +@c , again accomplished +@c almost entirely by electronic mail, resulted in the present report. +and in the spring of 1988 [R4RS]. +The present report reflects further revisions agreed upon in a meeting +at Xerox PARC in June 1992. + +@c \vest The number 3 in the title is part of the title, not a reference to +@c a footnote. The word ``revised'' is raised to the third power because +@c the report is a revision of a report that was already twice revised. + +@ignore todo +Write an editors' note? +@end ignore + + + +@sp 3 + +We intend this report to belong to the entire Scheme community, and so +we grant permission to copy it in whole or in part without fee. In +particular, we encourage implementors of Scheme to use this report as +a starting point for manuals and other documentation, modifying it as +necessary. + + + + +@node Acknowledgements, , Background, Introduction +@unnumberedsec Acknowledgements + + +We would like to thank the following people for their help: Alan Bawden, Michael +Blair, George Carrette, Andy Cromarty, Pavel Curtis, Jeff Dalton, Olivier Danvy, +Ken Dickey, Bruce Duba, Marc Feeley, +Andy Freeman, Richard Gabriel, Yekta G"ursel, Ken Haase, Robert +Hieb, Paul Hudak, Morry Katz, Chris Lindblad, Mark Meyer, Jim Miller, Jim Philbin, +John Ramsdell, Mike Shaff, Jonathan Shapiro, Julie Sussman, +Perry Wagle, Daniel Weise, Henry Wu, and Ozan Yigit. +We thank Carol Fessenden, Daniel +Friedman, and Christopher Haynes for permission to use text from the Scheme 311 +version 4 reference manual. We thank Texas Instruments, Inc. for permission to +use text from the @emph{TI Scheme Language Reference Manual}[TImanual85]. +We gladly acknowledge the influence of manuals for MIT Scheme[MITScheme], +T[Rees84], Scheme 84[Scheme84],Common Lisp[CLtL], +and Algol 60[Naur63]. + +We also thank Betty Dexter for the extreme effort she put into +setting this report in @TeX{}, and Donald Knuth for designing the program +that caused her troubles. + +The Artificial Intelligence Laboratory of the +Massachusetts Institute of Technology, the Computer Science +Department of Indiana University, the Computer and Information +Sciences Department of the University of Oregon, and the NEC Research +Institute supported the preparation of this report. Support for the MIT +work was provided in part by +the Advanced Research Projects Agency of the Department of Defense under Office +of Naval Research contract N00014-80-C-0505. Support for the Indiana +University work was provided by NSF grants NCS 83-04567 and NCS +83-03325. + + + + +@sp 2 + +@c \clearchapterstar{Description of the language} %\unskip\vskip -2ex +@c @include{struct} + +@c 1. Structure of the language + +@node Overview of Scheme, Lexical conventions, Introduction, top +@chapter Overview of Scheme + +@menu +* Semantics:: +* Syntax:: +* Notation and terminology:: +@end menu + + +@node Semantics, Syntax, Overview of Scheme, Overview of Scheme +@section Semantics + + + +This section gives an overview of Scheme's semantics. A +detailed informal semantics is the subject of +chapters @ref{Basic concepts} through @ref{Standard procedures}. For reference +purposes, section @ref{Formal semantics} provides a formal +semantics of Scheme. + +Following Algol, Scheme is a statically scoped programming +language. Each use of a variable is associated with a lexically +apparent binding of that variable. + +Scheme has latent as opposed to manifest types. Types +are associated with values (also called objects) rather than +@cindex @w{object} +with variables. (Some authors refer to languages with latent types as +weakly typed or dynamically typed languages.) Other languages with +latent types are APL, Snobol, and other dialects of Lisp. Languages +with manifest types (sometimes referred to as strongly typed or +statically typed languages) include Algol 60, Pascal, and C. + +All objects created in the course of a Scheme computation, including +procedures and continuations, have unlimited extent. +No Scheme object is ever destroyed. The reason that +implementations of Scheme do not (usually!) run out of storage is that +they are permitted to reclaim the storage occupied by an object if +they can prove that the object cannot possibly matter to any future +computation. Other languages in which most objects have unlimited +extent include APL and other Lisp dialects. + +Implementations of Scheme are required to be properly tail-recursive. +This allows the execution of an iterative computation in constant space, +even if the iterative computation is described by a syntactically +recursive procedure. Thus with a properly tail-recursive implementation, +iteration can be expressed using the ordinary procedure-call +mechanics, so that special iteration constructs are useful only as +syntactic sugar. See section @ref{Proper tail recursion}. + +Scheme procedures are objects in their own right. Procedures can be +created dynamically, stored in data structures, returned as results of +procedures, and so on. Other languages with these properties include +Common Lisp and ML. +@ignore todo +Rozas: Scheme had them first. +@end ignore + + +One distinguishing feature of Scheme is that continuations, which +in most other languages only operate behind the scenes, also have +``first-class'' status. Continuations are useful for implementing a +wide variety of advanced control constructs, including non-local exits, +backtracking, and coroutines. See section @ref{Control features}. + +Arguments to Scheme procedures are always passed by value, which +means that the actual argument expressions are evaluated before the +procedure gains control, whether the procedure needs the result of the +evaluation or not. ML, C, and APL are three other languages that always +pass arguments by value. +This is distinct from the lazy-evaluation semantics of Haskell, +or the call-by-name semantics of Algol 60, where an argument +expression is not evaluated unless its value is needed by the +procedure. + +@ignore todo +Lisp's call by value should be explained more +accurately. What's funny is that all values are references. +@end ignore + + +Scheme's model of arithmetic is designed to remain as independent as +possible of the particular ways in which numbers are represented within a +computer. In Scheme, every integer is a rational number, every rational is a +real, and every real is a complex number. Thus the distinction between integer +and real arithmetic, so important to many programming languages, does not +appear in Scheme. In its place is a distinction between exact arithmetic, +which corresponds to the mathematical ideal, and inexact arithmetic on +approximations. As in Common Lisp, exact arithmetic is not limited to +integers. + +@node Syntax, Notation and terminology, Semantics, Overview of Scheme +@section Syntax + + +Scheme, like most dialects of Lisp, employs a fully parenthesized prefix +notation for programs and (other) data; the grammar of Scheme generates a +sublanguage of the language used for data. An important +consequence of this simple, uniform representation is the susceptibility of +Scheme programs and data to uniform treatment by other Scheme programs. +For example, the @samp{eval} procedure evaluates a Scheme program expressed +as data. + +The @samp{read} procedure performs syntactic as well as lexical decomposition of +the data it reads. The @samp{read} procedure parses its input as data +(section @pxref{External representation}), not as program. + +The formal syntax of Scheme is described in section @ref{Formal syntax}. + + +@node Notation and terminology, , Syntax, Overview of Scheme +@section Notation and terminology + +@menu +* Primitive; library; and optional features:: +* Error situations and unspecified behavior:: +* Entry format:: +* Evaluation examples:: +* Naming conventions:: +@end menu + + + +@node Primitive; library; and optional features, Error situations and unspecified behavior, Notation and terminology, Notation and terminology +@subsection Primitive; library; and optional features + + + +It is required that every implementation of Scheme support all +features that are not marked as being @dfn{optional}. Implementations are +@cindex @w{optional} +free to omit optional features of Scheme or to add extensions, +provided the extensions are not in conflict with the language reported +here. In particular, implementations must support portable code by +providing a syntactic mode that preempts no lexical conventions of this +report. + +To aid in understanding and implementing Scheme, some features are marked +as @dfn{library}. These can be easily implemented in terms of the other, +@cindex @w{library} +primitive, features. They are redundant in the strict sense of +the word, but they capture common patterns of usage, and are therefore +provided as convenient abbreviations. + +@node Error situations and unspecified behavior, Entry format, Primitive; library; and optional features, Notation and terminology +@subsection Error situations and unspecified behavior + + + +@cindex @w{error} +When speaking of an error situation, this report uses the phrase ``an +error is signalled'' to indicate that implementations must detect and +report the error. If such wording does not appear in the discussion of +an error, then implementations are not required to detect or report the +error, though they are encouraged to do so. An error situation that +implementations are not required to detect is usually referred to simply +as ``an error.'' + +For example, it is an error for a procedure to be passed an argument that +the procedure is not explicitly specified to handle, even though such +domain errors are seldom mentioned in this report. Implementations may +extend a procedure's domain of definition to include such arguments. + +This report uses the phrase ``may report a violation of an +implementation restriction'' to indicate circumstances under which an +implementation is permitted to report that it is unable to continue +execution of a correct program because of some restriction imposed by the +implementation. Implementation restrictions are of course discouraged, +but implementations are encouraged to report violations of implementation +restrictions. +@cindex @w{implementation restriction} + +For example, an implementation may report a violation of an +implementation restriction if it does not have enough storage to run a +program. + +If the value of an expression is said to be ``unspecified,'' then +the expression must evaluate to some object without signalling an error, +but the value depends on the implementation; this report explicitly does +not say what value should be returned. +@cindex @w{unspecified} + +@ignore todo +Talk about unspecified behavior vs. unspecified values. +@end ignore + + +@ignore todo +Look at KMP's situations paper. +@end ignore + + + +@node Entry format, Evaluation examples, Error situations and unspecified behavior, Notation and terminology +@subsection Entry format + + +Chapters @ref{Expressions} and @ref{Standard procedures} are organized +into entries. Each entry describes one language feature or a group of +related features, where a feature is either a syntactic construct or a +built-in procedure. An entry begins with one or more header lines of the form + + +@noindent +@deffn {@var{category}} @var{template} + +@end deffn + +for required, primitive features, or + + +@noindent +@deffn {@var{qualifier} @var{category}} @var{template} + +@end deffn + +where @var{qualifier} is either ``library'' or ``optional'' as defined + in section @ref{Primitive; library; and optional features}. + +If @var{category} is ``syntax'', the entry describes an expression +type, and the template gives the syntax of the expression type. +Components of expressions are designated by syntactic variables, which +are written using angle brackets, for example, @r{}, +@r{}. Syntactic variables should be understood to denote segments of +program text; for example, @r{} stands for any string of +characters which is a syntactically valid expression. The notation + +@format + @r{} @dots{} +@end format + +indicates zero or more occurrences of a @r{}, and + +@format + @r{} @r{} @dots{} +@end format + +indicates one or more occurrences of a @r{}. + +If @var{category} is ``procedure'', then the entry describes a procedure, and +the header line gives a template for a call to the procedure. Argument +names in the template are @var{italicized}. Thus the header line + + +@noindent +@deffn {procedure} vector-ref @var{vector} @var{k} + +@end deffn + +indicates that the built-in procedure @t{vector-ref} takes +two arguments, a vector @var{vector} and an exact non-negative integer +@var{k} (see below). The header lines + + +@noindent + +@deffn {procedure} make-vector @var{k} + + +@deffnx {procedure} make-vector @var{k} @var{fill} + +@end deffn + +indicate that the @t{make-vector} procedure must be defined to take +either one or two arguments. + + +It is an error for an operation to be presented with an argument that it +is not specified to handle. For succinctness, we follow the convention +that if an argument name is also the name of a type listed in +section @ref{Disjointness of types}, then that argument must be of the named type. +For example, the header line for @t{vector-ref} given above dictates that the +first argument to @t{vector-ref} must be a vector. The following naming +conventions also imply type restrictions: +@c \newcommand{\foo}[1]{\vr{#1}, \vri{#1}, $\ldots$ \vrj{#1}, $\ldots$} + + +@center @c begin-tabular +@quotation +@table @asis +@item @var{obj} +any object +@item @var{list}, @var{list1}, @dots{} @var{listj}, @dots{} +list (see section @pxref{Pairs and lists}) +@item @var{z}, @var{z1}, @dots{} @var{zj}, @dots{} +complex number +@item @var{x}, @var{x1}, @dots{} @var{xj}, @dots{} +real number +@item @var{y}, @var{y1}, @dots{} @var{yj}, @dots{} +real number +@item @var{q}, @var{q1}, @dots{} @var{qj}, @dots{} +rational number +@item @var{n}, @var{n1}, @dots{} @var{nj}, @dots{} +integer +@item @var{k}, @var{k1}, @dots{} @var{kj}, @dots{} +exact non-negative integer +@item +@end table +@end quotation + + + + +@ignore todo +Provide an example entry?? +@end ignore + + + +@node Evaluation examples, Naming conventions, Entry format, Notation and terminology +@subsection Evaluation examples + + +The symbol ``@result{}'' used in program examples should be read +``evaluates to.'' For example, + + +@example + +(* 5 8) ==> 40 + +@end example + + +means that the expression @t{(* 5 8)} evaluates to the object @t{40}. +Or, more precisely: the expression given by the sequence of characters +``@t{(* 5 8)}'' evaluates, in the initial environment, to an object +that may be represented externally by the sequence of characters ``@t{40}''. See section @ref{External representations} for a discussion of external +representations of objects. + +@node Naming conventions, , Evaluation examples, Notation and terminology +@subsection Naming conventions + + +By convention, the names of procedures that always return a boolean +value usually end +in ``@code{?}''. Such procedures are called predicates. +@vindex @w{?} + +By convention, the names of procedures that store values into previously +allocated locations (see section @pxref{Storage model}) usually end in +``@code{!}''. +@vindex @w{!} +Such procedures are called mutation procedures. +By convention, the value returned by a mutation procedure is unspecified. + +By convention, ``@code{->}'' appears within the names of procedures that +@vindex @w{->} +take an object of one type and return an analogous object of another type. +For example, @samp{list->vector} takes a list and returns a vector whose +elements are the same as those of the list. + + + +@ignore todo +Terms that need defining: thunk, command (what else?). +@end ignore + + +@c @include{lex} + +@c Lexical structure + +@c %\vfill\eject +@node Lexical conventions, Basic concepts, Overview of Scheme, top +@chapter Lexical conventions + +@menu +* Identifiers:: +* Whitespace and comments:: +* Other notations:: +@end menu + + +This section gives an informal account of some of the lexical +conventions used in writing Scheme programs. For a formal syntax of +Scheme, see section @ref{Formal syntax}. + +Upper and lower case forms of a letter are never distinguished +except within character and string constants. For example, @samp{Foo} is +the same identifier as @samp{FOO}, and @t{#x1AB} is the same number as +@t{#X1ab}. + +@node Identifiers, Whitespace and comments, Lexical conventions, Lexical conventions +@section Identifiers + + + +Most identifiers allowed by other programming +@cindex @w{identifier} +languages are also acceptable to Scheme. The precise rules for forming +identifiers vary among implementations of Scheme, but in all +implementations a sequence of letters, digits, and ``extended alphabetic +characters'' that begins with a character that cannot begin a number is +an identifier. In addition, @code{+}, @code{-}, and @code{...} are identifiers. +@vindex @w{...} +@vindex @w{-} +@vindex @w{+} +Here are some examples of identifiers: + + +@example + +lambda q +list->vector soup ++ V17a +<=? a34kTMNs +the-word-recursion-has-many-meanings + +@end example + + +Extended alphabetic characters may be used within identifiers as if +they were letters. The following are extended alphabetic characters: + + +@example + +! $ % & * + - . / : < = > ? @@ ^ _ ~ +@end example + + +See section @ref{Lexical structure} for a formal syntax of identifiers. + +Identifiers have two uses within Scheme programs: + + +@itemize @bullet + +@item +Any identifier may be used as a variable +or as a syntactic keyword +(see sections @pxref{Variables; syntactic keywords; and regions} and @pxref{Macros}). + +@item +When an identifier appears as a literal or within a literal +(see section @pxref{Literal expressions}), it is being used to denote a @emph{symbol} +(see section @pxref{Symbols}). + + +@end itemize + +@cindex @w{syntactic keyword} +@cindex @w{variable} + +@c \label{keywordsection} +@c The following identifiers are syntactic keywords, and should not be used +@c as variables: + +@c \begin{scheme} +@c => do or +@c and else quasiquote +@c begin if quote +@c case lambda set! +@c cond let unquote +@c define let* unquote-splicing +@c delay letrec% +@c \end{scheme} + +@c Some implementations allow all identifiers, including syntactic +@c keywords, to be used as variables. This is a compatible extension to +@c the language, but ambiguities in the language result when the +@c restriction is relaxed, and the ways in which these ambiguities are +@c resolved vary between implementations. + + +@node Whitespace and comments, Other notations, Identifiers, Lexical conventions +@section Whitespace and comments + + +@dfn{Whitespace} characters are spaces and newlines. +@cindex @w{Whitespace} +(Implementations typically provide additional whitespace characters such +as tab or page break.) Whitespace is used for improved readability and +as necessary to separate tokens from each other, a token being an +indivisible lexical unit such as an identifier or number, but is +otherwise insignificant. Whitespace may occur between any two tokens, +but not within a token. Whitespace may also occur inside a string, +where it is significant. + +A semicolon (@t{;}) indicates the start of a +comment. The comment continues to the +@cindex @w{;} +@cindex @w{comment} +end of the line on which the semicolon appears. Comments are invisible +to Scheme, but the end of the line is visible as whitespace. This +prevents a comment from appearing in the middle of an identifier or +number. + + +@example + +;;; The FACT procedure computes the factorial +;;; of a non-negative integer. +(define fact + (lambda (n) + (if (= n 0) + 1 ;Base case: return 1 + (* n (fact (- n 1)))))) + +@end example + + + +@node Other notations, , Whitespace and comments, Lexical conventions +@section Other notations + + +@ignore todo +Rewrite? +@end ignore + + +For a description of the notations used for numbers, see +section @ref{Numbers}. + + +@table @t + + +@item @t{.@: + -} +These are used in numbers, and may also occur anywhere in an identifier +except as the first character. A delimited plus or minus sign by itself +is also an identifier. +A delimited period (not occurring within a number or identifier) is used +in the notation for pairs (section @pxref{Pairs and lists}), and to indicate a +rest-parameter in a formal parameter list (section @pxref{Procedures}). +A delimited sequence of three successive periods is also an identifier. + +@item @t{( )} +Parentheses are used for grouping and to notate lists +(section @pxref{Pairs and lists}). + +@item @t{'} +The single quote character is used to indicate literal data (section @pxref{Literal expressions}). + +@item @t{`} +The backquote character is used to indicate almost-constant +data (section @pxref{Quasiquotation}). + +@item @t{, ,@@} +The character comma and the sequence comma at-sign are used in conjunction +with backquote (section @pxref{Quasiquotation}). + +@item @t{"} +The double quote character is used to delimit strings (section @pxref{Strings}). + +@item \ +Backslash is used in the syntax for character constants +(section @pxref{Characters}) and as an escape character within string +constants (section @pxref{Strings}). + +@c A box used because \verb is not allowed in command arguments. + +@item @w{@t{[ ] @{ @} |}} +Left and right square brackets and curly braces and vertical bar +are reserved for possible future extensions to the language. + +@item # + Sharp sign is used for a variety of purposes depending on +the character that immediately follows it: + +@item @t{#t} @t{#f} +These are the boolean constants (section @pxref{Booleans}). + +@item #\ +This introduces a character constant (section @pxref{Characters}). + +@item #@t{(} +This introduces a vector constant (section @pxref{Vectors}). Vector constants +are terminated by @t{)} . + +@item @t{#e #i #b #o #d #x} +These are used in the notation for numbers (section @pxref{Syntax of numerical constants}). + +@end table + + +@c @include{basic} + +@c \vfill\eject +@node Basic concepts, Expressions, Lexical conventions, top +@chapter Basic concepts + +@menu +* Variables; syntactic keywords; and regions:: +* Disjointness of types:: +* External representations:: +* Storage model:: +* Proper tail recursion:: +@end menu + + + +@node Variables; syntactic keywords; and regions, Disjointness of types, Basic concepts, Basic concepts +@section Variables; syntactic keywords; and regions + + + + +An identifier may name a type of syntax, or it may name +@cindex @w{identifier} +a location where a value can be stored. An identifier that names a type +of syntax is called a @emph{syntactic keyword} +@cindex @w{syntactic keyword} +and is said to be @emph{bound} to that syntax. An identifier that names a +location is called a @emph{variable} and is said to be +@cindex @w{variable} +@emph{bound} to that location. The set of all visible +bindings in effect at some point in a program is +@cindex @w{binding} +known as the @emph{environment} in effect at that point. The value +stored in the location to which a variable is bound is called the +variable's value. By abuse of terminology, the variable is sometimes +said to name the value or to be bound to the value. This is not quite +accurate, but confusion rarely results from this practice. + +@ignore todo +Define ``assigned'' and ``unassigned'' perhaps? +@end ignore + + +@ignore todo +In programs without side effects, one can safely pretend that the +variables are bound directly to the arguments. Or: +In programs without @code{set!}, one can safely pretend that the +@vindex @w{set!} +variable is bound directly to the value. +@end ignore + + +Certain expression types are used to create new kinds of syntax +and bind syntactic keywords to those new syntaxes, while other +expression types create new locations and bind variables to those +locations. These expression types are called @emph{binding constructs}. + +@cindex @w{binding construct} +Those that bind syntactic keywords are listed in section @ref{Macros}. +The most fundamental of the variable binding constructs is the +@samp{lambda} expression, because all other variable binding constructs +can be explained in terms of @samp{lambda} expressions. The other +variable binding constructs are @samp{let}, @samp{let*}, @samp{letrec}, +and @samp{do} expressions (see sections @pxref{Procedures}, @pxref{Binding constructs}, and +@pxref{Iteration}). + +@c Note: internal definitions not mentioned here. + +Like Algol and Pascal, and unlike most other dialects of Lisp +except for Common Lisp, Scheme is a statically scoped language with +block structure. To each place where an identifier is bound in a program +there corresponds a @dfn{region} of the program text within which +@cindex @w{region} +the binding is visible. The region is determined by the particular +binding construct that establishes the binding; if the binding is +established by a @samp{lambda} expression, for example, then its region +is the entire @samp{lambda} expression. Every mention of an identifier +refers to the binding of the identifier that established the +innermost of the regions containing the use. If there is no binding of +the identifier whose region contains the use, then the use refers to the +binding for the variable in the top level environment, if any +(chapters @pxref{Expressions} and @pxref{Standard procedures}); if there is no +binding for the identifier, +it is said to be @dfn{unbound}. +@cindex @w{top level environment} +@cindex @w{bound} +@cindex @w{unbound} + +@ignore todo +Mention that some implementations have multiple top level environments? +@end ignore + + +@ignore todo +Pitman sez: needs elaboration in case of @t{(let ...)} +@end ignore + + +@ignore todo +Pitman asks: say something about vars created after scheme starts? +@t{(define x 3) (define (f) x) (define (g) y) (define y 4)} +Clinger replies: The language was explicitly +designed to permit a view in which no variables are created after +Scheme starts. In files, you can scan out the definitions beforehand. +I think we're agreed on the principle that interactive use should +approximate that behavior as closely as possible, though we don't yet +agree on which programming environment provides the best approximation. +@end ignore + + +@node Disjointness of types, External representations, Variables; syntactic keywords; and regions, Basic concepts +@section Disjointness of types + + + +No object satisfies more than one of the following predicates: + + +@example + +boolean? pair? +symbol? number? +char? string? +vector? port? +procedure? + +@end example + + +These predicates define the types @emph{boolean}, @emph{pair}, @emph{symbol}, @emph{number}, @emph{char} (or @emph{character}), @emph{string}, @emph{vector}, @emph{port}, and @emph{procedure}. The empty list is a special +object of its own type; it satisfies none of the above predicates. + +@vindex symbol? +@vindex pair? +@vindex boolean? +@cindex @w{type} + +@vindex vector? +@vindex string? +@vindex char? +@vindex number? + +@cindex @w{empty list} +@vindex procedure? +@vindex port? + +Although there is a separate boolean type, +any Scheme value can be used as a boolean value for the purpose of a +conditional test. As explained in section @ref{Booleans}, all +values count as true in such a test except for @t{#f}. +@c and possibly the empty list. +@c The only value that is guaranteed to count as +@c false is \schfalse{}. It is explicitly unspecified whether the empty list +@c counts as true or as false. +This report uses the word ``true'' to refer to any +Scheme value except @t{#f}, and the word ``false'' to refer to +@t{#f}. +@cindex @w{false} +@cindex @w{true} + +@node External representations, Storage model, Disjointness of types, Basic concepts +@section External representations + + + +An important concept in Scheme (and Lisp) is that of the @emph{external +representation} of an object as a sequence of characters. For example, +an external representation of the integer 28 is the sequence of +characters ``@t{28}'', and an external representation of a list consisting +of the integers 8 and 13 is the sequence of characters ``@t{(8 13)}''. + +The external representation of an object is not necessarily unique. The +integer 28 also has representations ``@t{#e28.000}'' and ``@t{#x1c}'', and the +list in the previous paragraph also has the representations ``@t{( 08 13 +)}'' and ``@t{(8 .@: (13 .@: ()))}'' (see section @pxref{Pairs and lists}). + +Many objects have standard external representations, but some, such as +procedures, do not have standard representations (although particular +implementations may define representations for them). + +An external representation may be written in a program to obtain the +corresponding object (see @samp{quote}, section @pxref{Literal expressions}). + +External representations can also be used for input and output. The +procedure @samp{read} (section @pxref{Input}) parses external +representations, and the procedure @samp{write} (section @pxref{Output}) +generates them. Together, they provide an elegant and powerful +input/output facility. + +Note that the sequence of characters ``@t{(+ 2 6)}'' is @emph{not} an +external representation of the integer 8, even though it @emph{is} an +expression evaluating to the integer 8; rather, it is an external +representation of a three-element list, the elements of which are the symbol +@t{+} and the integers 2 and 6. Scheme's syntax has the property that +any sequence of characters that is an expression is also the external +representation of some object. This can lead to confusion, since it may +not be obvious out of context whether a given sequence of characters is +intended to denote data or program, but it is also a source of power, +since it facilitates writing programs such as interpreters and +compilers that treat programs as data (or vice versa). + +The syntax of external representations of various kinds of objects +accompanies the description of the primitives for manipulating the +objects in the appropriate sections of chapter @ref{Standard procedures}. + +@node Storage model, Proper tail recursion, External representations, Basic concepts +@section Storage model + + + +Variables and objects such as pairs, vectors, and strings implicitly +denote locations or sequences of locations. A string, for +@cindex @w{location} +example, denotes as many locations as there are characters in the string. +(These locations need not correspond to a full machine word.) A new value may be +stored into one of these locations using the @t{string-set!} procedure, but +the string continues to denote the same locations as before. + +An object fetched from a location, by a variable reference or by +a procedure such as @samp{car}, @samp{vector-ref}, or @samp{string-ref}, is +equivalent in the sense of @code{eqv?} +@c and \ide{eq?} ?? +(section @pxref{Equivalence predicates}) +@vindex @w{eqv?} +to the object last stored in the location before the fetch. + +Every location is marked to show whether it is in use. +No variable or object ever refers to a location that is not in use. +Whenever this report speaks of storage being allocated for a variable +or object, what is meant is that an appropriate number of locations are +chosen from the set of locations that are not in use, and the chosen +locations are marked to indicate that they are now in use before the variable +or object is made to denote them. + +In many systems it is desirable for constants (i.e. the values of +@cindex @w{constant} +literal expressions) to reside in read-only-memory. To express this, it is +convenient to imagine that every object that denotes locations is associated +with a flag telling whether that object is mutable or +@cindex @w{mutable} +immutable. In such systems literal constants and the strings +@cindex @w{immutable} +returned by @code{symbol->string} are immutable objects, while all objects +@vindex @w{symbol->string} +created by the other procedures listed in this report are mutable. It is an +error to attempt to store a new value into a location that is denoted by an +immutable object. + +@node Proper tail recursion, , Storage model, Basic concepts +@section Proper tail recursion + + + +Implementations of Scheme are required to be +@emph{properly tail-recursive}. +@cindex @w{proper tail recursion} +Procedure calls that occur in certain syntactic +contexts defined below are `tail calls'. A Scheme implementation is +properly tail-recursive if it supports an unbounded number of active +tail calls. A call is @emph{active} if the called procedure may still +return. Note that this includes calls that may be returned from either +by the current continuation or by continuations captured earlier by +@samp{call-with-current-continuation} that are later invoked. +In the absence of captured continuations, calls could +return at most once and the active calls would be those that had not +yet returned. +A formal definition of proper tail recursion can be found +in [propertailrecursion]. + + +@quotation +@emph{Rationale:} + +Intuitively, no space is needed for an active tail call because the +continuation that is used in the tail call has the same semantics as the +continuation passed to the procedure containing the call. Although an improper +implementation might use a new continuation in the call, a return +to this new continuation would be followed immediately by a return +to the continuation passed to the procedure. A properly tail-recursive +implementation returns to that continuation directly. + +Proper tail recursion was one of the central ideas in Steele and +Sussman's original version of Scheme. Their first Scheme interpreter +implemented both functions and actors. Control flow was expressed using +actors, which differed from functions in that they passed their results +on to another actor instead of returning to a caller. In the terminology +of this section, each actor finished with a tail call to another actor. + +Steele and Sussman later observed that in their interpreter the code +for dealing with actors was identical to that for functions and thus +there was no need to include both in the language. + +@end quotation + + +A @emph{tail call} is a procedure call that occurs +@cindex @w{tail call} +in a @emph{tail context}. Tail contexts are defined inductively. Note +that a tail context is always determined with respect to a particular lambda +expression. + + + +@itemize @bullet + +@item +The last expression within the body of a lambda expression, +shown as @r{} below, occurs in a tail context. + +@format +@t{(lambda + * * ) +} + +@end format + + + +@item +If one of the following expressions is in a tail context, +then the subexpressions shown as are in a tail context. +These were derived from rules in the grammar given in +chapter @ref{Formal syntax and semantics} by replacing some occurrences of +with . Only those rules that contain tail contexts +are shown here. + + +@format +@t{(if ) +(if ) + +(cond +) +(cond * (else )) + +(case + +) +(case + * + (else )) + +(and * ) +(or * ) + +(let (*) ) +(let (*) ) +(let* (*) ) +(letrec (*) ) + +(let-syntax (*) ) +(letrec-syntax (*) ) + +(begin ) + +(do (*) + ( ) + *) + +@r{where} + + --> ( ) + --> ((*) ) + + --> * + --> * +} + +@end format + + + +@item +If a @samp{cond} expression is in a tail context, and has a clause of +the form @samp{(@r{} => @r{})} +then the (implied) call to +the procedure that results from the evaluation of @r{} is in a +tail context. @r{} itself is not in a tail context. + + +@end itemize + + +Certain built-in procedures are also required to perform tail calls. +The first argument passed to @code{apply} and to +@vindex @w{apply} +@code{call-with-current-continuation}, and the second argument passed to +@vindex @w{call-with-current-continuation} +@code{call-with-values}, must be called via a tail call. +@vindex @w{call-with-values} +Similarly, @code{eval} must evaluate its argument as if it +@vindex @w{eval} +were in tail position within the @code{eval} procedure. +@vindex @w{eval} + +In the following example the only tail call is the call to @samp{f}. +None of the calls to @samp{g} or @samp{h} are tail calls. The reference to +@samp{x} is in a tail context, but it is not a call and thus is not a +tail call. + +@example + +(lambda () + (if (g) + (let ((x (h))) + x) + (and (g) (f)))) + +@end example + + + +@quotation +@emph{Note:} +Implementations are allowed, but not required, to +recognize that some non-tail calls, such as the call to @samp{h} +above, can be evaluated as though they were tail calls. +In the example above, the @samp{let} expression could be compiled +as a tail call to @samp{h}. (The possibility of @samp{h} returning +an unexpected number of values can be ignored, because in that +case the effect of the @samp{let} is explicitly unspecified and +implementation-dependent.) +@end quotation + + + +@c @include{expr} + +@c \vfill\eject +@node Expressions, Program structure, Basic concepts, top +@chapter Expressions + +@menu +* Primitive expression types:: +* Derived expression types:: +* Macros:: +@end menu + + + +@c \newcommand{\syntax}{{\em Syntax: }} +@c \newcommand{\semantics}{{\em Semantics: }} + +@c [Deleted for R5RS because of multiple-value returns. -RK] +@c A Scheme expression is a construct that returns a value, such as a +@c variable reference, literal, procedure call, or conditional. + +Expression types are categorized as @emph{primitive} or @emph{derived}. +Primitive expression types include variables and procedure calls. +Derived expression types are not semantically primitive, but can instead +be defined as macros. +With the exception of @samp{quasiquote}, whose macro definition is complex, +the derived expressions are classified as library features. +Suitable definitions are given in section @ref{Derived expression type}. + +@node Primitive expression types, Derived expression types, Expressions, Expressions +@section Primitive expression types + +@menu +* Variable references:: +* Literal expressions:: +* Procedure calls:: +* Procedures:: +* Conditionals:: +* Assignments:: +@end menu + + + +@node Variable references, Literal expressions, Primitive expression types, Primitive expression types +@subsection Variable references + + + +@deffn {syntax} @r{} + + +An expression consisting of a variable +@cindex @w{variable} +(section @pxref{Variables; syntactic keywords; and regions}) is a variable reference. The value of +the variable reference is the value stored in the location to which the +variable is bound. It is an error to reference an +unbound variable. +@cindex @w{unbound} + + +@format +@t{(define x 28) +x ==> 28 +} +@end format + +@end deffn + +@node Literal expressions, Procedure calls, Variable references, Primitive expression types +@subsection Literal expressions + + + + +@deffn {syntax} quote @r{} + +@deffnx {syntax} @t{'}@r{} + + +@deffnx {syntax} @r{} + + +@samp{(quote @r{})} evaluates to @r{}. +@cindex @w{'} +@r{} +may be any external representation of a Scheme object (see +section @pxref{External representations}). This notation is used to include literal +constants in Scheme code. + + +@format +@t{ +(quote a) ==> a +(quote #(a b c)) ==> #(a b c) +(quote (+ 1 2)) ==> (+ 1 2) +} +@end format + + +@samp{(quote @r{})} may be abbreviated as +@t{'}@r{}. The two notations are equivalent in all +respects. + + +@format +@t{'a ==> a +'#(a b c) ==> #(a b c) +'() ==> () +'(+ 1 2) ==> (+ 1 2) +'(quote a) ==> (quote a) +''a ==> (quote a) +} +@end format + + +Numerical constants, string constants, character constants, and boolean +constants evaluate ``to themselves''; they need not be quoted. + + +@format +@t{'"abc" ==> "abc" +"abc" ==> "abc" +'145932 ==> 145932 +145932 ==> 145932 +'#t ==> #t +#t ==> #t +} +@end format + + +As noted in section @ref{Storage model}, it is an error to alter a constant +(i.e. the value of a literal expression) using a mutation procedure like +@samp{set-car!} or @samp{string-set!}. + +@end deffn + + +@node Procedure calls, Procedures, Literal expressions, Primitive expression types +@subsection Procedure calls + + + +@deffn {syntax} @r{} @r{} @dots{}, + + +A procedure call is written by simply enclosing in parentheses +expressions for the procedure to be called and the arguments to be +passed to it. The operator and operand expressions are evaluated (in an +unspecified order) and the resulting procedure is passed the resulting +arguments. +@cindex @w{procedure call} +@cindex @w{call} + +@format +@t{ +(+ 3 4) ==> 7 +((if #f + *) 3 4) ==> 12 +} +@end format + + +A number of procedures are available as the values of variables in the +initial environment; for example, the addition and multiplication +procedures in the above examples are the values of the variables @samp{+} +and @samp{*}. New procedures are created by evaluating lambda expressions +(see section @pxref{Procedures}). +@ignore todo +At Friedman's request, flushed mention of other ways. +@end ignore + +@c or definitions (see section~\ref{define}). + +Procedure calls may return any number of values (see @code{values} in +@vindex @w{values} +section @pxref{Control features}). With the exception of @samp{values} +the procedures available in the initial environment return one +value or, for procedures such as @samp{apply}, pass on the values returned +by a call to one of their arguments. + +Procedure calls are also called @emph{combinations}. + +@cindex @w{combination} + + +@quotation +@emph{Note:} In contrast to other dialects of Lisp, the order of +evaluation is unspecified, and the operator expression and the operand +expressions are always evaluated with the same evaluation rules. +@end quotation + + + +@quotation +@emph{Note:} +Although the order of evaluation is otherwise unspecified, the effect of +any concurrent evaluation of the operator and operand expressions is +constrained to be consistent with some sequential order of evaluation. +The order of evaluation may be chosen differently for each procedure call. +@end quotation + + + +@quotation +@emph{Note:} In many dialects of Lisp, the empty combination, @t{()}, is a legitimate expression. In Scheme, combinations must have at +least one subexpression, so @t{()} is not a syntactically valid +expression. +@ignore todo +Dybvig: ``it should be obvious from the syntax.'' +@end ignore + +@end quotation + + +@ignore todo +Freeman: +I think an explanation as to why evaluation order is not specified +should be included. It should not include any reference to parallel +evaluation. Does any existing compiler generate better code because +the evaluation order is unspecified? Clinger: yes: T3, MacScheme v2, +probably MIT Scheme and Chez Scheme. But that's not the main reason +for leaving the order unspecified. +@end ignore + + +@end deffn + + +@node Procedures, Conditionals, Procedure calls, Primitive expression types +@subsection Procedures + + + + +@deffn {syntax} lambda @r{} @r{} + +@emph{Syntax:} +@r{} should be a formal arguments list as described below, +and @r{} should be a sequence of one or more expressions. + +@emph{Semantics:} +A lambda expression evaluates to a procedure. The environment in +effect when the lambda expression was evaluated is remembered as part of the +procedure. When the procedure is later called with some actual +arguments, the environment in which the lambda expression was evaluated will +be extended by binding the variables in the formal argument list to +fresh locations, the corresponding actual argument values will be stored +in those locations, and the expressions in the body of the lambda expression +will be evaluated sequentially in the extended environment. +The result(s) of the last expression in the body will be returned as +the result(s) of the procedure call. + + +@format +@t{(lambda (x) (+ x x)) ==> @emph{}a procedure +((lambda (x) (+ x x)) 4) ==> 8 + +(define reverse-subtract + (lambda (x y) (- y x))) +(reverse-subtract 7 10) ==> 3 + +(define add4 + (let ((x 4)) + (lambda (y) (+ x y)))) +(add4 6) ==> 10 +} +@end format + + +@r{} should have one of the following forms: + + + +@itemize @bullet + +@item +@t{(@r{} @dots{},)}: +The procedure takes a fixed number of arguments; when the procedure is +called, the arguments will be stored in the bindings of the +corresponding variables. + +@item +@r{}: +The procedure takes any number of arguments; when the procedure is +called, the sequence of actual arguments is converted into a newly +allocated list, and the list is stored in the binding of the +@r{}. + +@item +@t{(@r{} @dots{}, @r{} @b{.} +@r{})}: +If a space-delimited period precedes the last variable, then +the procedure takes n or more arguments, where n is the +number of formal arguments before the period (there must +be at least one). +The value stored in the binding of the last variable will be a +newly allocated +list of the actual arguments left over after all the other actual +arguments have been matched up against the other formal arguments. + +@end itemize + + +It is an error for a @r{} to appear more than once in +@r{}. + + +@format +@t{((lambda x x) 3 4 5 6) ==> (3 4 5 6) +((lambda (x y . z) z) + 3 4 5 6) ==> (5 6) +} +@end format + + +Each procedure created as the result of evaluating a lambda expression is +(conceptually) tagged +with a storage location, in order to make @code{eqv?} and +@vindex @w{eqv?} +@code{eq?} work on procedures (see section @pxref{Equivalence predicates}). +@vindex @w{eq?} + +@end deffn + + +@node Conditionals, Assignments, Procedures, Primitive expression types +@subsection Conditionals + + + +@deffn {syntax} if @r{} @r{} @r{} +@deffnx {syntax} if @r{} @r{} +@c \/ if hyper = italic + +@emph{Syntax:} +@r{}, @r{}, and @r{} may be arbitrary +expressions. + +@emph{Semantics:} +An @samp{if} expression is evaluated as follows: first, +@r{} is evaluated. If it yields a true value (see +@cindex @w{true} +section @pxref{Booleans}), then @r{} is evaluated and +its value(s) is(are) returned. Otherwise @r{} is evaluated and its +value(s) is(are) returned. If @r{} yields a false value and no +@r{} is specified, then the result of the expression is +unspecified. + + +@format +@t{(if (> 3 2) 'yes 'no) ==> yes +(if (> 2 3) 'yes 'no) ==> no +(if (> 3 2) + (- 3 2) + (+ 3 2)) ==> 1 +} +@end format + + +@end deffn + + +@node Assignments, , Conditionals, Primitive expression types +@subsection Assignments + + + + +@deffn {syntax} set! @r{} @r{} + +@r{} is evaluated, and the resulting value is stored in +the location to which @r{} is bound. @r{} must +be bound either in some region enclosing the @samp{set!} expression +@cindex @w{region} +or at top level. The result of the @samp{set!} expression is +unspecified. + + +@format +@t{(define x 2) +(+ x 1) ==> 3 +(set! x 4) ==> @emph{unspecified} +(+ x 1) ==> 5 +} +@end format + + +@end deffn + + +@node Derived expression types, Macros, Primitive expression types, Expressions +@section Derived expression types + +@menu +* Conditional:: +* Binding constructs:: +* Sequencing:: +* Iteration:: +* Delayed evaluation:: +* Quasiquotation:: +@end menu + + + +The constructs in this section are hygienic, as discussed in +section @ref{Macros}. +For reference purposes, section @ref{Derived expression type} gives macro definitions +that will convert most of the constructs described in this section +into the primitive constructs described in the previous section. + +@ignore todo +Mention that no definition of backquote is provided? +@end ignore + + +@node Conditional, Binding constructs, Derived expression types, Derived expression types +@subsection Conditionals + + + +@deffn {library syntax} cond @dots{}, + +@emph{Syntax:} +Each @r{} should be of the form + +@format +@t{(@r{} @r{} @dots{},) +} +@end format + +where @r{} is any expression. Alternatively, a @r{} may be +of the form + +@format +@t{(@r{} => @r{}) +} +@end format + +The last @r{} may be +an ``else clause,'' which has the form + +@format +@t{(else @r{} @r{} @dots{},)@r{.} +} +@end format + + +@cindex @w{else} + +@cindex @w{=>} + +@emph{Semantics:} +A @samp{cond} expression is evaluated by evaluating the @r{} +expressions of successive @r{}s in order until one of them +evaluates to a true value (see +@cindex @w{true} +section @pxref{Booleans}). When a @r{} evaluates to a true +value, then the remaining @r{}s in its @r{} are +evaluated in order, and the result(s) of the last @r{} in the +@r{} is(are) returned as the result(s) of the entire @samp{cond} +expression. If the selected @r{} contains only the +@r{} and no @r{}s, then the value of the +@r{} is returned as the result. If the selected @r{} uses the +@code{=>} alternate form, then the @r{} is evaluated. +@vindex @w{=>} +Its value must be a procedure that accepts one argument; this procedure is then +called on the value of the @r{} and the value(s) returned by this +procedure is(are) returned by the @samp{cond} expression. +If all @r{}s evaluate +to false values, and there is no else clause, then the result of +the conditional expression is unspecified; if there is an else +clause, then its @r{}s are evaluated, and the value(s) of +the last one is(are) returned. + + +@format +@t{(cond ((> 3 2) 'greater) + ((< 3 2) 'less)) ==> greater + +(cond ((> 3 3) 'greater) + ((< 3 3) 'less) + (else 'equal)) ==> equal + +(cond ((assv 'b '((a 1) (b 2))) => cadr) + (else #f)) ==> 2 +} +@end format + + + +@end deffn + + + +@deffn {library syntax} case @r{} @dots{}, + +@emph{Syntax:} +@r{} may be any expression. Each @r{} should have +the form + +@format +@t{((@r{} @dots{},) @r{} @r{} @dots{},)@r{,} +} +@end format + +where each @r{} is an external representation of some object. +All the @r{}s must be distinct. +The last @r{} may be an ``else clause,'' which has the form + +@format +@t{(else @r{} @r{} @dots{},)@r{.} +} +@end format + + +@vindex else + +@emph{Semantics:} +A @samp{case} expression is evaluated as follows. @r{} is +evaluated and its result is compared against each @r{}. If the +result of evaluating @r{} is equivalent (in the sense of +@samp{eqv?}; see section @pxref{Equivalence predicates}) to a @r{}, then the +expressions in the corresponding @r{} are evaluated from left +to right and the result(s) of the last expression in the @r{} is(are) +returned as the result(s) of the @samp{case} expression. If the result of +evaluating @r{} is different from every @r{}, then if +there is an else clause its expressions are evaluated and the +result(s) of the last is(are) the result(s) of the @samp{case} expression; +otherwise the result of the @samp{case} expression is unspecified. + + +@format +@t{(case (* 2 3) + ((2 3 5 7) 'prime) + ((1 4 6 8 9) 'composite)) ==> composite +(case (car '(c d)) + ((a) 'a) + ((b) 'b)) ==> @emph{unspecified} +(case (car '(c d)) + ((a e i o u) 'vowel) + ((w y) 'semivowel) + (else 'consonant)) ==> consonant +} +@end format + + +@end deffn + + + +@deffn {library syntax} and @dots{}, + +The @r{} expressions are evaluated from left to right, and the +value of the first expression that evaluates to a false value (see +section @pxref{Booleans}) is returned. Any remaining expressions +are not evaluated. If all the expressions evaluate to true values, the +value of the last expression is returned. If there are no expressions +then @t{#t} is returned. + + +@format +@t{(and (= 2 2) (> 2 1)) ==> #t +(and (= 2 2) (< 2 1)) ==> #f +(and 1 2 'c '(f g)) ==> (f g) +(and) ==> #t +} +@end format + + +@end deffn + + + +@deffn {library syntax} or @dots{}, + +The @r{} expressions are evaluated from left to right, and the value of the +first expression that evaluates to a true value (see +section @pxref{Booleans}) is returned. Any remaining expressions +are not evaluated. If all expressions evaluate to false values, the +value of the last expression is returned. If there are no +expressions then @t{#f} is returned. + + +@format +@t{(or (= 2 2) (> 2 1)) ==> #t +(or (= 2 2) (< 2 1)) ==> #t +(or #f #f #f) ==> #f +(or (memq 'b '(a b c)) + (/ 3 0)) ==> (b c) +} +@end format + + +@end deffn + + +@node Binding constructs, Sequencing, Conditional, Derived expression types +@subsection Binding constructs + + +The three binding constructs @samp{let}, @samp{let*}, and @samp{letrec} +give Scheme a block structure, like Algol 60. The syntax of the three +constructs is identical, but they differ in the regions they establish +@cindex @w{region} +for their variable bindings. In a @samp{let} expression, the initial +values are computed before any of the variables become bound; in a +@samp{let*} expression, the bindings and evaluations are performed +sequentially; while in a @samp{letrec} expression, all the bindings are in +effect while their initial values are being computed, thus allowing +mutually recursive definitions. + + +@deffn {library syntax} let @r{} @r{} + +@emph{Syntax:} +@r{} should have the form + +@format +@t{((@r{} @r{}) @dots{},)@r{,} +} +@end format + +where each @r{} is an expression, and @r{} should be a +sequence of one or more expressions. It is +an error for a @r{} to appear more than once in the list of variables +being bound. + +@emph{Semantics:} +The @r{}s are evaluated in the current environment (in some +unspecified order), the @r{}s are bound to fresh locations +holding the results, the @r{} is evaluated in the extended +environment, and the value(s) of the last expression of @r{} +is(are) returned. Each binding of a @r{} has @r{} as its +region. +@cindex @w{region} + + +@format +@t{(let ((x 2) (y 3)) + (* x y)) ==> 6 + +(let ((x 2) (y 3)) + (let ((x 7) + (z (+ x y))) + (* z x))) ==> 35 +} +@end format + + +See also named @samp{let}, section @ref{Iteration}. + +@end deffn + + + +@deffn {library syntax} let* @r{} @r{} + + +@emph{Syntax:} +@r{} should have the form + +@format +@t{((@r{} @r{}) @dots{},)@r{,} +} +@end format + +and @r{} should be a sequence of +one or more expressions. + +@emph{Semantics:} +@samp{Let*} is similar to @samp{let}, but the bindings are performed +sequentially from left to right, and the region of a binding indicated +@cindex @w{region} +by @samp{(@r{} @r{})} is that part of the @samp{let*} +expression to the right of the binding. Thus the second binding is done +in an environment in which the first binding is visible, and so on. + + +@format +@t{(let ((x 2) (y 3)) + (let* ((x 7) + (z (+ x y))) + (* z x))) ==> 70 +} +@end format + + +@end deffn + + + +@deffn {library syntax} letrec @r{} @r{} + +@emph{Syntax:} +@r{} should have the form + +@format +@t{((@r{} @r{}) @dots{},)@r{,} +} +@end format + +and @r{} should be a sequence of +one or more expressions. It is an error for a @r{} to appear more +than once in the list of variables being bound. + +@emph{Semantics:} +The @r{}s are bound to fresh locations holding undefined +values, the @r{}s are evaluated in the resulting environment (in +some unspecified order), each @r{} is assigned to the result +of the corresponding @r{}, the @r{} is evaluated in the +resulting environment, and the value(s) of the last expression in +@r{} is(are) returned. Each binding of a @r{} has the +entire @samp{letrec} expression as its region, making it possible to +@cindex @w{region} +define mutually recursive procedures. + + +@format +@t{(letrec ((even? + (lambda (n) + (if (zero? n) + #t + (odd? (- n 1))))) + (odd? + (lambda (n) + (if (zero? n) + #f + (even? (- n 1)))))) + (even? 88)) + ==> #t +} +@end format + + +One restriction on @samp{letrec} is very important: it must be possible +to evaluate each @r{} without assigning or referring to the value of any +@r{}. If this restriction is violated, then it is an error. The +restriction is necessary because Scheme passes arguments by value rather than by +name. In the most common uses of @samp{letrec}, all the @r{}s are +lambda expressions and the restriction is satisfied automatically. + +@c \todo{use or uses? --- Jinx.} + +@end deffn + + +@node Sequencing, Iteration, Binding constructs, Derived expression types +@subsection Sequencing + + + +@deffn {library syntax} begin @dots{}, + +The @r{}s are evaluated sequentially from left to right, +and the value(s) of the last @r{} is(are) returned. This +expression type is used to sequence side effects such as input and +output. + + +@format +@t{(define x 0) + +(begin (set! x 5) + (+ x 1)) ==> 6 + +(begin (display "4 plus 1 equals ") + (display (+ 4 1))) ==> @emph{unspecified} + @emph{and prints} 4 plus 1 equals 5 +} +@end format + + +@end deffn + + +@node Iteration, Delayed evaluation, Sequencing, Derived expression types +@subsection Iteration + +@c \unsection + + +@noindent + +@deffn {library syntax} do ((@r{} @r{} @r{}) @dots{}) (@r{} @r{} @dots{}) @r{} @dots{} +@cindex @w{do} + +@samp{Do} is an iteration construct. It specifies a set of variables to +be bound, how they are to be initialized at the start, and how they are +to be updated on each iteration. When a termination condition is met, +the loop exits after evaluating the @r{}s. + +@samp{Do} expressions are evaluated as follows: +The @r{} expressions are evaluated (in some unspecified order), +the @r{}s are bound to fresh locations, the results of the +@r{} expressions are stored in the bindings of the +@r{}s, and then the iteration phase begins. + +Each iteration begins by evaluating @r{}; if the result is +false (see section @pxref{Booleans}), then the @r{} +expressions are evaluated in order for effect, the @r{} +expressions are evaluated in some unspecified order, the +@r{}s are bound to fresh locations, the results of the +@r{}s are stored in the bindings of the +@r{}s, and the next iteration begins. + +If @r{} evaluates to a true value, then the +@r{}s are evaluated from left to right and the value(s) of +the last @r{} is(are) returned. If no @r{}s +are present, then the value of the @samp{do} expression is unspecified. + +The region of the binding of a @r{} +@cindex @w{region} +consists of the entire @samp{do} expression except for the @r{}s. +It is an error for a @r{} to appear more than once in the +list of @samp{do} variables. + +A @r{} may be omitted, in which case the effect is the +same as if @samp{(@r{} @r{} @r{})} had +been written instead of @samp{(@r{} @r{})}. + + +@format +@t{(do ((vec (make-vector 5)) + (i 0 (+ i 1))) + ((= i 5) vec) + (vector-set! vec i i)) ==> #(0 1 2 3 4) + +(let ((x '(1 3 5 7 9))) + (do ((x x (cdr x)) + (sum 0 (+ sum (car x)))) + ((null? x) sum))) ==> 25 +} +@end format + + +@c \end{entry} +@end deffn + + +@deffn {library syntax} let @r{} @r{} @r{} + + +``Named @samp{let}'' is a variant on the syntax of @code{let} which provides +@vindex @w{let} +a more general looping construct than @samp{do} and may also be used to express +recursions. +It has the same syntax and semantics as ordinary @samp{let} +except that @r{} is bound within @r{} to a procedure +whose formal arguments are the bound variables and whose body is +@r{}. Thus the execution of @r{} may be repeated by +invoking the procedure named by @r{}. + +@c | <-- right margin + +@format +@t{(let loop ((numbers '(3 -2 1 6 -5)) + (nonneg '()) + (neg '())) + (cond ((null? numbers) (list nonneg neg)) + ((>= (car numbers) 0) + (loop (cdr numbers) + (cons (car numbers) nonneg) + neg)) + ((< (car numbers) 0) + (loop (cdr numbers) + nonneg + (cons (car numbers) neg))))) + ==> ((6 1 3) (-5 -2)) +} +@end format + + +@end deffn + + +@node Delayed evaluation, Quasiquotation, Iteration, Derived expression types +@subsection Delayed evaluation + + + +@deffn {library syntax} delay @r{} + +@ignore todo +Fix. +@end ignore + + +The @samp{delay} construct is used together with the procedure @code{force} to +@vindex @w{force} +implement @dfn{lazy evaluation} or @dfn{call by need}. +@cindex @w{call by need} +@cindex @w{lazy evaluation} +@t{(delay @r{})} returns an object called a +@dfn{promise} which at some point in the future may be asked (by +@cindex @w{promise} +the @samp{force} procedure) +@ignore todo +Bartley's white lie; OK? +@end ignore + to evaluate +@r{}, and deliver the resulting value. +The effect of @r{} returning multiple values +is unspecified. + +See the description of @samp{force} (section @pxref{Control features}) for a +more complete description of @samp{delay}. + +@end deffn + + +@node Quasiquotation, , Delayed evaluation, Derived expression types +@subsection Quasiquotation + + + + +@deffn {syntax} quasiquote @r{} + +@deffnx {syntax} @t{`}@r{} + + +``Backquote'' or ``quasiquote'' expressions are useful +@cindex @w{backquote} +for constructing a list or vector structure when most but not all of the +desired structure is known in advance. If no +commas appear within the @r{}, the result of +@cindex @w{comma} +evaluating +@t{`}@r{} is equivalent to the result of evaluating +@t{'}@r{}. If a comma appears within the +@cindex @w{,} +@r{}, however, the expression following the comma is +evaluated (``unquoted'') and its result is inserted into the structure +instead of the comma and the expression. If a comma appears followed +immediately by an at-sign (@@), then the following +@cindex @w{,@@} +expression must evaluate to a list; the opening and closing parentheses +of the list are then ``stripped away'' and the elements of the list are +inserted in place of the comma at-sign expression sequence. A comma +at-sign should only appear within a list or vector @r{}. + +@c struck: "(in the sense of {\cf equal?})" after "equivalent" + + +@format +@t{`(list ,(+ 1 2) 4) ==> (list 3 4) +(let ((name 'a)) `(list ,name ',name)) + ==> (list a (quote a)) +`(a ,(+ 1 2) ,@@(map abs '(4 -5 6)) b) + ==> (a 3 4 5 6 b) +`((@samp{foo} ,(- 10 3)) ,@@(cdr '(c)) . ,(car '(cons))) + ==> ((foo 7) . cons) +`#(10 5 ,(sqrt 4) ,@@(map sqrt '(16 9)) 8) + ==> #(10 5 2 4 3 8) +} +@end format + + +Quasiquote forms may be nested. Substitutions are made only for +unquoted components appearing at the same nesting level +as the outermost backquote. The nesting level increases by one inside +each successive quasiquotation, and decreases by one inside each +unquotation. + + +@format +@t{`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f) + ==> (a `(b ,(+ 1 2) ,(foo 4 d) e) f) +(let ((name1 'x) + (name2 'y)) + `(a `(b ,,name1 ,',name2 d) e)) + ==> (a `(b ,x ,'y d) e) +} +@end format + + +The two notations + @t{`}@r{} and @t{(quasiquote @r{})} + are identical in all respects. + @samp{,@r{}} is identical to @samp{(unquote @r{})}, + and + @samp{,@@@r{}} is identical to @samp{(unquote-splicing @r{})}. +The external syntax generated by @code{write} for two-element lists whose +@vindex @w{write} +car is one of these symbols may vary between implementations. + +@cindex @w{`} + + +@format +@t{(quasiquote (list (unquote (+ 1 2)) 4)) + ==> (list 3 4) +'(quasiquote (list (unquote (+ 1 2)) 4)) + ==> `(list ,(+ 1 2) 4) + @emph{}i.e., (quasiquote (list (unquote (+ 1 2)) 4)) +} +@end format + + +Unpredictable behavior can result if any of the symbols +@code{quasiquote}, @code{unquote}, or @code{unquote-splicing} appear in +@vindex @w{unquote-splicing} +@vindex @w{unquote} +@vindex @w{quasiquote} +positions within a @r{} otherwise than as described above. + +@end deffn + +@node Macros, , Derived expression types, Expressions +@section Macros + +@menu +* Binding constructs for syntactic keywords:: +* Pattern language:: +@end menu + + + +Scheme programs can define and use new derived expression types, + called @emph{macros}. +@cindex @w{macro} +Program-defined expression types have the syntax + +@example + +(@r{} @r{} ...) + +@end example + +where @r{} is an identifier that uniquely determines the +expression type. This identifier is called the @emph{syntactic +keyword}, or simply @emph{keyword}, of the macro. The +@cindex @w{macro keyword} +@cindex @w{keyword} +@cindex @w{syntactic keyword} +number of the @r{}s, and their syntax, depends on the +expression type. + +Each instance of a macro is called a @emph{use} +@cindex @w{macro use} +of the macro. +The set of rules that specifies +how a use of a macro is transcribed into a more primitive expression +is called the @emph{transformer} +@cindex @w{macro transformer} +of the macro. + +The macro definition facility consists of two parts: + + + +@itemize @bullet + +@item +A set of expressions used to establish that certain identifiers +are macro keywords, associate them with macro transformers, and control +the scope within which a macro is defined, and + +@item +a pattern language for specifying macro transformers. + +@end itemize + + +The syntactic keyword of a macro may shadow variable bindings, and local +variable bindings may shadow keyword bindings. All macros +@cindex @w{keyword} +defined using the pattern language are ``hygienic'' and ``referentially +transparent'' and thus preserve Scheme's lexical scoping [Kohlbecker86], [ +hygienic], [Bawden88], [macrosthatwork], [syntacticabstraction]: + +@cindex @w{hygienic} + +@cindex @w{referentially transparent} + + + + +@itemize @bullet + + +@item +If a macro transformer inserts a binding for an identifier +(variable or keyword), the identifier will in effect be renamed +throughout its scope to avoid conflicts with other identifiers. +Note that a @code{define} at top level may or may not introduce a binding; +see section @ref{Definitions}. + +@item +If a macro transformer inserts a free reference to an +identifier, the reference refers to the binding that was visible +where the transformer was specified, regardless of any local +bindings that may surround the use of the macro. + + +@end itemize + +@vindex @w{define} + +@c The low-level facility permits non-hygienic macros to be written, +@c and may be used to implement the high-level pattern language. + +@c The fourth section describes some features that would make the +@c low-level macro facility easier to use directly. + +@node Binding constructs for syntactic keywords, Pattern language, Macros, Macros +@subsection Binding constructs for syntactic keywords + + + +@samp{Let-syntax} and @samp{letrec-syntax} are +analogous to @samp{let} and @samp{letrec}, but they bind +syntactic keywords to macro transformers instead of binding variables +to locations that contain values. Syntactic keywords may also be +bound at top level; see section @ref{Syntax definitions}. + + +@deffn {syntax} let-syntax @r{} @r{} + +@emph{Syntax:} +@r{} should have the form + +@format +@t{((@r{} @r{}) @dots{},) +} +@end format + +Each @r{} is an identifier, +each @r{} is an instance of @samp{syntax-rules}, and +@r{} should be a sequence of one or more expressions. It is an error +for a @r{} to appear more than once in the list of keywords +being bound. + +@emph{Semantics:} +The @r{} is expanded in the syntactic environment +obtained by extending the syntactic environment of the +@samp{let-syntax} expression with macros whose keywords are +the @r{}s, bound to the specified transformers. +Each binding of a @r{} has @r{} as its region. + + +@format +@t{(let-syntax ((when (syntax-rules () + ((when test stmt1 stmt2 ...) + (if test + (begin stmt1 + stmt2 ...)))))) + (let ((if #t)) + (when if (set! if 'now)) + if)) ==> now + +(let ((x 'outer)) + (let-syntax ((m (syntax-rules () ((m) x)))) + (let ((x 'inner)) + (m)))) ==> outer +} +@end format + + +@end deffn + + +@deffn {syntax} letrec-syntax @r{} @r{} + +@emph{Syntax:} +Same as for @samp{let-syntax}. + +@emph{Semantics:} + The @r{} is expanded in the syntactic environment obtained by +extending the syntactic environment of the @samp{letrec-syntax} +expression with macros whose keywords are the +@r{}s, bound to the specified transformers. +Each binding of a @r{} has the @r{} +as well as the @r{} within its region, +so the transformers can +transcribe expressions into uses of the macros +introduced by the @samp{letrec-syntax} expression. + + +@format +@t{(letrec-syntax + ((my-or (syntax-rules () + ((my-or) #f) + ((my-or e) e) + ((my-or e1 e2 ...) + (let ((temp e1)) + (if temp + temp + (my-or e2 ...))))))) + (let ((x #f) + (y 7) + (temp 8) + (let odd?) + (if even?)) + (my-or x + (let temp) + (if y) + y))) ==> 7 +} +@end format + + +@end deffn + +@node Pattern language, , Binding constructs for syntactic keywords, Macros +@subsection Pattern language + + + +A @r{} has the following form: + + +@deffn {} syntax-rules @r{} @r{} @dots{}, + +@emph{Syntax:} +@r{} is a list of identifiers and each @r{} +should be of the form + +@format +@t{(@r{} @r{