better error checking for formal argument lists

some cosmetic error improvements
adding more tests
This commit is contained in:
JeffBezanson 2009-08-03 05:00:44 +00:00
parent 15c8cb327d
commit c6a977063e
6 changed files with 90 additions and 30 deletions

View File

@ -348,9 +348,6 @@
" argument."
" arguments.")))
(define (compile-app g env tail? x)
(compile-call g env tail? x))
(define builtin->instruction
(let ((b2i (table number? 'number? cons 'cons
fixnum? 'fixnum? equal? 'equal?
@ -395,7 +392,7 @@
(emit g (if tail? 'tapply 'apply) nargs)))
(else (emit g b)))))
(define (compile-call g env tail? x)
(define (compile-app g env tail? x)
(let ((head (car x)))
(let ((head
(if (and (symbol? head)
@ -502,28 +499,33 @@
k))
(define (lambda-vars l)
(define (check-formals l o)
(or
(null? l) (symbol? l)
(and
(pair? l)
(or (symbol? (car l))
(and (pair? (car l))
(or (every pair? (cdr l))
(define (check-formals l o opt kw)
(cond ((or (null? l) (symbol? l)) #t)
((and (pair? l) (symbol? (car l)))
(if (or opt kw)
(error "compile error: invalid argument list "
o ". optional arguments must come after required.")
(check-formals (cdr l) o opt kw)))
((and (pair? l) (pair? (car l)))
(unless (and (length= (car l) 2)
(symbol? (caar l)))
(error "compile error: invalid optional argument " (car l)
" in list " o))
(if (keyword? (caar l))
(check-formals (cdr l) o opt #t)
(if kw
(error "compile error: invalid argument list "
o ". optional arguments must come after required."))
(if (keyword? (caar l))
(or (every keyword-arg? (cdr l))
(error "compile error: invalid argument list "
o ". keyword arguments must come last."))
#t))
(error "compile error: invalid formal argument " (car l)
" in list " o))
(check-formals (cdr l) o))
(if (eq? l o)
(error "compile error: invalid argument list " o)
(error "compile error: invalid formal argument " l " in list " o))))
(check-formals l l)
o ". keyword arguments must come last.")
(check-formals (cdr l) o #t kw))))
((pair? l)
(error "compile error: invalid formal argument " (car l)
" in list " o))
(else
(if (eq? l o)
(error "compile error: invalid argument list " o)
(error "compile error: invalid formal argument " l
" in list " o)))))
(check-formals l l #f #f)
(map! (lambda (s) (if (pair? s) (keyword->symbol (car s)) s))
(to-proper l)))

File diff suppressed because one or more lines are too long

View File

@ -202,7 +202,7 @@ void type_error(char *fname, char *expected, value_t got)
void bounds_error(char *fname, value_t arr, value_t ind)
{
lerrorf(listn(3, BoundsError, arr, ind), "%s: index out of bounds", fname);
raise(listn(4, BoundsError, symbol(fname), arr, ind));
}
// safe cast operators --------------------------------------------------------

View File

@ -755,14 +755,19 @@
(cond ((and (pair? e)
(eq? (car e) 'type-error)
(length= e 4))
(eprinc "type-error: " (cadr e) ": expected " (caddr e) ", got ")
(eprinc "type error: " (cadr e) ": expected " (caddr e) ", got ")
(eprint (cadddr e)))
((and (pair? e)
(eq? (car e) 'bounds-error)
(length= e 4))
(eprinc (cadr e) ": index " (cadddr e) " out of bounds for ")
(eprint (caddr e)))
((and (pair? e)
(eq? (car e) 'unbound-error)
(pair? (cdr e)))
(eprinc "unbound-error: eval: variable " (cadr e)
" has no value"))
(eprinc "eval: variable " (cadr e) " has no value"))
((and (pair? e)
(eq? (car e) 'error))

View File

@ -1150,3 +1150,22 @@ brbound 2 L2
loada 1
seta 2
L2:
-----------------------------------------------------------------------------
what needs more test coverage:
- more error cases, lerrorf() cases
- printing gensyms
- gensyms with bindings
- listn(), isnumber(), list*, boolean?, function?, add2+ovf, >2arg add,div
- large functions, requiring long versions of branch opcodes
- setal, loadvl, (long arglist and lots of vals cases)
- aref/aset on c array
- printing everything
- reading floats, escaped symbols, multiline comment, octal chars in strs
- equal? on functions
- all cvalue ctors, string_from_cstrn()
- typeof, copy, podp, builtin()
- bitwise and logical ops
- making a closure in a default value expression for an optional arg

View File

@ -1,4 +1,9 @@
; -*- scheme -*-
(define-macro (assert-fail expr . what)
`(assert (trycatch (begin ,expr #f)
(lambda (e) ,(if (null? what) #t
`(eq? (car e) ',(car what)))))))
(define (every-int n)
(list (fixnum n) (int8 n) (uint8 n) (int16 n) (uint16 n) (int32 n) (uint32 n)
(int64 n) (uint64 n)))
@ -95,8 +100,20 @@
; this crashed once
(for 1 10 (lambda (i) 0))
; failing applications
(assert-fail ((lambda (x) x) 1 2))
(assert-fail ((lambda (x) x)))
(assert-fail ((lambda (x y . z) z) 1))
(assert-fail (car 'x) type-error)
(assert-fail gjegherqpfdf___trejif unbound-error)
; long argument lists
(assert (= (apply + (iota 100000)) 4999950000))
(define ones (map (lambda (x) 1) (iota 80000)))
(assert (= (eval `(if (< 2 1)
(+ ,@ones)
(+ ,@(cdr ones))))
79999))
(define MAX_ARGS 255)
@ -106,6 +123,14 @@
(assert (equal? (apply f (iota (+ MAX_ARGS 1))) `(,MAX_ARGS)))
(assert (equal? (apply f (iota (+ MAX_ARGS 2))) `(,MAX_ARGS ,(+ MAX_ARGS 1))))
(define as (apply list* (map-int (lambda (x) (gensym)) (+ MAX_ARGS 100))))
(define ff (compile `(lambda ,as (set! ,(car (last-pair as)) 42)
,(car (last-pair as)))))
(assert (equal? (apply ff (iota (+ MAX_ARGS 100))) 42))
(define ff (compile `(lambda ,as (set! ,(car (last-pair as)) 42)
(lambda () ,(car (last-pair as))))))
(assert (equal? ((apply ff (iota (+ MAX_ARGS 100)))) 42))
(define as (map-int (lambda (x) (gensym)) 1000))
(define f (compile `(lambda ,as ,(car (last-pair as)))))
(assert (equal? (apply f (iota 1000)) 999))
@ -136,6 +161,15 @@
(assert (equal? (keys4 b: 10) '(8 10 7 6)))
(assert (equal? (keys4 c: 10) '(8 3 10 6)))
(assert (equal? (keys4 d: 10) '(8 3 7 10)))
(assert-fail (keys4 e: 10)) ; unsupported keyword
(assert-fail (keys4 a: 1 b:)) ; keyword with no argument
; cvalues and arrays
(assert (equal? (typeof "") '(array byte)))
(assert-fail (aref #(1) 3) bounds-error)
(define iarr (array 'int64 32 16 8 7 1))
(assert (equal? (aref iarr 0) 32))
(assert (equal? (aref iarr #int8(3)) 7))
; ok, a couple end-to-end tests as well
(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))