1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-04 05:50:26 +02:00
guile/test-suite/tests/syntax.test
Dirk Herrmann cc56ba8062 * libguile/eval.c (s_missing_expression, s_bad_variable): New static
identifiers.

	(scm_m_define): Use ASSERT_SYNTAX to signal syntax errors.  Prefer
	R5RS terminology for the naming of variables.  Be more specific
	about the kind of error that was detected.  Make sure file name,
	line number etc. are added to all freshly created expressions.
	Avoid unnecessary consing when creating the memoized code.

	* test-suite/tests/syntax.test (exception:missing-expr,
	exception:extra-expr): New.

	Adapted tests for 'begin' to the new way of error
	reporting.
2003-10-11 16:03:29 +00:00

868 lines
21 KiB
Scheme

;;;; syntax.test --- test suite for Guile's syntactic forms -*- scheme -*-
;;;;
;;;; Copyright (C) 2001, 2003 Free Software Foundation, Inc.
;;;;
;;;; This program is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License as published by
;;;; the Free Software Foundation; either version 2, or (at your option)
;;;; any later version.
;;;;
;;;; This program is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with this software; see the file COPYING. If not, write to
;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;;;; Boston, MA 02111-1307 USA
(define-module (test-suite test-syntax)
:use-module (test-suite lib))
(define exception:bad-expression
(cons 'syntax-error "Bad expression"))
(define exception:missing/extra-expr
(cons 'misc-error "^missing or extra expression"))
(define exception:missing-expr
(cons 'syntax-error "Missing expression"))
(define exception:extra-expr
(cons 'syntax-error "Extra expression"))
(define exception:bad-bindings
(cons 'misc-error "^bad bindings"))
(define exception:duplicate-bindings
(cons 'misc-error "^duplicate bindings"))
(define exception:bad-body
(cons 'misc-error "^bad body"))
(define exception:bad-formals
(cons 'misc-error "^bad formals"))
(define exception:duplicate-formals
(cons 'misc-error "^duplicate formals"))
(define exception:missing-clauses
(cons 'syntax-error "Missing clauses"))
(define exception:misplaced-else-clause
(cons 'syntax-error "Misplaced else clause"))
(define exception:bad-case-clause
(cons 'syntax-error "Bad case clause"))
(define exception:bad-case-labels
(cons 'syntax-error "Bad case labels"))
(define exception:bad-cond-clause
(cons 'syntax-error "Bad cond clause"))
(define exception:bad-var
(cons 'misc-error "^bad variable"))
(with-test-prefix "expressions"
(with-test-prefix "Bad argument list"
(pass-if-exception "improper argument list of length 1"
exception:wrong-num-args
(eval '(let ((foo (lambda (x y) #t)))
(foo . 1))
(interaction-environment)))
(pass-if-exception "improper argument list of length 2"
exception:wrong-num-args
(eval '(let ((foo (lambda (x y) #t)))
(foo 1 . 2))
(interaction-environment))))
(with-test-prefix "missing or extra expression"
;; R5RS says:
;; *Note:* In many dialects of Lisp, the empty combination, (),
;; is a legitimate expression. In Scheme, combinations must
;; have at least one subexpression, so () is not a syntactically
;; valid expression.
;; Fixed on 2001-3-3
(pass-if-exception "empty parentheses \"()\""
exception:missing/extra-expr
(eval '()
(interaction-environment)))))
(with-test-prefix "quote"
#t)
(with-test-prefix "quasiquote"
(with-test-prefix "unquote"
(pass-if "repeated execution"
(let ((foo (let ((i 0)) (lambda () (set! i (+ i 1)) `(,i)))))
(and (equal? (foo) '(1)) (equal? (foo) '(2))))))
(with-test-prefix "unquote-splicing"
(pass-if-exception "extra arguments"
exception:missing/extra-expr
(quasiquote ((unquote-splicing (list 1 2) (list 3 4)))))))
(with-test-prefix "begin"
(pass-if "legal (begin)"
(begin)
#t)
(expect-fail-exception "illegal (begin)"
exception:bad-body
(if #t (begin))
#t))
(with-test-prefix "lambda"
(with-test-prefix "bad formals"
(pass-if-exception "(lambda)"
exception:bad-formals
(eval '(lambda)
(interaction-environment)))
(pass-if-exception "(lambda . \"foo\")"
exception:bad-formals
(eval '(lambda . "foo")
(interaction-environment)))
(pass-if-exception "(lambda \"foo\")"
exception:bad-formals
(eval '(lambda "foo")
(interaction-environment)))
(pass-if-exception "(lambda \"foo\" #f)"
exception:bad-formals
(eval '(lambda "foo" #f)
(interaction-environment)))
(pass-if-exception "(lambda (x 1) 2)"
exception:bad-formals
(eval '(lambda (x 1) 2)
(interaction-environment)))
(pass-if-exception "(lambda (1 x) 2)"
exception:bad-formals
(eval '(lambda (1 x) 2)
(interaction-environment)))
(pass-if-exception "(lambda (x \"a\") 2)"
exception:bad-formals
(eval '(lambda (x "a") 2)
(interaction-environment)))
(pass-if-exception "(lambda (\"a\" x) 2)"
exception:bad-formals
(eval '(lambda ("a" x) 2)
(interaction-environment))))
(with-test-prefix "duplicate formals"
;; Fixed on 2001-3-3
(pass-if-exception "(lambda (x x) 1)"
exception:duplicate-formals
(eval '(lambda (x x) 1)
(interaction-environment)))
;; Fixed on 2001-3-3
(pass-if-exception "(lambda (x x x) 1)"
exception:duplicate-formals
(eval '(lambda (x x x) 1)
(interaction-environment))))
(with-test-prefix "bad body"
(pass-if-exception "(lambda ())"
exception:bad-body
(eval '(lambda ())
(interaction-environment)))))
(with-test-prefix "let"
(with-test-prefix "bindings"
(pass-if-exception "late binding"
exception:unbound-var
(let ((x 1) (y x)) y)))
(with-test-prefix "bad bindings"
(pass-if-exception "(let)"
exception:bad-bindings
(eval '(let)
(interaction-environment)))
(pass-if-exception "(let 1)"
exception:bad-bindings
(eval '(let 1)
(interaction-environment)))
(pass-if-exception "(let (x))"
exception:bad-bindings
(eval '(let (x))
(interaction-environment)))
;; FIXME: Wouldn't one rather expect a 'bad bindings' error?
;; (Even although the body is bad as well...)
(pass-if-exception "(let ((x)))"
exception:bad-body
(eval '(let ((x)))
(interaction-environment)))
(pass-if-exception "(let (x) 1)"
exception:bad-bindings
(eval '(let (x) 1)
(interaction-environment)))
(pass-if-exception "(let ((x)) 3)"
exception:bad-bindings
(eval '(let ((x)) 3)
(interaction-environment)))
(pass-if-exception "(let ((x 1) y) x)"
exception:bad-bindings
(eval '(let ((x 1) y) x)
(interaction-environment)))
(pass-if-exception "(let ((1 2)) 3)"
exception:bad-var
(eval '(let ((1 2)) 3)
(interaction-environment))))
(with-test-prefix "duplicate bindings"
(pass-if-exception "(let ((x 1) (x 2)) x)"
exception:duplicate-bindings
(eval '(let ((x 1) (x 2)) x)
(interaction-environment))))
(with-test-prefix "bad body"
(pass-if-exception "(let ())"
exception:bad-body
(eval '(let ())
(interaction-environment)))
(pass-if-exception "(let ((x 1)))"
exception:bad-body
(eval '(let ((x 1)))
(interaction-environment)))))
(with-test-prefix "named let"
(with-test-prefix "initializers"
(pass-if "evaluated in outer environment"
(let ((f -))
(eqv? (let f ((n (f 1))) n) -1))))
(with-test-prefix "bad bindings"
(pass-if-exception "(let x (y))"
exception:bad-bindings
(eval '(let x (y))
(interaction-environment))))
(with-test-prefix "bad body"
(pass-if-exception "(let x ())"
exception:bad-body
(eval '(let x ())
(interaction-environment)))
(pass-if-exception "(let x ((y 1)))"
exception:bad-body
(eval '(let x ((y 1)))
(interaction-environment)))))
(with-test-prefix "let*"
(with-test-prefix "bindings"
(pass-if "(let* ((x 1) (x 2)) ...)"
(let* ((x 1) (x 2))
(= x 2)))
(pass-if "(let* ((x 1) (x x)) ...)"
(let* ((x 1) (x x))
(= x 1))))
(with-test-prefix "bad bindings"
(pass-if-exception "(let*)"
exception:bad-bindings
(eval '(let*)
(interaction-environment)))
(pass-if-exception "(let* 1)"
exception:bad-bindings
(eval '(let* 1)
(interaction-environment)))
(pass-if-exception "(let* (x))"
exception:bad-bindings
(eval '(let* (x))
(interaction-environment)))
(pass-if-exception "(let* (x) 1)"
exception:bad-bindings
(eval '(let* (x) 1)
(interaction-environment)))
(pass-if-exception "(let* ((x)) 3)"
exception:bad-bindings
(eval '(let* ((x)) 3)
(interaction-environment)))
(pass-if-exception "(let* ((x 1) y) x)"
exception:bad-bindings
(eval '(let* ((x 1) y) x)
(interaction-environment)))
(pass-if-exception "(let* x ())"
exception:bad-bindings
(eval '(let* x ())
(interaction-environment)))
(pass-if-exception "(let* x (y))"
exception:bad-bindings
(eval '(let* x (y))
(interaction-environment)))
(pass-if-exception "(let* ((1 2)) 3)"
exception:bad-var
(eval '(let* ((1 2)) 3)
(interaction-environment))))
(with-test-prefix "bad body"
(pass-if-exception "(let* ())"
exception:bad-body
(eval '(let* ())
(interaction-environment)))
(pass-if-exception "(let* ((x 1)))"
exception:bad-body
(eval '(let* ((x 1)))
(interaction-environment)))))
(with-test-prefix "letrec"
(with-test-prefix "bindings"
(pass-if-exception "initial bindings are undefined"
exception:unbound-var
(let ((x 1))
(letrec ((x 1) (y x)) y))))
(with-test-prefix "bad bindings"
(pass-if-exception "(letrec)"
exception:bad-bindings
(eval '(letrec)
(interaction-environment)))
(pass-if-exception "(letrec 1)"
exception:bad-bindings
(eval '(letrec 1)
(interaction-environment)))
(pass-if-exception "(letrec (x))"
exception:bad-bindings
(eval '(letrec (x))
(interaction-environment)))
(pass-if-exception "(letrec (x) 1)"
exception:bad-bindings
(eval '(letrec (x) 1)
(interaction-environment)))
(pass-if-exception "(letrec ((x)) 3)"
exception:bad-bindings
(eval '(letrec ((x)) 3)
(interaction-environment)))
(pass-if-exception "(letrec ((x 1) y) x)"
exception:bad-bindings
(eval '(letrec ((x 1) y) x)
(interaction-environment)))
(pass-if-exception "(letrec x ())"
exception:bad-bindings
(eval '(letrec x ())
(interaction-environment)))
(pass-if-exception "(letrec x (y))"
exception:bad-bindings
(eval '(letrec x (y))
(interaction-environment)))
(pass-if-exception "(letrec ((1 2)) 3)"
exception:bad-var
(eval '(letrec ((1 2)) 3)
(interaction-environment))))
(with-test-prefix "duplicate bindings"
(pass-if-exception "(letrec ((x 1) (x 2)) x)"
exception:duplicate-bindings
(eval '(letrec ((x 1) (x 2)) x)
(interaction-environment))))
(with-test-prefix "bad body"
(pass-if-exception "(letrec ())"
exception:bad-body
(eval '(letrec ())
(interaction-environment)))
(pass-if-exception "(letrec ((x 1)))"
exception:bad-body
(eval '(letrec ((x 1)))
(interaction-environment)))))
(with-test-prefix "if"
(with-test-prefix "missing or extra expressions"
(pass-if-exception "(if)"
exception:missing/extra-expr
(eval '(if)
(interaction-environment)))
(pass-if-exception "(if 1 2 3 4)"
exception:missing/extra-expr
(eval '(if 1 2 3 4)
(interaction-environment)))))
(with-test-prefix "cond"
(with-test-prefix "bad or missing clauses"
(pass-if-exception "(cond)"
exception:missing-clauses
(eval '(cond)
(interaction-environment)))
(pass-if-exception "(cond #t)"
exception:bad-cond-clause
(eval '(cond #t)
(interaction-environment)))
(pass-if-exception "(cond 1)"
exception:bad-cond-clause
(eval '(cond 1)
(interaction-environment)))
(pass-if-exception "(cond 1 2)"
exception:bad-cond-clause
(eval '(cond 1 2)
(interaction-environment)))
(pass-if-exception "(cond 1 2 3)"
exception:bad-cond-clause
(eval '(cond 1 2 3)
(interaction-environment)))
(pass-if-exception "(cond 1 2 3 4)"
exception:bad-cond-clause
(eval '(cond 1 2 3 4)
(interaction-environment)))
(pass-if-exception "(cond ())"
exception:bad-cond-clause
(eval '(cond ())
(interaction-environment)))
(pass-if-exception "(cond () 1)"
exception:bad-cond-clause
(eval '(cond () 1)
(interaction-environment)))
(pass-if-exception "(cond (1) 1)"
exception:bad-cond-clause
(eval '(cond (1) 1)
(interaction-environment)))))
(with-test-prefix "cond =>"
(with-test-prefix "cond is hygienic"
(pass-if "bound 'else is handled correctly"
(eq? (let ((else 'ok)) (cond (else))) 'ok))
(pass-if "bound '=> is handled correctly"
(eq? (let ((=> #f)) (cond (#t => 'ok))) 'ok)))
(with-test-prefix "else is handled correctly"
(pass-if "else =>"
(let ((=> 'foo))
(eq? (cond (else =>)) 'foo)))
(pass-if "else => identity"
(let* ((=> 'foo))
(eq? (cond (else => identity)) identity))))
(with-test-prefix "wrong number of arguments"
(pass-if-exception "=> (lambda (x y) #t)"
exception:wrong-num-args
(cond (1 => (lambda (x y) #t))))))
(with-test-prefix "case"
(pass-if "clause with empty labels list"
(case 1 (() #f) (else #t)))
(with-test-prefix "case is hygienic"
(pass-if-exception "bound 'else is handled correctly"
exception:bad-case-labels
(eval '(let ((else #f)) (case 1 (else #f)))
(interaction-environment))))
(with-test-prefix "bad or missing clauses"
(pass-if-exception "(case)"
exception:missing-clauses
(eval '(case)
(interaction-environment)))
(pass-if-exception "(case . \"foo\")"
exception:bad-expression
(eval '(case . "foo")
(interaction-environment)))
(pass-if-exception "(case 1)"
exception:missing-clauses
(eval '(case 1)
(interaction-environment)))
(pass-if-exception "(case 1 . \"foo\")"
exception:bad-expression
(eval '(case 1 . "foo")
(interaction-environment)))
(pass-if-exception "(case 1 \"foo\")"
exception:bad-case-clause
(eval '(case 1 "foo")
(interaction-environment)))
(pass-if-exception "(case 1 ())"
exception:bad-case-clause
(eval '(case 1 ())
(interaction-environment)))
(pass-if-exception "(case 1 (\"foo\"))"
exception:bad-case-clause
(eval '(case 1 ("foo"))
(interaction-environment)))
(pass-if-exception "(case 1 (\"foo\" \"bar\"))"
exception:bad-case-labels
(eval '(case 1 ("foo" "bar"))
(interaction-environment)))
(pass-if-exception "(case 1 ((2) \"bar\") . \"foo\")"
exception:bad-expression
(eval '(case 1 ((2) "bar") . "foo")
(interaction-environment)))
(pass-if-exception "(case 1 ((2) \"bar\") (else))"
exception:bad-case-clause
(eval '(case 1 ((2) "bar") (else))
(interaction-environment)))
(pass-if-exception "(case 1 (else #f) . \"foo\")"
exception:bad-expression
(eval '(case 1 (else #f) . "foo")
(interaction-environment)))
(pass-if-exception "(case 1 (else #f) ((1) #t))"
exception:misplaced-else-clause
(eval '(case 1 (else #f) ((1) #t))
(interaction-environment)))))
(with-test-prefix "define"
(with-test-prefix "currying"
(pass-if "(define ((foo)) #f)"
(define ((foo)) #t)
((foo))))
(with-test-prefix "missing or extra expressions"
(pass-if-exception "(define)"
exception:missing-expr
(eval '(define)
(interaction-environment)))))
(with-test-prefix "set!"
(with-test-prefix "missing or extra expressions"
(pass-if-exception "(set!)"
exception:missing/extra-expr
(eval '(set!)
(interaction-environment)))
(pass-if-exception "(set! 1)"
exception:missing/extra-expr
(eval '(set! 1)
(interaction-environment)))
(pass-if-exception "(set! 1 2 3)"
exception:missing/extra-expr
(eval '(set! 1 2 3)
(interaction-environment))))
(with-test-prefix "bad variable"
(pass-if-exception "(set! \"\" #t)"
exception:bad-var
(eval '(set! "" #t)
(interaction-environment)))
(pass-if-exception "(set! 1 #t)"
exception:bad-var
(eval '(set! 1 #t)
(interaction-environment)))
(pass-if-exception "(set! #t #f)"
exception:bad-var
(eval '(set! #t #f)
(interaction-environment)))
(pass-if-exception "(set! #f #t)"
exception:bad-var
(eval '(set! #f #t)
(interaction-environment)))
(pass-if-exception "(set! #\space #f)"
exception:bad-var
(eval '(set! #\space #f)
(interaction-environment)))))
(with-test-prefix "quote"
(with-test-prefix "missing or extra expression"
(pass-if-exception "(quote)"
exception:missing/extra-expr
(eval '(quote)
(interaction-environment)))
(pass-if-exception "(quote a b)"
exception:missing/extra-expr
(eval '(quote a b)
(interaction-environment)))))
(with-test-prefix "while"
(define (unreachable)
(error "unreachable code has been reached!"))
;; Return a new procedure COND which when called (COND) will return #t the
;; first N times, then #f, then any further call is an error. N=0 is
;; allowed, in which case #f is returned by the first call.
(define (make-iterations-cond n)
(lambda ()
(cond ((not n)
(error "oops, condition re-tested after giving false"))
((= 0 n)
(set! n #f)
#f)
(else
(set! n (1- n))
#t))))
(pass-if-exception "too few args" exception:wrong-num-args
(eval '(while) (interaction-environment)))
(with-test-prefix "empty body"
(do ((n 0 (1+ n)))
((> n 5))
(pass-if n
(let ((cond (make-iterations-cond n)))
(while (cond)))
#t)))
(pass-if "initially false"
(while #f
(unreachable))
#t)
(with-test-prefix "in empty environment"
;; an environment with no bindings at all
(define empty-environment
(make-module 1))
(pass-if "empty body"
(eval `(,while #f)
empty-environment)
#t)
(pass-if "initially false"
(eval `(,while #f
#f)
empty-environment)
#t)
(pass-if "iterating"
(let ((cond (make-iterations-cond 3)))
(eval `(,while (,cond)
123 456)
empty-environment))
#t))
(with-test-prefix "iterations"
(do ((n 0 (1+ n)))
((> n 5))
(pass-if n
(let ((cond (make-iterations-cond n))
(i 0))
(while (cond)
(set! i (1+ i)))
(= i n)))))
(with-test-prefix "break"
(pass-if-exception "too many args" exception:wrong-num-args
(while #t
(break 1)))
(with-test-prefix "from cond"
(pass-if "first"
(while (begin
(break)
(unreachable))
(unreachable))
#t)
(do ((n 0 (1+ n)))
((> n 5))
(pass-if n
(let ((cond (make-iterations-cond n))
(i 0))
(while (if (cond)
#t
(begin
(break)
(unreachable)))
(set! i (1+ i)))
(= i n)))))
(with-test-prefix "from body"
(pass-if "first"
(while #t
(break)
(unreachable))
#t)
(do ((n 0 (1+ n)))
((> n 5))
(pass-if n
(let ((cond (make-iterations-cond n))
(i 0))
(while #t
(if (not (cond))
(begin
(break)
(unreachable)))
(set! i (1+ i)))
(= i n)))))
(pass-if "from nested"
(while #t
(let ((outer-break break))
(while #t
(outer-break)
(unreachable)))
(unreachable))
#t)
(pass-if "from recursive"
(let ((outer-break #f))
(define (r n)
(while #t
(if (eq? n 'outer)
(begin
(set! outer-break break)
(r 'inner))
(begin
(outer-break)
(unreachable))))
(if (eq? n 'inner)
(error "broke only from inner loop")))
(r 'outer))
#t))
(with-test-prefix "continue"
(pass-if-exception "too many args" exception:wrong-num-args
(while #t
(continue 1)))
(with-test-prefix "from cond"
(do ((n 0 (1+ n)))
((> n 5))
(pass-if n
(let ((cond (make-iterations-cond n))
(i 0))
(while (if (cond)
(begin
(set! i (1+ i))
(continue)
(unreachable))
#f)
(unreachable))
(= i n)))))
(with-test-prefix "from body"
(do ((n 0 (1+ n)))
((> n 5))
(pass-if n
(let ((cond (make-iterations-cond n))
(i 0))
(while (cond)
(set! i (1+ i))
(continue)
(unreachable))
(= i n)))))
(pass-if "from nested"
(let ((cond (make-iterations-cond 3)))
(while (cond)
(let ((outer-continue continue))
(while #t
(outer-continue)
(unreachable)))))
#t)
(pass-if "from recursive"
(let ((outer-continue #f))
(define (r n)
(let ((cond (make-iterations-cond 3))
(first #t))
(while (begin
(if (and (not first)
(eq? n 'inner))
(error "continued only to inner loop"))
(cond))
(set! first #f)
(if (eq? n 'outer)
(begin
(set! outer-continue continue)
(r 'inner))
(begin
(outer-continue)
(unreachable))))))
(r 'outer))
#t)))