-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathmyenv.sch
204 lines (171 loc) · 7.32 KB
/
myenv.sch
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
;; My Standard Scheme "Prelude"
;;
;; This version of the prelude contains several forms and procedures
;; that are specific to a Gambit-C 3.0 system.
;; See myenv-scm.scm, myenv-bigloo.scm, etc. for versions
;; of this prelude that are tuned to other Scheme systems.
;;
;; $Id: myenv.scm,v 1.12 2001/03/14 18:21:42 oleg Exp oleg $
;==============================================================================
; Assertion tests
; assert truth of an expression (or a sequence of expressions)
; if there is more than one expression, they're 'AND'ed
(define-macro (assert . x)
(if (null? (cdr x))
`(or ,@x (error "failed assertion" ',@x))
`(or (and ,@x) (error "failed assertion" '(,@x)))))
;==============================================================================
; Some useful increment/decrement operators
; Note, ##fixnum prefix is Gambit-specific, it means that the
; operands assumed FIXNUM (as they ought to be anyway).
; This perfix could be safely removed: it'll leave the code just as
; correct, but more portable (and less efficient)
; Mutable increment
(define-macro (++! x) `(set! ,x (##fixnum.+ 1 ,x)))
; Read-only increment
(define-macro (++ x) `(##fixnum.+ 1 ,x))
; Mutable decrement
(define-macro (--! x) `(set! ,x (##fixnum.- ,x 1)))
; Read-only decrement
(define-macro (-- x) `(##fixnum.- ,x 1))
;==============================================================================
; Some useful control operators
; if condition is true, execute stmts in turn
; and return the result of the last statement
; otherwise, return #f
(define-macro (when condition . stmts)
`(and ,condition (begin ,@stmts)))
; if condition is false execute stmts in turn
; and return the result of the last statement
; otherwise, return #t
; This primitive is often called 'unless'
(define-macro (whennot condition . stmts)
`(or ,condition (begin ,@stmts)))
; Execute a sequence of forms and return the
; result of the _first_ one. Like PROG1 in Lisp.
; Typically used to evaluate one or more forms with
; side effects and return a value that must be
; computed before some or all of the side effects
; happen.
(define-macro (begin0 form . forms)
(let ((var (gensym)))
`(let ((,var ,form)) ,@forms ,var)))
; Prepend an ITEM to a LIST, like a Lisp macro PUSH
; an ITEM can be an expression, but ls must be a VAR
(define-macro (push! item ls)
`(set! ,ls (cons ,item ,ls)))
; Is str the empty string?
; string-null? str -> bool
; See Olin Shiver's Underground String functions
(define-macro (string-null? str) `(zero? (string-length ,str)))
;==============================================================================
; Support for multiple-values and let-values* form
; Multiple values are not present natively in Gambit.
; What follows is an _approximation_: it is not very good in case
; of continuations captured while evaluating an argument expression of
; values. Note that the only meaningful way to use 'values' procedure is
; in conjunction with call-with-values or let-values*
; The next 2 functions are now supported natively in Gambit 4
;
;(define values list)
;
;(define (call-with-values producer consumer)
; (apply consumer (producer)))
;
;; Like let* but allowing for multiple-value bindings
;(define-macro (let-values* bindings . body)
; (if (null? bindings) (cons 'begin body)
; (apply (lambda (vars initializer)
; (let ((cont
; (cons 'let-values*
; (cons (cdr bindings) body))))
; (cond
; ((not (pair? vars)) ; regular let case, a single var
; `(let ((,vars ,initializer)) ,cont))
; ((null? (cdr vars)) ; single var, see the prev case
; `(let ((,(car vars) ,initializer)) ,cont))
; ((null? (cddr vars)) ; two variables
; (let ((val (gensym)))
; `(let* ((,val ,initializer)
; (,(car vars) (car ,val))
; (,(cadr vars) (cadr ,val))) ,cont)))
; (else ; the most generic case
; `(apply (lambda ,vars ,cont) ,initializer)))))
; (car bindings))))
;==============================================================================
; assoc-primitives with a default clause
; If the search in the assoc list fails, the
; default action argument is returned. If this
; default action turns out to be a thunk,
; the result of its evaluation is returned.
; If the default action is not given, an error
; is signaled
(define-macro (assq-def key alist . default-action-arg)
(let ((default-action
(if (null? default-action-arg)
`(error "failed to assq key '" ,key "' in a list " ,alist)
(let ((defact-symb (gensym)))
`(let ((,defact-symb ,(car default-action-arg)))
(if (procedure? ,defact-symb) (,defact-symb) ,defact-symb))))))
`(or (assq ,key ,alist) ,default-action)))
(define-macro (assv-def key alist . default-action-arg)
(let ((default-action
(if (null? default-action-arg)
`(error "failed to assv key '" ,key "' in a list " ,alist)
(let ((defact-symb (gensym)))
`(let ((,defact-symb ,(car default-action-arg)))
(if (procedure? ,defact-symb) (,defact-symb) ,defact-symb))))))
`(or (assv ,key ,alist) ,default-action)))
(define-macro (assoc-def key alist . default-action-arg)
(let ((default-action
(if (null? default-action-arg)
`(error "failed to assoc key '" ,key "' in a list " ,alist)
(let ((defact-symb (gensym)))
`(let ((,defact-symb ,(car default-action-arg)))
(if (procedure? ,defact-symb) (,defact-symb) ,defact-symb))))))
`(or (assoc ,key ,alist) ,default-action)))
;==============================================================================
; Convenience macros to avoid quoting of symbols
; being deposited/looked up in the environment
(define-macro (env.find key) `(%%env.find ',key))
(define-macro (env.demand key) `(%%env.demand ',key))
(define-macro (env.bind key value) `(%%env.bind ',key ,value))
;==============================================================================
; Implementation of SRFI-0
; Only feature-identifiers srfi-0 and gambit
; assumed predefined
(define-macro (cond-expand . clauses)
(define feature-ids '(gambit srfi-0))
(define (feature-req-satisfies? fr) ; does feature-request satisfies?
(cond
((memq fr feature-ids) #t)
((not (pair? fr)) #f)
((eq? 'and (car fr))
(let loop ((clauses (cdr fr)))
(or (null? clauses)
(and (feature-req-satisfies? (car clauses))
(loop (cdr clauses))))))
((eq? 'or (car fr))
(let loop ((clauses (cdr fr)))
(and (pair? clauses)
(or (feature-req-satisfies? (car clauses))
(loop (cdr clauses))))))
((eq? 'not (car fr))
(not (feature-req-satisfies? (and (pair? (cdr fr)) (cadr fr)))))
(else #f)))
(let loop ((clauses clauses))
(if (null? clauses) '(error "Unfulfilled cond-expand")
(let* ((feature-req (if (pair? (car clauses)) (caar clauses)
(error "<cond-expand clause> is not a list")))
(cmd-or-defs* (cons 'begin (cdar clauses))))
(cond
((and (eq? 'else feature-req) (null? (cdr clauses)))
cmd-or-defs*)
((feature-req-satisfies? feature-req)
cmd-or-defs*)
(else (loop (cdr clauses))))))))
;==============================================================================
; DL: taken from previous versions of "myenv.scm"
; DL: aliases for ++ and --
(define-macro (inc x) `(##fixnum.+ 1 ,x))
(define-macro (dec x) `(##fixnum.- ,x 1))