This repository has been archived by the owner on Nov 8, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
dynamic-state.lisp
105 lines (96 loc) · 3.43 KB
/
dynamic-state.lisp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; File - dynamic-state.lisp
;; Description - Dynamic state access
;; Author - Tim Bradshaw (tfb at KINGSTON)
;; Created On - Wed Feb 21 09:10:49 2001
;; Last Modified On - Mon Jun 3 17:33:58 2002
;; Last Modified By - Tim Bradshaw (tfb at lostwithiel)
;; Update Count - 21
;; Status - Unknown
;;
;; $Id: //depot/www-tfeb-org/before-2013-prune/www-tfeb-org/html/programs/lisp/dynamic-state.lisp#1 $
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; Dynamic state access
;;;
;;; dynamic-state.lisp is copyright 2001 by me, Tim Bradshaw, and
;;; may be used for any purpose whatsoever by anyone. It has no
;;; warranty whatsoever. I would appreciate acknowledgement if you use
;;; it in anger, and I would also very much appreciate any feedback or
;;; bug fixes.
(eval-when (:compile-toplevel :load-toplevel :execute)
(when (not (find-package ':org.tfeb.hax))
(make-package ':org.tfeb.hax)))
(eval-when (:compile-toplevel :load-toplevel :execute)
(export '(org.tfeb.hax::define-dynamic-state)
(find-package ':org.tfeb.hax)))
(in-package :org.tfeb.hax)
(defmacro define-dynamic-state ((binder accessor) &rest all-specials)
;; define a binder, BINDER, and accessor, ACCESSOR for some dynamic
;; state variables. The legal variables must come from
;; ALL-SPECIALS.
`(progn
(defmacro ,binder (bindings &body body)
;; Establish a dynamic state: binding specs like LET.
(let ((varnames
(mapcan #'(lambda (b)
(typecase b
(symbol
(unless (member b ',all-specials)
(error "~S is not a valid dynamic state variable for ~S"
b ',binder))
(list b))
(cons
(unless (and (= (length b) 2)
(symbolp (first b)))
(error "~S is not a valid binding specification" b))
(unless (member (first b) ',all-specials)
(error "~S is not a valid dynamic state variable for ~S"
(first b) ',binder))
(list (first b)))
(t
(error "~S is not a valid binding specification" b))))
bindings)))
;; try and generate slightly reasonable-looking code.
(if (not (null varnames))
`(let ,bindings
(declare (special ,@varnames))
,@body)
`(locally
,@body))))
(defmacro ,accessor (varnames &body body)
;; get access to a dynamic state -- VARNAMES is list of
;; variables we want to see.
(dolist (v varnames)
(unless (symbolp v)
(error "~S is not a valid binding specification" v))
(unless (member v ',all-specials)
(error "~S is not a valid dynamic state variable for ~S"
v ',accessor)))
;; try and generate slightly reasonable-looking code.
(if (not (null varnames))
`(locally
(declare (special ,@varnames))
,@body)
`(locally
,@body)))
'(,binder ,accessor)))
#||
(define-dynamic-state (with-dynamic-state with-dynamic-state-access)
error-code result)
(defun foo (x)
(with-dynamic-state ((result x))
(bar)
(values (let ((result 10))
;; This RESULT is *lexical*, so this closes over it
#'(lambda (x)
(cons x result)))
result)))
(defun bar ()
(let ((result 12))
;; This closure closes over the *lexical* RESULT we have here.
(henry #'(lambda (x)
(cons x result)))))
(defun henry (fn)
(with-dynamic-state-access (result)
(setf result fn)))
||#