remove `with-always-lexical' elisp special form
[bpt/guile.git] / test-suite / tests / elisp-compiler.test
1 ;;;; elisp-compiler.test --- Test the compiler for Elisp. -*- scheme -*-
2 ;;;;
3 ;;;; Copyright (C) 2009, 2010 Free Software Foundation, Inc.
4 ;;;; Daniel Kraft
5 ;;;;
6 ;;;; This library is free software; you can redistribute it and/or
7 ;;;; modify it under the terms of the GNU Lesser General Public
8 ;;;; License as published by the Free Software Foundation; either
9 ;;;; version 3 of the License, or (at your option) any later version.
10 ;;;;
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
15 ;;;;
16 ;;;; You should have received a copy of the GNU Lesser General Public
17 ;;;; License along with this library; if not, write to the Free Software
18 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
20 (define-module (test-elisp-compiler)
21 :use-module (test-suite lib)
22 :use-module (system base compile)
23 :use-module (language elisp runtime))
24
25
26 ; Macros to handle the compilation conveniently.
27
28 (define-syntax compile-test
29 (syntax-rules (pass-if pass-if-equal pass-if-exception)
30 ((_ (pass-if test-name exp))
31 (pass-if test-name (compile 'exp #:from 'elisp #:to 'value)))
32 ((_ (pass-if test-name exp #:opts opts))
33 (pass-if test-name (compile 'exp #:from 'elisp #:to 'value #:opts opts)))
34 ((_ (pass-if-equal test-name result exp))
35 (pass-if test-name (equal? result
36 (compile 'exp #:from 'elisp #:to 'value))))
37 ((_ (pass-if-exception test-name exc exp))
38 (pass-if-exception test-name exc
39 (compile 'exp #:from 'elisp #:to 'value)))))
40
41 (define-syntax with-test-prefix/compile
42 (syntax-rules ()
43 ((_ section-name exp ...)
44 (with-test-prefix section-name (compile-test exp) ...))))
45
46
47 ; Test control structures.
48 ; ========================
49
50 (with-test-prefix/compile "Sequencing"
51
52 (pass-if-equal "progn" 1
53 (progn (setq a 0)
54 (setq a (1+ a))
55 a))
56
57 (pass-if-equal "empty progn" #nil
58 (progn))
59
60 (pass-if "prog1"
61 (progn (setq a 0)
62 (setq b (prog1 a (setq a (1+ a))))
63 (and (= a 1) (= b 0))))
64
65 (pass-if "prog2"
66 (progn (setq a 0)
67 (setq b (prog2 (setq a (1+ a))
68 (setq a (1+ a))
69 (setq a (1+ a))))
70 (and (= a 3) (= b 2)))))
71
72 (with-test-prefix/compile "Conditionals"
73
74 (pass-if-equal "succeeding if" 1
75 (if t 1 2))
76 (pass-if "failing if"
77 (and (= (if nil
78 1
79 (setq a 2) (setq a (1+ a)) a)
80 3)
81 (equal (if nil 1) nil)))
82
83 (pass-if-equal "if with no else" #nil
84 (if nil t))
85
86 (pass-if-equal "empty cond" nil-value
87 (cond))
88 (pass-if-equal "all failing cond" nil-value
89 (cond (nil) (nil)))
90 (pass-if-equal "only condition" 5
91 (cond (nil) (5)))
92 (pass-if-equal "succeeding cond value" 42
93 (cond (nil) (t 42) (t 0)))
94 (pass-if-equal "succeeding cond side-effect" 42
95 (progn (setq a 0)
96 (cond (nil) (t (setq a 42) 1) (t (setq a 0)))
97 a)))
98
99 (with-test-prefix/compile "Combining Conditions"
100
101 (pass-if-equal "empty and" t-value (and))
102 (pass-if-equal "failing and" nil-value (and 1 2 nil 3))
103 (pass-if-equal "succeeding and" 3 (and 1 2 3))
104
105 (pass-if-equal "empty or" nil-value (or))
106 (pass-if-equal "failing or" nil-value (or nil nil nil))
107 (pass-if-equal "succeeding or" 1 (or nil 1 nil 2 nil 3))
108
109 (pass-if-equal "not true" nil-value (not 1))
110 (pass-if-equal "not false" t-value (not nil)))
111
112 (with-test-prefix/compile "Iteration"
113
114 (pass-if-equal "failing while" 0
115 (progn (setq a 0)
116 (while nil (setq a 1))
117 a))
118 (pass-if-equal "running while" 120
119 (progn (setq prod 1
120 i 1)
121 (while (<= i 5)
122 (setq prod (* i prod))
123 (setq i (1+ i)))
124 prod)))
125
126 (with-test-prefix/compile "Exceptions"
127
128 (pass-if "catch without exception"
129 (and (setq a 0)
130 (= (catch 'foobar
131 (setq a (1+ a))
132 (setq a (1+ a))
133 a)
134 2)
135 (= (catch (+ 1 2) a) 2)))
136
137 ; FIXME: Figure out how to do this...
138 ;(pass-if-exception "uncaught exception" 'elisp-exception
139 ; (throw 'abc 1))
140
141 (pass-if "catch and throw"
142 (and (setq mylist '(1 2))
143 (= (catch 'abc (throw 'abc 2) 1) 2)
144 (= (catch 'abc (catch 'def (throw 'abc (1+ 0)) 2) 3) 1)
145 (= (catch 'abc (catch 'def (throw 'def 1) 2) 3) 3)
146 (= (catch mylist (catch (list 1 2) (throw mylist 1) 2) 3) 1)))
147
148 (pass-if "unwind-protect"
149 (progn (setq a 0 b 1 c 1)
150 (catch 'exc
151 (unwind-protect (progn (setq a 1)
152 (throw 'exc 0))
153 (setq a 0)
154 (setq b 0)))
155 (unwind-protect nil (setq c 0))
156 (and (= a 0) (= b 0) (= c 0)
157 (= (unwind-protect 42 1 2 3) 42)))))
158
159 (with-test-prefix/compile "Eval"
160
161 (pass-if-equal "basic eval" 3
162 (progn (setq code '(+ 1 2))
163 (eval code)))
164
165 (pass-if "real dynamic code"
166 (and (setq a 1 b 1 c 1)
167 (defun set-code (var val)
168 (list 'setq var val))
169 (= a 1) (= b 1) (= c 1)
170 (eval (set-code 'a '(+ 2 3)))
171 (eval (set-code 'c 42))
172 (= a 5) (= b 1) (= c 42)))
173
174 ; Build code that recursively again and again calls eval. What we want is
175 ; something like:
176 ; (eval '(1+ (eval '(1+ (eval 1)))))
177 (pass-if "recursive eval"
178 (progn (setq depth 10 i depth)
179 (setq code '(eval 0))
180 (while (not (zerop i))
181 (setq code (#{`}# (eval (quote (1+ (#{,}# code))))))
182 (setq i (1- i)))
183 (= (eval code) depth))))
184
185
186 ; Test handling of variables.
187 ; ===========================
188
189 (with-test-prefix/compile "Variable Setting/Referencing"
190
191 ; TODO: Check for variable-void error
192
193 (pass-if-equal "setq and reference" 6
194 (progn (setq a 1 b 2 c 3)
195 (+ a b c)))
196 (pass-if-equal "setq evaluation order" 1
197 (progn (setq a 0 b 0)
198 (setq a 1 b a)))
199 (pass-if-equal "setq value" 2
200 (progn (setq a 1 b 2)))
201
202 (pass-if "set and symbol-value"
203 (progn (setq myvar 'a)
204 (and (= (set myvar 42) 42)
205 (= a 42)
206 (= (symbol-value myvar) 42))))
207 (pass-if "void variables"
208 (progn (setq a 1 b 2)
209 (and (eq (makunbound 'b) 'b)
210 (boundp 'a)
211 (not (boundp 'b))))))
212
213 (with-test-prefix/compile "Let and Let*"
214
215 (pass-if-equal "let without value" nil-value
216 (let (a (b 5)) a))
217 (pass-if-equal "basic let" 0
218 (progn (setq a 0)
219 (let ((a 1)
220 (b a))
221 b)))
222
223 (pass-if-equal "empty let" #nil (let ()))
224
225 (pass-if "let*"
226 (progn (setq a 0)
227 (and (let* ((a 1)
228 (b a))
229 (= b 1))
230 (let* (a b)
231 (setq a 1 b 2)
232 (and (= a 1) (= b 2)))
233 (= a 0)
234 (not (boundp 'b)))))
235
236 (pass-if-equal "empty let*" #nil
237 (let* ()))
238
239 (pass-if "local scope"
240 (progn (setq a 0)
241 (setq b (let (a)
242 (setq a 1)
243 a))
244 (and (= a 0)
245 (= b 1)))))
246
247 (with-test-prefix/compile "Lexical Scoping"
248
249 (pass-if "basic let semantics"
250 (and (setq a 1)
251 (lexical-let ((a 2) (b a))
252 (and (= a 2) (= b 1)))
253 (lexical-let* ((a 2) (b a))
254 (and (= a 2) (= b 2) (setq a 42) (= a 42)))
255 (= a 1)))
256
257 (pass-if "lexical scope with lexical-let's"
258 (and (setq a 1)
259 (defun dyna () a)
260 (lexical-let (a)
261 (setq a 2)
262 (and (= a 2) (= (dyna) 1)))
263 (= a 1)
264 (lexical-let* (a)
265 (setq a 2)
266 (and (= a 2) (= (dyna) 1)))
267 (= a 1)))
268
269 (pass-if "lexical scoping vs. symbol-value / set"
270 (and (setq a 1)
271 (lexical-let ((a 2))
272 (and (= a 2)
273 (= (symbol-value 'a) 1)
274 (set 'a 3)
275 (= a 2)
276 (= (symbol-value 'a) 3)))
277 (= a 3)))
278
279 (pass-if "let inside lexical-let"
280 (and (setq a 1 b 1)
281 (defun dynvals () (cons a b))
282 (lexical-let ((a 2))
283 (and (= a 2) (equal (dynvals) '(1 . 1))
284 (let ((a 3) (b a))
285 (and (= a 3) (= b 2)
286 (equal (dynvals) '(1 . 2))))
287 (let* ((a 4) (b a))
288 (and (= a 4) (= b 4)
289 (equal (dynvals) '(1 . 4))))
290 (= a 2)))
291 (= a 1)))
292
293 (pass-if "lambda args inside lexical-let"
294 (and (setq a 1)
295 (defun dyna () a)
296 (lexical-let ((a 2) (b 42))
297 (and (= a 2) (= (dyna) 1)
298 ((lambda (a) (and (= a 3) (= b 42) (= (dyna) 1))) 3)
299 ((lambda () (let ((a 3))
300 (and (= a 3) (= (dyna) 1)))))
301 (= a 2) (= (dyna) 1)))
302 (= a 1)))
303
304 (pass-if "closures"
305 (and (defun make-counter ()
306 (lexical-let ((cnt 0))
307 (lambda ()
308 (setq cnt (1+ cnt)))))
309 (setq c1 (make-counter) c2 (make-counter))
310 (= (funcall c1) 1)
311 (= (funcall c1) 2)
312 (= (funcall c1) 3)
313 (= (funcall c2) 1)
314 (= (funcall c2) 2)
315 (= (funcall c1) 4)
316 (= (funcall c2) 3)))
317
318 (pass-if "lexical lambda args"
319 (progn (setq a 1 b 1)
320 (defun dyna () a)
321 (defun dynb () b)
322 (lexical-let (a c)
323 ((lambda (a b &optional c)
324 (and (= a 3) (= (dyna) 1)
325 (= b 2) (= (dynb) 2)
326 (= c 1)))
327 3 2 1))))
328
329 ; Check if a lambda without dynamically bound arguments
330 ; is tail-optimized by doing a deep recursion that would otherwise overflow
331 ; the stack.
332 (pass-if "lexical lambda tail-recursion"
333 (lexical-let (i)
334 (setq to 1000000)
335 (defun iteration-1 (i)
336 (if (< i to)
337 (iteration-1 (1+ i))))
338 (iteration-1 0)
339 (setq x 0)
340 (defun iteration-2 ()
341 (if (< x to)
342 (setq x (1+ x))
343 (iteration-2)))
344 (iteration-2)
345 t)))
346
347
348 (with-test-prefix/compile "defconst and defvar"
349
350 (pass-if-equal "defconst without docstring" 3.141
351 (progn (setq pi 3)
352 (defconst pi 3.141)
353 pi))
354 (pass-if-equal "defconst value" 'pi
355 (defconst pi 3.141 "Pi"))
356
357 (pass-if-equal "defvar without value" 42
358 (progn (setq a 42)
359 (defvar a)
360 a))
361 (pass-if-equal "defvar on already defined variable" 42
362 (progn (setq a 42)
363 (defvar a 1 "Some docstring is also ok")
364 a))
365 (pass-if-equal "defvar on undefined variable" 1
366 (progn (makunbound 'a)
367 (defvar a 1)
368 a))
369 (pass-if-equal "defvar value" 'a
370 (defvar a)))
371
372
373 ; Functions and lambda expressions.
374 ; =================================
375
376 (with-test-prefix/compile "Lambda Expressions"
377
378 (pass-if-equal "required arguments" 3
379 ((lambda (a b c) c) 1 2 3))
380
381 (pass-if-equal "optional argument" 3
382 ((function (lambda (a &optional b c) c)) 1 2 3))
383 (pass-if-equal "optional missing" nil-value
384 ((lambda (&optional a) a)))
385
386 (pass-if-equal "rest argument" '(3 4 5)
387 ((lambda (a b &rest c) c) 1 2 3 4 5))
388 (pass-if-equal "rest missing" nil-value
389 ((lambda (a b &rest c) c) 1 2))
390
391 (pass-if-equal "empty lambda" #nil
392 ((lambda ()))))
393
394 (with-test-prefix/compile "Function Definitions"
395
396 (pass-if-equal "defun" 3
397 (progn (defun test (a b) (+ a b))
398 (test 1 2)))
399 (pass-if-equal "defun value" 'test
400 (defun test (a b) (+ a b)))
401
402 (pass-if "fset and symbol-function"
403 (progn (setq myfunc 'x x 5)
404 (and (= (fset myfunc 42) 42)
405 (= (symbol-function myfunc) 42)
406 (= x 5))))
407 (pass-if "void function values"
408 (progn (setq a 1)
409 (defun test (a b) (+ a b))
410 (fmakunbound 'a)
411 (fset 'b 5)
412 (and (fboundp 'b) (fboundp 'test)
413 (not (fboundp 'a))
414 (= a 1))))
415
416 (pass-if "flet and flet*"
417 (progn (defun foobar () 42)
418 (defun test () (foobar))
419 (and (= (test) 42)
420 (flet ((foobar (lambda () 0))
421 (myfoo (symbol-function 'foobar)))
422 (and (= (myfoo) 42)
423 (= (test) 42)))
424 (flet* ((foobar (lambda () 0))
425 (myfoo (symbol-function 'foobar)))
426 (= (myfoo) 42))
427 (flet (foobar)
428 (defun foobar () 0)
429 (= (test) 42))
430 (= (test) 42)))))
431
432 (with-test-prefix/compile "Calling Functions"
433
434 (pass-if-equal "recursion" 120
435 (progn (defun factorial (n prod)
436 (if (zerop n)
437 prod
438 (factorial (1- n) (* prod n))))
439 (factorial 5 1)))
440
441 (pass-if "dynamic scoping"
442 (progn (setq a 0)
443 (defun foo ()
444 (setq a (1+ a))
445 a)
446 (defun bar (a)
447 (foo))
448 (and (= 43 (bar 42))
449 (zerop a))))
450
451 (pass-if "funcall and apply argument handling"
452 (and (defun allid (&rest args) args)
453 (setq allid-var (symbol-function 'allid))
454 (equal (funcall allid-var 1 2 3) '(1 2 3))
455 (equal (funcall allid-var) nil)
456 (equal (funcall allid-var 1 2 '(3 4)) '(1 2 (3 4)))
457 (equal (funcall allid-var '()) '(()))
458 (equal (apply allid-var 1 2 '(3 4)) '(1 2 3 4))
459 (equal (apply allid-var '(1 2)) '(1 2))
460 (equal (apply allid-var '()) nil)))
461
462 (pass-if "raw functions with funcall"
463 (and (= (funcall '+ 1 2) 3)
464 (= (funcall (lambda (a b) (+ a b)) 1 2) 3)
465 (= (funcall '(lambda (a b) (+ a b)) 1 2) 3))))
466
467
468 ; Quoting and Backquotation.
469 ; ==========================
470
471 (with-test-prefix/compile "Quotation"
472
473 (pass-if "quote"
474 (and (equal '42 42) (equal '"abc" "abc")
475 (equal '(1 2 (3 (4) x)) '(1 2 (3 (4) x)))
476 (not (equal '(1 2 (3 4 (x))) '(1 2 3 4 x)))
477 (equal '(1 2 . 3) '(1 2 . 3))))
478
479 (pass-if "simple backquote"
480 (and (equal (#{`}# 42) 42)
481 (equal (#{`}# (1 (a))) '(1 (a)))
482 (equal (#{`}# (1 . 2)) '(1 . 2))))
483 (pass-if "unquote"
484 (progn (setq a 42 l '(18 12))
485 (and (equal (#{`}# (#{,}# a)) 42)
486 (equal (#{`}# (1 a ((#{,}# l)) . (#{,}# a))) '(1 a ((18 12)) . 42)))))
487 (pass-if "unquote splicing"
488 (progn (setq l '(18 12) empty '())
489 (and (equal (#{`}# (#{,@}# l)) '(18 12))
490 (equal (#{`}# (l 2 (3 (#{,@}# l)) ((#{,@}# l)) (#{,@}# l)))
491 '(l 2 (3 18 12) (18 12) 18 12))
492 (equal (#{`}# (1 2 (#{,@}# empty) 3)) '(1 2 3))))))
493
494
495
496 ; Macros.
497 ; =======
498
499 (with-test-prefix/compile "Macros"
500
501 (pass-if-equal "defmacro value" 'magic-number
502 (defmacro magic-number () 42))
503
504 (pass-if-equal "macro expansion" 1
505 (progn (defmacro take-first (a b) a)
506 (take-first 1 (/ 1 0)))))
507
508
509 ; Test the built-ins.
510 ; ===================
511
512 (with-test-prefix/compile "Equivalence Predicates"
513
514 (pass-if "equal"
515 (and (equal 2 2) (not (equal 1 2))
516 (equal "abc" "abc") (not (equal "abc" "ABC"))
517 (equal 'abc 'abc) (not (equal 'abc 'def))
518 (equal '(1 2 (3 4) 5) '(1 2 (3 4) 5))
519 (not (equal '(1 2 3 4 5) '(1 2 (3 4) 5)))))
520
521 (pass-if "eq"
522 (progn (setq some-list '(1 2))
523 (setq some-string "abc")
524 (and (eq 2 2) (not (eq 1 2))
525 (eq 'abc 'abc) (not (eq 'abc 'def))
526 (eq some-string some-string) (not (eq some-string (string 97 98 99)))
527 (eq some-list some-list) (not (eq some-list (list 1 2)))))))
528
529 (with-test-prefix/compile "Number Built-Ins"
530
531 (pass-if "floatp"
532 (and (floatp 1.0) (not (floatp 1)) (not (floatp 'a))))
533 (pass-if "integerp"
534 (and (integerp 42) (integerp -2) (not (integerp 1.0))))
535 (pass-if "numberp"
536 (and (numberp 1.0) (numberp -2) (not (numberp 'a))))
537 (pass-if "wholenump"
538 (and (wholenump 0) (not (wholenump -2)) (not (wholenump 1.0))))
539 (pass-if "zerop"
540 (and (zerop 0) (zerop 0.0) (not (zerop 1))))
541
542 (pass-if "comparisons"
543 (and (= 1 1.0) (/= 0 1)
544 (< 1 2) (> 2 1) (>= 1 1) (<= 1 1)
545 (not (< 1 1)) (not (<= 2 1))))
546
547 (pass-if "max and min"
548 (and (= (max -5 2 4.0 1) 4.0) (= (min -5 2 4.0 1) -5)
549 (= (max 1) 1) (= (min 1) 1)))
550 (pass-if "abs"
551 (and (= (abs 1.0) 1.0) (= (abs -5) 5)))
552
553 (pass-if "float"
554 (and (= (float 1) 1) (= (float 5.5) 5.5)
555 (floatp (float 1))))
556
557 (pass-if-equal "basic arithmetic operators" -8.5
558 (+ (1+ 0) (1- 0) (- 5.5) (* 2 -2) (- 2 1)))
559 (pass-if "modulo"
560 (= (% 5 3) 2))
561
562 (pass-if "floating point rounding"
563 (and (= (ffloor 1.7) 1.0) (= (ffloor -1.2) -2.0) (= (ffloor 1.0) 1.0)
564 (= (fceiling 1.2) 2.0) (= (fceiling -1.7) -1.0) (= (fceiling 1.0) 1.0)
565 (= (ftruncate 1.6) 1.0) (= (ftruncate -1.7) -1.0)
566 (= (fround 1.2) 1.0) (= (fround 1.7) 2.0) (= (fround -1.7) -2.0))))
567
568 (with-test-prefix/compile "List Built-Ins"
569
570 (pass-if "consp and atom"
571 (and (consp '(1 2 3)) (consp '(1 2 . 3)) (consp '(a . b))
572 (not (consp '())) (not (consp 1)) (not (consp "abc"))
573 (atom 'a) (atom '()) (atom -1.5) (atom "abc")
574 (not (atom '(1 . 2))) (not (atom '(1)))))
575 (pass-if "listp and nlistp"
576 (and (listp '(1 2 3)) (listp '(1)) (listp '()) (listp '(1 . 2))
577 (not (listp 'a)) (not (listp 42)) (nlistp 42)
578 (not (nlistp '())) (not (nlistp '(1 2 3))) (not (nlistp '(1 . 2)))))
579 (pass-if "null"
580 (and (null '()) (not (null 1)) (not (null '(1 2))) (not (null '(1 . 2)))))
581
582 (pass-if "car and cdr"
583 (and (equal (car '(1 2 3)) 1) (equal (cdr '(1 2 3)) '(2 3))
584 (equal (car '()) nil) (equal (cdr '()) nil)
585 (equal (car '(1 . 2)) 1) (equal (cdr '(1 . 2)) 2)
586 (null (cdr '(1)))))
587 (pass-if "car-safe and cdr-safe"
588 (and (equal (car-safe '(1 2)) 1) (equal (cdr-safe '(1 2)) '(2))
589 (equal (car-safe 5) nil) (equal (cdr-safe 5) nil)))
590
591 (pass-if "nth and nthcdr"
592 (and (equal (nth -5 '(1 2 3)) 1) (equal (nth 3 '(1 2 3)) nil)
593 (equal (nth 0 '(1 2 3)) 1) (equal (nth 2 '(1 2 3)) 3)
594 (equal (nthcdr -5 '(1 2 3)) '(1 2 3))
595 (equal (nthcdr 4 '(1 2 3)) nil)
596 (equal (nthcdr 1 '(1 2 3)) '(2 3))
597 (equal (nthcdr 2 '(1 2 3)) '(3))))
598
599 (pass-if "length"
600 (and (= (length '()) 0)
601 (= (length '(1 2 3 4 5)) 5)
602 (= (length '(1 2 (3 4 (5)) 6)) 4)))
603
604 (pass-if "cons, list and make-list"
605 (and (equal (cons 1 2) '(1 . 2)) (equal (cons 1 '(2 3)) '(1 2 3))
606 (equal (cons 1 '()) '(1))
607 (equal (list 'a) '(a)) (equal (list) '()) (equal (list 1 2) '(1 2))
608 (equal (make-list 3 42) '(42 42 42))
609 (equal (make-list 0 1) '())))
610 (pass-if "append"
611 (and (equal (append '(1 2) '(3 4) '(5)) '(1 2 3 4 5))
612 (equal (append '(1 2) 3) '(1 2 . 3))))
613 (pass-if "reverse"
614 (and (equal (reverse '(5 4 3 2 1)) '(1 2 3 4 5))
615 (equal (reverse '()) '())))
616 (pass-if "setcar and setcdr"
617 (progn (setq pair '(1 . 2))
618 (setq copy pair)
619 (setq a (setcar copy 3))
620 (setq b (setcdr copy 4))
621 (and (= a 3) (= b 4)
622 (equal pair '(3 . 4))))))