improve management of global special variables
[bpt/guile.git] / module / language / elisp / boot.el
CommitLineData
ddc9006b 1;;; Guile Emacs Lisp -*- lexical-binding: t -*-
6937c7aa
BT
2
3;;; Copyright (C) 2011 Free Software Foundation, Inc.
4
5;;; This library is free software; you can redistribute it and/or modify
6;;; it under the terms of the GNU Lesser General Public License as
7;;; published by the Free Software Foundation; either version 3 of the
8;;; License, or (at your option) any later version.
9;;;
10;;; This library is distributed in the hope that it will be useful, but
11;;; WITHOUT ANY WARRANTY; without even the implied warranty of
12;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;;; Lesser General Public License for more details.
14;;;
15;;; You should have received a copy of the GNU Lesser General Public
16;;; License along with this library; if not, write to the Free Software
17;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18;;; 02110-1301 USA
19
20;;; Code:
9b15703d
BT
21
22(defmacro @ (module symbol)
23 `(guile-ref ,module ,symbol))
24
b652e2b9
BT
25(defmacro eval-and-compile (&rest body)
26 `(progn
27 (eval-when-compile ,@body)
28 (progn ,@body)))
29
30(eval-and-compile
b652e2b9
BT
31 (defun null (object)
32 (if object nil t))
b05ca4ab
BT
33 (defun consp (object)
34 (%funcall (@ (guile) pair?) object))
b652e2b9
BT
35 (defun listp (object)
36 (if object (consp object) t))
37 (defun car (list)
b05ca4ab 38 (if list (%funcall (@ (guile) car) list) nil))
b652e2b9 39 (defun cdr (list)
b05ca4ab
BT
40 (if list (%funcall (@ (guile) cdr) list) nil))
41 (defun make-symbol (name)
42 (%funcall (@ (guile) make-symbol) name))
5950f674
BT
43 (defun signal (error-symbol data)
44 (%funcall (@ (guile) throw) 'elisp-condition error-symbol data)))
b652e2b9
BT
45
46(defmacro lambda (&rest cdr)
47 `#'(lambda ,@cdr))
48
49(defmacro prog1 (first &rest body)
50 (let ((temp (make-symbol "prog1-temp")))
13f022c9
BT
51 `(let ((,temp ,first))
52 (declare (lexical ,temp))
b652e2b9
BT
53 ,@body
54 ,temp)))
55
56(defmacro prog2 (form1 form2 &rest body)
57 `(progn ,form1 (prog1 ,form2 ,@body)))
58
59(defmacro cond (&rest clauses)
60 (if (null clauses)
61 nil
62 (let ((first (car clauses))
63 (rest (cdr clauses)))
64 (if (listp first)
65 (let ((condition (car first))
66 (body (cdr first)))
67 (if (null body)
68 (let ((temp (make-symbol "cond-temp")))
13f022c9
BT
69 `(let ((,temp ,condition))
70 (declare (lexical ,temp))
b652e2b9
BT
71 (if ,temp
72 ,temp
73 (cond ,@rest))))
74 `(if ,condition
75 (progn ,@body)
76 (cond ,@rest))))
77 (signal 'wrong-type-argument `(listp ,first))))))
78
79(defmacro and (&rest conditions)
80 (cond ((null conditions) t)
81 ((null (cdr conditions)) (car conditions))
82 (t `(if ,(car conditions)
83 (and ,@(cdr conditions))
84 nil))))
85
86(defmacro or (&rest conditions)
87 (cond ((null conditions) nil)
88 ((null (cdr conditions)) (car conditions))
89 (t (let ((temp (make-symbol "or-temp")))
13f022c9
BT
90 `(let ((,temp ,(car conditions)))
91 (declare (lexical ,temp))
b652e2b9
BT
92 (if ,temp
93 ,temp
94 (or ,@(cdr conditions))))))))
95
9083c48d
BT
96(defmacro lexical-let (bindings &rest body)
97 (labels ((loop (list vars)
98 (if (null list)
99 `(let ,bindings
100 (declare (lexical ,@vars))
101 ,@body)
102 (loop (cdr list)
103 (if (consp (car list))
104 `(,(car (car list)) ,@vars)
105 `(,(car list) ,@vars))))))
106 (loop bindings '())))
107
108(defmacro lexical-let* (bindings &rest body)
109 (labels ((loop (list vars)
110 (if (null list)
111 `(let* ,bindings
112 (declare (lexical ,@vars))
113 ,@body)
114 (loop (cdr list)
115 (if (consp (car list))
116 (cons (car (car list)) vars)
117 (cons (car list) vars))))))
118 (loop bindings '())))
119
9b90b453
BT
120(defmacro while (test &rest body)
121 (let ((loop (make-symbol "loop")))
122 `(labels ((,loop ()
123 (if ,test
124 (progn ,@body (,loop))
125 nil)))
126 (,loop))))
127
b652e2b9
BT
128(defmacro unwind-protect (bodyform &rest unwindforms)
129 `(funcall (@ (guile) dynamic-wind)
130 #'(lambda () nil)
131 #'(lambda () ,bodyform)
132 #'(lambda () ,@unwindforms)))
9b15703d 133
b05ca4ab
BT
134(defun symbolp (object)
135 (%funcall (@ (guile) symbol?) object))
136
137(defun functionp (object)
138 (%funcall (@ (guile) procedure?) object))
139
140(defun symbol-function (symbol)
141 (let ((f (%funcall (@ (language elisp runtime) symbol-function)
142 symbol)))
143 (if (%funcall (@ (language elisp falias) falias?) f)
144 (%funcall (@ (language elisp falias) falias-object) f)
145 f)))
97d9da9a 146
5bcc6d9e 147(defun eval (form)
b05ca4ab
BT
148 (%funcall (@ (system base compile) compile)
149 form
150 (%funcall (@ (guile) symbol->keyword) 'from)
151 'elisp
152 (%funcall (@ (guile) symbol->keyword) 'to)
153 'value))
154
155(defun %indirect-function (object)
156 (cond
157 ((functionp object)
158 object)
159 ((symbolp object) ;++ cycle detection
160 (%indirect-function (symbol-function object)))
161 ((listp object)
162 (eval `(function ,object)))
163 (t
164 (signal 'invalid-function `(,object)))))
165
166(defun apply (function &rest arguments)
167 (%funcall (@ (guile) apply)
168 (@ (guile) apply)
169 (%indirect-function function)
170 arguments))
171
172(defun funcall (function &rest arguments)
173 (%funcall (@ (guile) apply)
174 (%indirect-function function)
175 arguments))
176
177(defun fset (symbol definition)
178 (funcall (@ (language elisp runtime) set-symbol-function!)
179 symbol
180 (if (functionp definition)
181 definition
182 (funcall (@ (language elisp falias) make-falias)
183 #'(lambda (&rest args) (apply definition args))
184 definition)))
185 definition)
186
5bcc6d9e
BT
187(defun load (file)
188 (funcall (@ (system base compile) compile-file)
189 file
190 (funcall (@ (guile) symbol->keyword) 'from)
191 'elisp
192 (funcall (@ (guile) symbol->keyword) 'to)
193 'value)
194 t)
195
9b15703d
BT
196;;; Equality predicates
197
0ab2a63a
BT
198(defun eq (obj1 obj2)
199 (if obj1
200 (funcall (@ (guile) eq?) obj1 obj2)
201 (null obj2)))
202
203(defun eql (obj1 obj2)
204 (if obj1
205 (funcall (@ (guile) eqv?) obj1 obj2)
206 (null obj2)))
207
208(defun equal (obj1 obj2)
209 (if obj1
210 (funcall (@ (guile) equal?) obj1 obj2)
211 (null obj2)))
9b15703d 212
85bc6238
BT
213;;; Symbols
214
b05ca4ab
BT
215;;; `symbolp' and `symbol-function' are defined above.
216
85bc6238 217(fset 'symbol-value (@ (language elisp runtime) symbol-value))
85bc6238
BT
218(fset 'set (@ (language elisp runtime) set-symbol-value!))
219(fset 'makunbound (@ (language elisp runtime) makunbound!))
220(fset 'fmakunbound (@ (language elisp runtime) fmakunbound!))
221(fset 'boundp (@ (language elisp runtime) symbol-bound?))
222(fset 'fboundp (@ (language elisp runtime) symbol-fbound?))
223
14b288ce
BT
224(defun defvaralias (new-alias base-variable &optional docstring)
225 (let ((fluid (funcall (@ (language elisp runtime) symbol-fluid)
226 base-variable)))
227 (funcall (@ (language elisp runtime) set-symbol-fluid!)
228 new-alias
229 fluid)
230 base-variable))
231
9b15703d
BT
232;;; Numerical type predicates
233
234(defun floatp (object)
235 (and (funcall (@ (guile) real?) object)
236 (or (funcall (@ (guile) inexact?) object)
237 (null (funcall (@ (guile) integer?) object)))))
238
239(defun integerp (object)
240 (and (funcall (@ (guile) exact?) object)
241 (funcall (@ (guile) integer?) object)))
242
243(defun numberp (object)
244 (funcall (@ (guile) real?) object))
245
246(defun wholenump (object)
247 (and (funcall (@ (guile) exact?) object)
248 (funcall (@ (guile) integer?) object)
249 (>= object 0)))
250
251(defun zerop (object)
252 (= object 0))
253
254;;; Numerical comparisons
255
256(fset '= (@ (guile) =))
257
258(defun /= (num1 num2)
259 (null (= num1 num2)))
260
261(fset '< (@ (guile) <))
262(fset '<= (@ (guile) <=))
263(fset '> (@ (guile) >))
264(fset '>= (@ (guile) >=))
265
266(defun max (&rest numbers)
267 (apply (@ (guile) max) numbers))
268
269(defun min (&rest numbers)
270 (apply (@ (guile) min) numbers))
271
272;;; Arithmetic functions
273
274(fset '1+ (@ (guile) 1+))
275(fset '1- (@ (guile) 1-))
276(fset '+ (@ (guile) +))
277(fset '- (@ (guile) -))
278(fset '* (@ (guile) *))
279(fset '% (@ (guile) modulo))
280(fset 'abs (@ (guile) abs))
281
282;;; Floating-point rounding
283
284(fset 'ffloor (@ (guile) floor))
285(fset 'fceiling (@ (guile) ceiling))
286(fset 'ftruncate (@ (guile) truncate))
287(fset 'fround (@ (guile) round))
288
289;;; Numeric conversion
290
291(defun float (arg)
292 (if (numberp arg)
293 (funcall (@ (guile) exact->inexact) arg)
294 (signal 'wrong-type-argument `(numberp ,arg))))
295
296;;; List predicates
297
9b15703d
BT
298(fset 'not #'null)
299
300(defun atom (object)
301 (null (consp object)))
302
9b15703d
BT
303(defun nlistp (object)
304 (null (listp object)))
305
306;;; Lists
307
308(fset 'cons (@ (guile) cons))
309(fset 'list (@ (guile) list))
310(fset 'make-list (@ (guile) make-list))
311(fset 'append (@ (guile) append))
312(fset 'reverse (@ (guile) reverse))
313
9b15703d
BT
314(defun car-safe (object)
315 (if (consp object)
316 (car object)
317 nil))
318
319(defun cdr-safe (object)
320 (if (consp object)
321 (cdr object)
322 nil))
323
324(defun setcar (cell newcar)
325 (if (consp cell)
326 (progn
327 (funcall (@ (guile) set-car!) cell newcar)
328 newcar)
329 (signal 'wrong-type-argument `(consp ,cell))))
330
331(defun setcdr (cell newcdr)
332 (if (consp cell)
333 (progn
334 (funcall (@ (guile) set-cdr!) cell newcdr)
335 newcdr)
336 (signal 'wrong-type-argument `(consp ,cell))))
337
338(defun nthcdr (n list)
339 (let ((i 0))
340 (while (< i n)
341 (setq list (cdr list)
342 i (+ i 1)))
343 list))
344
345(defun nth (n list)
346 (car (nthcdr n list)))
347
df9cd3b4
BT
348(defun %member (elt list test)
349 (cond
350 ((null list) nil)
351 ((consp list)
352 (if (funcall test elt (car list))
353 list
354 (%member elt (cdr list) test)))
355 (t (signal 'wrong-type-argument `(listp ,list)))))
356
357(defun member (elt list)
358 (%member elt list #'equal))
359
360(defun memql (elt list)
361 (%member elt list #'eql))
362
363(defun memq (elt list)
364 (%member elt list #'eq))
365
8f2f6566
BT
366;;; Strings
367
368(defun string (&rest characters)
369 (funcall (@ (guile) list->string)
370 (mapcar (@ (guile) integer->char) characters)))
371
9b15703d
BT
372;;; Sequences
373
374(fset 'length (@ (guile) length))
8f2f6566
BT
375
376(defun mapcar (function sequence)
377 (funcall (@ (guile) map) function sequence))
12ca82ca
BT
378
379;;; Property lists
380
381(defun %plist-member (plist property test)
76c50ec5
BT
382 (cond
383 ((null plist) nil)
384 ((consp plist)
385 (if (funcall test (car plist) property)
386 (cdr plist)
387 (%plist-member (cdr (cdr plist)) property test)))
388 (t (signal 'wrong-type-argument `(listp ,plist)))))
12ca82ca
BT
389
390(defun %plist-get (plist property test)
391 (car (%plist-member plist property test)))
392
393(defun %plist-put (plist property value test)
13f022c9 394 (let ((x (%plist-member plist property test)))
12ca82ca
BT
395 (if x
396 (progn (setcar x value) plist)
397 (cons property (cons value plist)))))
398
399(defun plist-get (plist property)
400 (%plist-get plist property #'eq))
401
402(defun plist-put (plist property value)
403 (%plist-put plist property value #'eq))
404
405(defun plist-member (plist property)
406 (%plist-member plist property #'eq))
407
408(defun lax-plist-get (plist property)
409 (%plist-get plist property #'equal))
410
411(defun lax-plist-put (plist property value)
412 (%plist-put plist property value #'equal))
413
414(defvar plist-function (funcall (@ (guile) make-object-property)))
415
416(defun symbol-plist (symbol)
417 (funcall plist-function symbol))
418
419(defun setplist (symbol plist)
420 (funcall (funcall (@ (guile) setter) plist-function) symbol plist))
421
422(defun get (symbol propname)
423 (plist-get (symbol-plist symbol) propname))
424
425(defun put (symbol propname value)
426 (setplist symbol (plist-put (symbol-plist symbol) propname value)))
5950f674
BT
427
428;;; Nonlocal exits
429
430(defmacro condition-case (var bodyform &rest handlers)
431 (let ((key (make-symbol "key"))
432 (error-symbol (make-symbol "error-symbol"))
433 (data (make-symbol "data"))
434 (conditions (make-symbol "conditions")))
435 (flet ((handler->cond-clause (handler)
436 `((or ,@(mapcar #'(lambda (c) `(memq ',c ,conditions))
437 (if (consp (car handler))
438 (car handler)
439 (list (car handler)))))
440 ,@(cdr handler))))
441 `(funcall (@ (guile) catch)
442 'elisp-condition
443 #'(lambda () ,bodyform)
444 #'(lambda (,key ,error-symbol ,data)
b07a7449 445 (declare (lexical ,key ,error-symbol ,data))
5950f674
BT
446 (let ((,conditions
447 (get ,error-symbol 'error-conditions))
448 ,@(if var
449 `((,var (cons ,error-symbol ,data)))
450 '()))
b07a7449
BT
451 (declare (lexical ,conditions
452 ,@(if var `(,var) '())))
5950f674
BT
453 (cond ,@(mapcar #'handler->cond-clause handlers)
454 (t (signal ,error-symbol ,data)))))))))
ce9b7cc2
BT
455
456(put 'error 'error-conditions '(error))
457(put 'wrong-type-argument 'error-conditions '(wrong-type-argument error))
458(put 'invalid-function 'error-conditions '(invalid-function error))
459(put 'no-catch 'error-conditions '(no-catch error))
8fb67871
BT
460(put 'throw 'error-conditions '(throw))
461
85b3dd6c
BT
462(defvar %catch nil)
463
8fb67871
BT
464(defmacro catch (tag &rest body)
465 (let ((tag-value (make-symbol "tag-value"))
466 (c (make-symbol "c"))
467 (data (make-symbol "data")))
468 `(let ((,tag-value ,tag))
b07a7449 469 (declare (lexical ,tag-value))
8fb67871 470 (condition-case ,c
85b3dd6c
BT
471 (let ((%catch t))
472 ,@body)
8fb67871
BT
473 (throw
474 (let ((,data (cdr ,c)))
b07a7449 475 (declare (lexical ,data))
8fb67871
BT
476 (if (eq (car ,data) ,tag-value)
477 (car (cdr ,data))
85b3dd6c 478 (apply #'throw ,data))))))))
ce9b7cc2 479
8fb67871 480(defun throw (tag value)
85b3dd6c 481 (signal (if %catch 'throw 'no-catch) (list tag value)))