Some type checking
authorDavid Vazquez <davazp@gmail.com>
Fri, 4 Jan 2013 02:05:45 +0000 (02:05 +0000)
committerDavid Vazquez <davazp@gmail.com>
Fri, 4 Jan 2013 02:05:45 +0000 (02:05 +0000)
lispstrack.lisp

index 96a38ee..e7f27e2 100644 (file)
    (%compile-defmacro 'defmacro
                       '(lambda (name args &rest body)
                         `(eval-when-compile
-                           (%compile-defmacro ',name '(lambda ,args ,@body))))))
+                           (%compile-defmacro ',name
+                                              '(lambda ,(mapcar (lambda (x)
+                                                                  (if (eq x '&body)
+                                                                      '&rest
+                                                                      x))
+                                                                args)
+                                                ,@body))))))
 
  (defmacro %defvar (name value)
    `(progn
   (defun char-code (x) x)
   (defun char= (x y) (= x y))
 
-  (defun <= (x y) (or (< x y) (= x y)))
-  (defun >= (x y) (not (< x y)))
-
   (defun integerp (x)
     (and (numberp x) (= (floor x) x)))
 
   (defun setcdr (cons new)
     (setf (cdr cons) new)))
 
-
 ;;; At this point, no matter if Common Lisp or lispstrack is compiling
 ;;; from here, this code will compile on both. We define some helper
 ;;; functions now for string manipulation and so on. They will be
        (join (mapcar (lambda (d) (string (char "0123456789" d)))
                      digits))))))
 
+
 #+lispstrack
 (defun print-to-string (form)
   (cond
                                     (join (reverse cases))))
                            "}" *newline*)
                    "")
-               ;; &rest argument
+               ;; &rest/&body argument
                (if rest-argument
                    (let ((js!rest (lookup-variable-translation rest-argument new-env)))
                      (concat "var " js!rest "= " (ls-compile nil env fenv) ";" *newline*
 (defun compile-bool (x)
   (concat "(" x "?" (ls-compile t nil nil) ": " (ls-compile nil nil nil) ")"))
 
-(define-builtin + (x y) (concat "((" x ") + (" y "))"))
-(define-builtin - (x y) (concat "((" x ") - (" y "))"))
-(define-builtin * (x y) (concat "((" x ") * (" y "))"))
-(define-builtin / (x y) (concat "((" x ") / (" y "))"))
-
-(define-builtin mod (x y) (concat "((" x ") % (" y "))"))
-
-(define-builtin < (x y) (compile-bool (concat "((" x ") < (" y "))")))
-(define-builtin = (x y) (compile-bool (concat "((" x ") == (" y "))")))
-
-(define-builtin numberp (x) (compile-bool (concat "(typeof (" x ") == \"number\")")))
-
-(define-builtin floor (x) (concat "(Math.floor(" x "))"))
+;;; DECLS is a list of (JSVARNAME TYPE LISPFORM) declarations.
+(defmacro type-check (decls &body body)
+  `(concat "(function(){" *newline*
+           (indent ,@(mapcar (lambda (decl)
+                               `(concat "var " ,(first decl) " = " ,(third decl) ";" *newline*))
+                             decls)
+
+                   ,@(mapcar (lambda (decl)
+                               `(concat "if (typeof " ,(first decl) " != '" ,(second decl) "')" *newline*
+                                        (indent "throw 'The value ' + "
+                                                ,(first decl)
+                                                " + ' is not a type "
+                                                ,(second decl)
+                                                ".';"
+                                                *newline*)))
+                             decls)
+                   ,@body)
+           "})()"))
+
+(defun num-op-num (x op y)
+  (type-check (("x" "number" x) ("y" "number" y))
+    (concat "return x" op "y;" *newline*)))
+
+(define-builtin + (x y) (num-op-num x "+" y))
+(define-builtin - (x y) (num-op-num x "-" y))
+(define-builtin * (x y) (num-op-num x "*" y))
+(define-builtin / (x y) (num-op-num x "/" y))
+
+(define-builtin mod (x y) (num-op-num x "%" y))
+
+(define-builtin < (x y)  (compile-bool (num-op-num x "<" y)))
+(define-builtin > (x y)  (compile-bool (num-op-num x ">" y)))
+(define-builtin = (x y)  (compile-bool (num-op-num x "==" y)))
+(define-builtin <= (x y) (compile-bool (num-op-num x "<=" y)))
+(define-builtin >= (x y) (compile-bool (num-op-num x ">=" y)))
+
+(define-builtin numberp (x)
+  (compile-bool (concat "(typeof (" x ") == \"number\")")))
+
+(define-builtin floor (x)
+  (type-check (("x" "number" x))
+    "return (Math.floor(x));"))
 
 (define-builtin cons (x y) (concat "({car: " x ", cdr: " y "})"))
 (define-builtin consp (x)
                   ": tmp.cdr;" *newline*)
           "})()"))
 
-(define-builtin setcar (x new) (concat "((" x ").car = " new ")"))
-(define-builtin setcdr (x new) (concat "((" x ").cdr = " new ")"))
+(define-builtin setcar (x new)
+  (type-check (("x" "object" x))
+    (concat "return (x.car = " new ");")))
+
+(define-builtin setcdr (x new)
+  (type-check (("x" "object" x))
+    (concat "return (x.cdr = " new ");")))
 
 (define-builtin symbolp (x)
   (compile-bool
            "})()")))
 
 (define-builtin make-symbol (name)
-  (concat "({name: " name "})"))
+  (type-check (("name" "string" name))
+    "return ({name: name});"))
 
 (define-builtin symbol-name (x)
   (concat "(" x ").name"))
 (define-builtin equal (x y) (compile-bool (concat "(" x  " == " y ")")))
 
 (define-builtin string (x)
-  (concat "String.fromCharCode(" x ")"))
+  (type-check (("x" "number" x))
+    "return String.fromCharCode(x);"))
 
 (define-builtin stringp (x)
   (compile-bool (concat "(typeof(" x ") == \"string\")")))
 
 (define-builtin string-upcase (x)
-  (concat "(" x ").toUpperCase()"))
+  (type-check (("x" "string" x))
+    "return x.toUpperCase();"))
 
 (define-builtin string-length (x)
-  (concat "(" x ").length"))
+  (type-check (("x" "string" x))
+    "return x.length;"))
 
 (define-compilation slice (string a &optional b)
   (concat "(function(){" *newline*
 (define-builtin write-string (x)
   (concat "lisp.write(" x ")"))
 
-
 (defun macrop (x)
   (and (symbolp x) (eq (binding-type (lookup-function x *fenv*)) 'macro)))