elisp sequence functions
[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)
fc45b7e8
BT
240 (and (funcall (@ (guile) integer?) object)
241 (funcall (@ (guile) exact?) object)))
9b15703d
BT
242
243(defun numberp (object)
244 (funcall (@ (guile) real?) object))
245
246(defun wholenump (object)
fc45b7e8 247 (and (integerp object) (>= object 0)))
9b15703d
BT
248
249(defun zerop (object)
250 (= object 0))
251
252;;; Numerical comparisons
253
254(fset '= (@ (guile) =))
255
256(defun /= (num1 num2)
257 (null (= num1 num2)))
258
259(fset '< (@ (guile) <))
260(fset '<= (@ (guile) <=))
261(fset '> (@ (guile) >))
262(fset '>= (@ (guile) >=))
263
264(defun max (&rest numbers)
265 (apply (@ (guile) max) numbers))
266
267(defun min (&rest numbers)
268 (apply (@ (guile) min) numbers))
269
270;;; Arithmetic functions
271
272(fset '1+ (@ (guile) 1+))
273(fset '1- (@ (guile) 1-))
274(fset '+ (@ (guile) +))
275(fset '- (@ (guile) -))
276(fset '* (@ (guile) *))
277(fset '% (@ (guile) modulo))
278(fset 'abs (@ (guile) abs))
279
280;;; Floating-point rounding
281
282(fset 'ffloor (@ (guile) floor))
283(fset 'fceiling (@ (guile) ceiling))
284(fset 'ftruncate (@ (guile) truncate))
285(fset 'fround (@ (guile) round))
286
287;;; Numeric conversion
288
289(defun float (arg)
290 (if (numberp arg)
291 (funcall (@ (guile) exact->inexact) arg)
292 (signal 'wrong-type-argument `(numberp ,arg))))
293
294;;; List predicates
295
9b15703d
BT
296(fset 'not #'null)
297
298(defun atom (object)
299 (null (consp object)))
300
9b15703d
BT
301(defun nlistp (object)
302 (null (listp object)))
303
304;;; Lists
305
306(fset 'cons (@ (guile) cons))
307(fset 'list (@ (guile) list))
308(fset 'make-list (@ (guile) make-list))
309(fset 'append (@ (guile) append))
310(fset 'reverse (@ (guile) reverse))
12c00a04 311(fset 'nreverse (@ (guile) reverse!))
9b15703d 312
9b15703d
BT
313(defun car-safe (object)
314 (if (consp object)
315 (car object)
316 nil))
317
318(defun cdr-safe (object)
319 (if (consp object)
320 (cdr object)
321 nil))
322
323(defun setcar (cell newcar)
324 (if (consp cell)
325 (progn
326 (funcall (@ (guile) set-car!) cell newcar)
327 newcar)
328 (signal 'wrong-type-argument `(consp ,cell))))
329
330(defun setcdr (cell newcdr)
331 (if (consp cell)
332 (progn
333 (funcall (@ (guile) set-cdr!) cell newcdr)
334 newcdr)
335 (signal 'wrong-type-argument `(consp ,cell))))
336
337(defun nthcdr (n list)
338 (let ((i 0))
339 (while (< i n)
340 (setq list (cdr list)
341 i (+ i 1)))
342 list))
343
344(defun nth (n list)
345 (car (nthcdr n list)))
346
df9cd3b4
BT
347(defun %member (elt list test)
348 (cond
349 ((null list) nil)
350 ((consp list)
351 (if (funcall test elt (car list))
352 list
353 (%member elt (cdr list) test)))
354 (t (signal 'wrong-type-argument `(listp ,list)))))
355
356(defun member (elt list)
357 (%member elt list #'equal))
358
359(defun memql (elt list)
360 (%member elt list #'eql))
361
362(defun memq (elt list)
363 (%member elt list #'eq))
364
12c00a04
BT
365(defun assoc (key list)
366 (funcall (@ (srfi srfi-1) assoc) key list #'equal))
367
368(defun assq (key list)
369 (funcall (@ (srfi srfi-1) assoc) key list #'eq))
370
371(defun rplaca (cell newcar)
372 (funcall (@ (guile) set-car!) cell newcar)
373 newcar)
374
375(defun rplacd (cell newcdr)
376 (funcall (@ (guile) set-cdr!) cell newcdr)
377 newcdr)
378
379(defun caar (x)
380 (car (car x)))
381
382(defun cadr (x)
383 (car (cdr x)))
384
385(defun cdar (x)
386 (cdr (car x)))
387
388(defun cddr (x)
389 (cdr (cdr x)))
390
391(defmacro dolist (spec &rest body)
392 (apply #'(lambda (var list &optional result)
393 `(mapc #'(lambda (,var)
394 ,@body
395 ,result)
396 ,list))
397 spec))
398
8f2f6566
BT
399;;; Strings
400
401(defun string (&rest characters)
402 (funcall (@ (guile) list->string)
403 (mapcar (@ (guile) integer->char) characters)))
404
12c00a04
BT
405(defun stringp (object)
406 (funcall (@ (guile) string?) object))
407
408(defun string-equal (s1 s2)
409 (let ((s1 (if (symbolp s1) (symbol-name s1) s1))
410 (s2 (if (symbolp s2) (symbol-name s2) s2)))
411 (funcall (@ (guile) string=?) s1 s2)))
412
413(fset 'string= 'string-equal)
414
415(defun substring (string from &optional to)
416 (apply (@ (guile) substring) string from (if to (list to) nil)))
417
418(defun upcase (obj)
419 (funcall (@ (guile) string-upcase) obj))
420
421(defun downcase (obj)
422 (funcall (@ (guile) string-downcase) obj))
423
424(defun string-match (regexp string &optional start)
425 (let ((m (funcall (@ (ice-9 regex) string-match)
426 regexp
427 string
428 (or start 0))))
429 (if m
430 (funcall (@ (ice-9 regex) match:start) m 0)
431 nil)))
432
433;; Vectors
434
435(defun make-vector (length init)
436 (funcall (@ (guile) make-vector) length init))
437
9b15703d
BT
438;;; Sequences
439
440(fset 'length (@ (guile) length))
8f2f6566
BT
441
442(defun mapcar (function sequence)
443 (funcall (@ (guile) map) function sequence))
12ca82ca 444
12c00a04
BT
445(defun mapc (function sequence)
446 (funcall (@ (guile) for-each) function sequence)
447 sequence)
448
449(defun aref (array idx)
450 (funcall (@ (guile) generalized-vector-ref) array idx))
451
452(defun aset (array idx newelt)
453 (funcall (@ (guile) generalized-vector-set!) array idx newelt)
454 newelt)
455
456(defun concat (&rest sequences)
457 (apply (@ (guile) string-append) sequences))
458
12ca82ca
BT
459;;; Property lists
460
461(defun %plist-member (plist property test)
76c50ec5
BT
462 (cond
463 ((null plist) nil)
464 ((consp plist)
465 (if (funcall test (car plist) property)
466 (cdr plist)
467 (%plist-member (cdr (cdr plist)) property test)))
468 (t (signal 'wrong-type-argument `(listp ,plist)))))
12ca82ca
BT
469
470(defun %plist-get (plist property test)
471 (car (%plist-member plist property test)))
472
473(defun %plist-put (plist property value test)
13f022c9 474 (let ((x (%plist-member plist property test)))
12ca82ca
BT
475 (if x
476 (progn (setcar x value) plist)
477 (cons property (cons value plist)))))
478
479(defun plist-get (plist property)
480 (%plist-get plist property #'eq))
481
482(defun plist-put (plist property value)
483 (%plist-put plist property value #'eq))
484
485(defun plist-member (plist property)
486 (%plist-member plist property #'eq))
487
488(defun lax-plist-get (plist property)
489 (%plist-get plist property #'equal))
490
491(defun lax-plist-put (plist property value)
492 (%plist-put plist property value #'equal))
493
494(defvar plist-function (funcall (@ (guile) make-object-property)))
495
496(defun symbol-plist (symbol)
497 (funcall plist-function symbol))
498
499(defun setplist (symbol plist)
500 (funcall (funcall (@ (guile) setter) plist-function) symbol plist))
501
502(defun get (symbol propname)
503 (plist-get (symbol-plist symbol) propname))
504
505(defun put (symbol propname value)
506 (setplist symbol (plist-put (symbol-plist symbol) propname value)))
5950f674
BT
507
508;;; Nonlocal exits
509
510(defmacro condition-case (var bodyform &rest handlers)
511 (let ((key (make-symbol "key"))
512 (error-symbol (make-symbol "error-symbol"))
513 (data (make-symbol "data"))
514 (conditions (make-symbol "conditions")))
515 (flet ((handler->cond-clause (handler)
516 `((or ,@(mapcar #'(lambda (c) `(memq ',c ,conditions))
517 (if (consp (car handler))
518 (car handler)
519 (list (car handler)))))
520 ,@(cdr handler))))
521 `(funcall (@ (guile) catch)
522 'elisp-condition
523 #'(lambda () ,bodyform)
524 #'(lambda (,key ,error-symbol ,data)
b07a7449 525 (declare (lexical ,key ,error-symbol ,data))
5950f674
BT
526 (let ((,conditions
527 (get ,error-symbol 'error-conditions))
528 ,@(if var
529 `((,var (cons ,error-symbol ,data)))
530 '()))
b07a7449
BT
531 (declare (lexical ,conditions
532 ,@(if var `(,var) '())))
5950f674
BT
533 (cond ,@(mapcar #'handler->cond-clause handlers)
534 (t (signal ,error-symbol ,data)))))))))
ce9b7cc2
BT
535
536(put 'error 'error-conditions '(error))
537(put 'wrong-type-argument 'error-conditions '(wrong-type-argument error))
538(put 'invalid-function 'error-conditions '(invalid-function error))
539(put 'no-catch 'error-conditions '(no-catch error))
8fb67871
BT
540(put 'throw 'error-conditions '(throw))
541
85b3dd6c
BT
542(defvar %catch nil)
543
8fb67871
BT
544(defmacro catch (tag &rest body)
545 (let ((tag-value (make-symbol "tag-value"))
546 (c (make-symbol "c"))
547 (data (make-symbol "data")))
548 `(let ((,tag-value ,tag))
b07a7449 549 (declare (lexical ,tag-value))
8fb67871 550 (condition-case ,c
85b3dd6c
BT
551 (let ((%catch t))
552 ,@body)
8fb67871
BT
553 (throw
554 (let ((,data (cdr ,c)))
b07a7449 555 (declare (lexical ,data))
8fb67871
BT
556 (if (eq (car ,data) ,tag-value)
557 (car (cdr ,data))
85b3dd6c 558 (apply #'throw ,data))))))))
ce9b7cc2 559
8fb67871 560(defun throw (tag value)
85b3dd6c 561 (signal (if %catch 'throw 'no-catch) (list tag value)))
39864d20
BT
562
563;;; I/O
564
565(defun princ (object)
566 (funcall (@ (guile) display) object))
567
568(defun print (object)
569 (funcall (@ (guile) write) object))
570
571(defun terpri ()
572 (funcall (@ (guile) newline)))
573
574(defun format* (stream string &rest args)
575 (apply (@ (guile) format) stream string args))