shithub: femtolisp

Download patch

ref: c6a977063e97d4d1a9b4c07d2e0c7d0ceb02a6c0
parent: 15c8cb327d542607b6faaa90498cdef29a321110
author: JeffBezanson <jeff.bezanson@gmail.com>
date: Mon Aug 3 01:00:44 EDT 2009

better error checking for formal argument lists
some cosmetic error improvements
adding more tests


--- a/femtolisp/compiler.lsp
+++ b/femtolisp/compiler.lsp
@@ -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)))
 
--- a/femtolisp/flisp.c
+++ b/femtolisp/flisp.c
@@ -202,7 +202,7 @@
 
 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 --------------------------------------------------------
--- a/femtolisp/system.lsp
+++ b/femtolisp/system.lsp
@@ -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))
--- a/femtolisp/todo
+++ b/femtolisp/todo
@@ -1150,3 +1150,22 @@
 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
--- a/femtolisp/unittest.lsp
+++ b/femtolisp/unittest.lsp
@@ -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)))))