better error checking for formal argument lists
some cosmetic error improvements adding more tests
This commit is contained in:
		
							parent
							
								
									15c8cb327d
								
							
						
					
					
						commit
						c6a977063e
					
				| 
						 | 
					@ -348,9 +348,6 @@
 | 
				
			||||||
	     " argument."
 | 
						     " argument."
 | 
				
			||||||
	     " arguments.")))
 | 
						     " arguments.")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define (compile-app g env tail? x)
 | 
					 | 
				
			||||||
  (compile-call g env tail? x))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
(define builtin->instruction
 | 
					(define builtin->instruction
 | 
				
			||||||
  (let ((b2i (table number? 'number?  cons 'cons
 | 
					  (let ((b2i (table number? 'number?  cons 'cons
 | 
				
			||||||
		    fixnum? 'fixnum?  equal? 'equal?
 | 
							    fixnum? 'fixnum?  equal? 'equal?
 | 
				
			||||||
| 
						 | 
					@ -395,7 +392,7 @@
 | 
				
			||||||
		    (emit g (if tail? 'tapply 'apply) nargs)))
 | 
							    (emit g (if tail? 'tapply 'apply) nargs)))
 | 
				
			||||||
      (else      (emit g b)))))
 | 
					      (else      (emit g b)))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define (compile-call g env tail? x)
 | 
					(define (compile-app g env tail? x)
 | 
				
			||||||
  (let ((head  (car x)))
 | 
					  (let ((head  (car x)))
 | 
				
			||||||
    (let ((head
 | 
					    (let ((head
 | 
				
			||||||
	   (if (and (symbol? head)
 | 
						   (if (and (symbol? head)
 | 
				
			||||||
| 
						 | 
					@ -502,28 +499,33 @@
 | 
				
			||||||
      k))
 | 
					      k))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(define (lambda-vars l)
 | 
					(define (lambda-vars l)
 | 
				
			||||||
  (define (check-formals l o)
 | 
					  (define (check-formals l o opt kw)
 | 
				
			||||||
    (or
 | 
					    (cond ((or (null? l) (symbol? l)) #t)
 | 
				
			||||||
     (null? l) (symbol? l)
 | 
						  ((and (pair? l) (symbol? (car l)))
 | 
				
			||||||
     (and
 | 
						   (if (or opt kw)
 | 
				
			||||||
      (pair? l)
 | 
					 | 
				
			||||||
      (or (symbol? (car l))
 | 
					 | 
				
			||||||
	  (and (pair? (car l))
 | 
					 | 
				
			||||||
	       (or (every pair? (cdr l))
 | 
					 | 
				
			||||||
	       (error "compile error: invalid argument list "
 | 
						       (error "compile error: invalid argument list "
 | 
				
			||||||
			  o ". optional arguments must come after required."))
 | 
							      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))
 | 
						   (if (keyword? (caar l))
 | 
				
			||||||
		   (or (every keyword-arg? (cdr l))
 | 
						       (check-formals (cdr l) o opt #t)
 | 
				
			||||||
 | 
						       (if kw
 | 
				
			||||||
		   (error "compile error: invalid argument list "
 | 
							   (error "compile error: invalid argument list "
 | 
				
			||||||
			      o ". keyword arguments must come last."))
 | 
								  o ". keyword arguments must come last.")
 | 
				
			||||||
		   #t))
 | 
							   (check-formals (cdr l) o #t kw))))
 | 
				
			||||||
 | 
						  ((pair? l)
 | 
				
			||||||
	   (error "compile error: invalid formal argument " (car l)
 | 
						   (error "compile error: invalid formal argument " (car l)
 | 
				
			||||||
		  " in list " o))
 | 
							  " in list " o))
 | 
				
			||||||
      (check-formals (cdr l) o))
 | 
						  (else
 | 
				
			||||||
	   (if (eq? l o)
 | 
						   (if (eq? l o)
 | 
				
			||||||
	       (error "compile error: invalid argument list " o)
 | 
						       (error "compile error: invalid argument list " o)
 | 
				
			||||||
	 (error "compile error: invalid formal argument " l " in list " o))))
 | 
						       (error "compile error: invalid formal argument " l
 | 
				
			||||||
  (check-formals l l)
 | 
							      " in list " o)))))
 | 
				
			||||||
 | 
					  (check-formals l l #f #f)
 | 
				
			||||||
  (map! (lambda (s) (if (pair? s) (keyword->symbol (car s)) s))
 | 
					  (map! (lambda (s) (if (pair? s) (keyword->symbol (car s)) s))
 | 
				
			||||||
	(to-proper l)))
 | 
						(to-proper l)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| 
						 | 
					@ -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)
 | 
					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 --------------------------------------------------------
 | 
					// safe cast operators --------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -755,14 +755,19 @@
 | 
				
			||||||
  (cond ((and (pair? e)
 | 
					  (cond ((and (pair? e)
 | 
				
			||||||
	      (eq? (car e) 'type-error)
 | 
						      (eq? (car e) 'type-error)
 | 
				
			||||||
	      (length= e 4))
 | 
						      (length= e 4))
 | 
				
			||||||
	 (eprinc "type-error: " (cadr e) ": expected " (caddr e) ", got ")
 | 
						 (eprinc "type error: " (cadr e) ": expected " (caddr e) ", got ")
 | 
				
			||||||
	 (eprint (cadddr e)))
 | 
						 (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)
 | 
						((and (pair? e)
 | 
				
			||||||
	      (eq? (car e) 'unbound-error)
 | 
						      (eq? (car e) 'unbound-error)
 | 
				
			||||||
	      (pair? (cdr e)))
 | 
						      (pair? (cdr e)))
 | 
				
			||||||
	 (eprinc "unbound-error: eval: variable " (cadr e)
 | 
						 (eprinc "eval: variable " (cadr e) " has no value"))
 | 
				
			||||||
		 " has no value"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	((and (pair? e)
 | 
						((and (pair? e)
 | 
				
			||||||
	      (eq? (car e) 'error))
 | 
						      (eq? (car e) 'error))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1150,3 +1150,22 @@ brbound 2 L2
 | 
				
			||||||
loada 1
 | 
					loada 1
 | 
				
			||||||
seta 2
 | 
					seta 2
 | 
				
			||||||
L2:
 | 
					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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,9 @@
 | 
				
			||||||
; -*- scheme -*-
 | 
					; -*- 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)
 | 
					(define (every-int n)
 | 
				
			||||||
  (list (fixnum n) (int8 n) (uint8 n) (int16 n) (uint16 n) (int32 n) (uint32 n)
 | 
					  (list (fixnum n) (int8 n) (uint8 n) (int16 n) (uint16 n) (int32 n) (uint32 n)
 | 
				
			||||||
        (int64 n) (uint64 n)))
 | 
					        (int64 n) (uint64 n)))
 | 
				
			||||||
| 
						 | 
					@ -95,8 +100,20 @@
 | 
				
			||||||
; this crashed once
 | 
					; this crashed once
 | 
				
			||||||
(for 1 10 (lambda (i) 0))
 | 
					(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
 | 
					; long argument lists
 | 
				
			||||||
(assert (= (apply + (iota 100000)) 4999950000))
 | 
					(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)
 | 
					(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 1))) `(,MAX_ARGS)))
 | 
				
			||||||
(assert (equal? (apply f (iota (+ MAX_ARGS 2))) `(,MAX_ARGS ,(+ MAX_ARGS 1))))
 | 
					(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 as (map-int (lambda (x) (gensym)) 1000))
 | 
				
			||||||
(define f (compile `(lambda ,as ,(car (last-pair as)))))
 | 
					(define f (compile `(lambda ,as ,(car (last-pair as)))))
 | 
				
			||||||
(assert (equal? (apply f (iota 1000)) 999))
 | 
					(assert (equal? (apply f (iota 1000)) 999))
 | 
				
			||||||
| 
						 | 
					@ -136,6 +161,15 @@
 | 
				
			||||||
(assert (equal? (keys4 b: 10) '(8 10 7 6)))
 | 
					(assert (equal? (keys4 b: 10) '(8 10 7 6)))
 | 
				
			||||||
(assert (equal? (keys4 c: 10) '(8 3 10 6)))
 | 
					(assert (equal? (keys4 c: 10) '(8 3 10 6)))
 | 
				
			||||||
(assert (equal? (keys4 d: 10) '(8 3 7 10)))
 | 
					(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
 | 
					; ok, a couple end-to-end tests as well
 | 
				
			||||||
(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
 | 
					(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue