📄 calling.scm
字号:
;;;; calling.scm --- Calling Conventions;;;;;;;; Copyright (C) 1995, 1996, 1997, 2000, 2001 Free Software Foundation, Inc.;;;; ;;;; This program is free software; you can redistribute it and/or modify;;;; it under the terms of the GNU General Public License as published by;;;; the Free Software Foundation; either version 2, or (at your option);;;; any later version.;;;; ;;;; This program is distributed in the hope that it will be useful,;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the;;;; GNU General Public License for more details.;;;; ;;;; You should have received a copy of the GNU General Public License;;;; along with this software; see the file COPYING. If not, write to;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,;;;; Boston, MA 02111-1307 USA;;;;;;;; As a special exception, the Free Software Foundation gives permission;;;; for additional uses of the text contained in its release of GUILE.;;;;;;;; The exception is that, if you link the GUILE library with other files;;;; to produce an executable, this does not by itself cause the;;;; resulting executable to be covered by the GNU General Public License.;;;; Your use of that executable is in no way restricted on account of;;;; linking the GUILE library code into it.;;;;;;;; This exception does not however invalidate any other reasons why;;;; the executable file might be covered by the GNU General Public License.;;;;;;;; This exception applies only to the code released by the;;;; Free Software Foundation under the name GUILE. If you copy;;;; code from other Free Software Foundation releases into a copy of;;;; GUILE, as the General Public License permits, the exception does;;;; not apply to the code that you add in this way. To avoid misleading;;;; anyone as to the status of such modified files, you must delete;;;; this exception notice from them.;;;;;;;; If you write modifications of your own for GUILE, it is your choice;;;; whether to permit this exception to apply to your modifications.;;;; If you do not wish that, delete this exception notice.;;;; (define-module (ice-9 calling) :export-syntax (with-excursion-function with-getter-and-setter with-getter with-delegating-getter-and-setter with-excursion-getter-and-setter with-configuration-getter-and-setter with-delegating-configuration-getter-and-setter let-with-configuration-getter-and-setter));;;;;;;;;; This file contains a number of macros that support ;;; common calling conventions.;;;;;; with-excursion-function <vars> proc;;; <vars> is an unevaluated list of names that are bound in the caller.;;; proc is a procedure, called:;;; (proc excursion);;;;;; excursion is a procedure isolates all changes to <vars>;;; in the dynamic scope of the call to proc. In other words,;;; the values of <vars> are saved when proc is entered, and when;;; proc returns, those values are restored. Values are also restored;;; entering and leaving the call to proc non-locally, such as using;;; call-with-current-continuation, error, or throw.;;;(defmacro with-excursion-function (vars proc) `(,proc ,(excursion-function-syntax vars)));;; with-getter-and-setter <vars> proc;;; <vars> is an unevaluated list of names that are bound in the caller.;;; proc is a procedure, called:;;; (proc getter setter);;; ;;; getter and setter are procedures used to access;;; or modify <vars>.;;; ;;; setter, called with keywords arguments, modifies the named;;; values. If "foo" and "bar" are among <vars>, then:;;; ;;; (setter :foo 1 :bar 2);;; == (set! foo 1 bar 2);;; ;;; getter, called with just keywords, returns;;; a list of the corresponding values. For example,;;; if "foo" and "bar" are among the <vars>, then;;; ;;; (getter :foo :bar);;; => (<value-of-foo> <value-of-bar>);;; ;;; getter, called with no arguments, returns a list of all accepted ;;; keywords and the corresponding values. If "foo" and "bar" are;;; the *only* <vars>, then:;;; ;;; (getter);;; => (:foo <value-of-bar> :bar <value-of-foo>);;; ;;; The unusual calling sequence of a getter supports too handy;;; idioms:;;; ;;; (apply setter (getter)) ;; save and restore;;; ;;; (apply-to-args (getter :foo :bar) ;; fetch and bind;;; (lambda (foo bar) ....));;; ;;; ;; [ "apply-to-args" is just like two-argument "apply" except that it ;;; ;; takes its arguments in a different order.;;; ;;;(defmacro with-getter-and-setter (vars proc) `(,proc ,@ (getter-and-setter-syntax vars)));;; with-getter vars proc;;; A short-hand for a call to with-getter-and-setter.;;; The procedure is called:;;; (proc getter);;;(defmacro with-getter (vars proc) `(,proc ,(car (getter-and-setter-syntax vars))));;; with-delegating-getter-and-setter <vars> get-delegate set-delegate proc;;; Compose getters and setters.;;; ;;; <vars> is an unevaluated list of names that are bound in the caller.;;; ;;; get-delegate is called by the new getter to extend the set of ;;; gettable variables beyond just <vars>;;; set-delegate is called by the new setter to extend the set of ;;; gettable variables beyond just <vars>;;;;;; proc is a procedure that is called;;; (proc getter setter);;;(defmacro with-delegating-getter-and-setter (vars get-delegate set-delegate proc) `(,proc ,@ (delegating-getter-and-setter-syntax vars get-delegate set-delegate)));;; with-excursion-getter-and-setter <vars> proc;;; <vars> is an unevaluated list of names that are bound in the caller.;;; proc is called:;;;;;; (proc excursion getter setter);;;;;; See also:;;; with-getter-and-setter;;; with-excursion-function;;;(defmacro with-excursion-getter-and-setter (vars proc) `(,proc ,(excursion-function-syntax vars) ,@ (getter-and-setter-syntax vars)))(define (excursion-function-syntax vars) (let ((saved-value-names (map gensym vars)) (tmp-var-name (gensym "temp")) (swap-fn-name (gensym "swap")) (thunk-name (gensym "thunk"))) `(lambda (,thunk-name) (letrec ((,tmp-var-name #f) (,swap-fn-name (lambda () ,@ (map (lambda (n sn) `(begin (set! ,tmp-var-name ,n) (set! ,n ,sn) (set! ,sn ,tmp-var-name))) vars saved-value-names))) ,@ (map (lambda (sn n) `(,sn ,n)) saved-value-names vars)) (dynamic-wind ,swap-fn-name ,thunk-name ,swap-fn-name)))))(define (getter-and-setter-syntax vars) (let ((args-name (gensym "args")) (an-arg-name (gensym "an-arg")) (new-val-name (gensym "new-value")) (loop-name (gensym "loop")) (kws (map symbol->keyword vars))) (list `(lambda ,args-name (let ,loop-name ((,args-name ,args-name)) (if (null? ,args-name) ,(if (null? kws) ''() `(let ((all-vals (,loop-name ',kws))) (let ,loop-name ((vals all-vals) (kws ',kws)) (if (null? vals) '() `(,(car kws) ,(car vals) ,@(,loop-name (cdr vals) (cdr kws))))))) (map (lambda (,an-arg-name) (case ,an-arg-name ,@ (append (map (lambda (kw v) `((,kw) ,v)) kws vars) `((else (throw 'bad-get-option ,an-arg-name)))))) ,args-name)))) `(lambda ,args-name (let ,loop-name ((,args-name ,args-name)) (or (null? ,args-name) (null? (cdr ,args-name)) (let ((,an-arg-name (car ,args-name)) (,new-val-name (cadr ,args-name))) (case ,an-arg-name ,@ (append (map (lambda (kw v) `((,kw) (set! ,v ,new-val-name))) kws vars) `((else (throw 'bad-set-option ,an-arg-name))))) (,loop-name (cddr ,args-name)))))))))(define (delegating-getter-and-setter-syntax vars get-delegate set-delegate) (let ((args-name (gensym "args")) (an-arg-name (gensym "an-arg")) (new-val-name (gensym "new-value")) (loop-name (gensym "loop")) (kws (map symbol->keyword vars))) (list `(lambda ,args-name (let ,loop-name ((,args-name ,args-name)) (if (null? ,args-name) (append! ,(if (null? kws) ''() `(let ((all-vals (,loop-name ',kws))) (let ,loop-name ((vals all-vals) (kws ',kws)) (if (null? vals) '() `(,(car kws) ,(car vals) ,@(,loop-name (cdr vals) (cdr kws))))))) (,get-delegate)) (map (lambda (,an-arg-name) (case ,an-arg-name ,@ (append (map (lambda (kw v) `((,kw) ,v)) kws vars) `((else (car (,get-delegate ,an-arg-name))))))) ,args-name)))) `(lambda ,args-name (let ,loop-name ((,args-name ,args-name)) (or (null? ,args-name) (null? (cdr ,args-name)) (let ((,an-arg-name (car ,args-name)) (,new-val-name (cadr ,args-name))) (case ,an-arg-name ,@ (append (map (lambda (kw v) `((,kw) (set! ,v ,new-val-name))) kws vars) `((else (,set-delegate ,an-arg-name ,new-val-name))))) (,loop-name (cddr ,args-name)))))))));;; with-configuration-getter-and-setter <vars-etc> proc;;;;;; Create a getter and setter that can trigger arbitrary computation.;;;;;; <vars-etc> is a list of variable specifiers, explained below.;;; proc is called:;;;;;; (proc getter setter);;;;;; Each element of the <vars-etc> list is of the form:;;;;;; (<var> getter-hook setter-hook);;;;;; Both hook elements are evaluated; the variable name is not.;;; Either hook may be #f or procedure.;;;;;; A getter hook is a thunk that returns a value for the corresponding;;; variable. If omitted (#f is passed), the binding of <var> is;;; returned.;;;;;; A setter hook is a procedure of one argument that accepts a new value;;; for the corresponding variable. If omitted, the binding of <var>;;; is simply set using set!.;;;(defmacro with-configuration-getter-and-setter (vars-etc proc) `((lambda (simpler-get simpler-set body-proc) (with-delegating-getter-and-setter () simpler-get simpler-set body-proc)) (lambda (kw) (case kw ,@(map (lambda (v) `((,(symbol->keyword (car v))) ,(cond ((cadr v) => list) (else `(list ,(car v)))))) vars-etc))) (lambda (kw new-val) (case kw ,@(map (lambda (v) `((,(symbol->keyword (car v))) ,(cond ((caddr v) => (lambda (proc) `(,proc new-val))) (else `(set! ,(car v) new-val))))) vars-etc))) ,proc))(defmacro with-delegating-configuration-getter-and-setter (vars-etc delegate-get delegate-set proc) `((lambda (simpler-get simpler-set body-proc) (with-delegating-getter-and-setter () simpler-get simpler-set body-proc)) (lambda (kw) (case kw ,@(append! (map (lambda (v) `((,(symbol->keyword (car v))) ,(cond ((cadr v) => list) (else `(list ,(car v)))))) vars-etc) `((else (,delegate-get kw)))))) (lambda (kw new-val) (case kw ,@(append! (map (lambda (v) `((,(symbol->keyword (car v))) ,(cond ((caddr v) => (lambda (proc) `(,proc new-val))) (else `(set! ,(car v) new-val))))) vars-etc) `((else (,delegate-set kw new-val)))))) ,proc));;; let-configuration-getter-and-setter <vars-etc> proc;;;;;; This procedure is like with-configuration-getter-and-setter (q.v.);;; except that each element of <vars-etc> is:;;;;;; (<var> initial-value getter-hook setter-hook);;;;;; Unlike with-configuration-getter-and-setter, let-configuration-getter-and-setter;;; introduces bindings for the variables named in <vars-etc>.;;; It is short-hand for:;;;;;; (let ((<var1> initial-value-1);;; (<var2> initial-value-2);;; ...);;; (with-configuration-getter-and-setter ((<var1> v1-get v1-set) ...) proc));;;(defmacro let-with-configuration-getter-and-setter (vars-etc proc) `(let ,(map (lambda (v) `(,(car v) ,(cadr v))) vars-etc) (with-configuration-getter-and-setter ,(map (lambda (v) `(,(car v) ,(caddr v) ,(cadddr v))) vars-etc) ,proc)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -