(defun reverse (list)
(revappend list '()))
+ (defmacro psetq (&rest pairs)
+ (let (;; For each pair, we store here a list of the form
+ ;; (VARIABLE GENSYM VALUE).
+ (assignments '()))
+ (while t
+ (cond
+ ((null pairs) (return))
+ ((null (cdr pairs))
+ (error "Odd paris in PSETQ"))
+ (t
+ (let ((variable (car pairs))
+ (value (cadr pairs)))
+ (push `(,variable ,(gensym) ,value) assignments)
+ (setq pairs (cddr pairs))))))
+ (setq assignments (reverse assignments))
+ ;;
+ `(let ,(mapcar #'cdr assignments)
+ (setq ,@(!reduce #'append (mapcar #'butlast assignments) '())))))
+
(defun list-length (list)
(let ((l 0))
(while (not (null list))
l))
(defun length (seq)
- (if (stringp seq)
- (string-length seq)
- (list-length seq)))
+ (cond
+ ((stringp seq)
+ (string-length seq))
+ ((arrayp seq)
+ (oget seq "length"))
+ ((listp seq)
+ (list-length seq))))
(defun concat-two (s1 s2)
(concat-two s1 s2))
(defun setcar (cons new)
(setf (car cons) new))
(defun setcdr (cons new)
- (setf (cdr cons) new)))
+ (setf (cdr cons) new))
+
+ (defun aset (array idx value)
+ (setf (aref array idx) value)))
;;; At this point, no matter if Common Lisp or ecmalisp is compiling
;;; from here, this code will compile on both. We define some helper
(defun mapconcat (func list)
(join (mapcar func list)))
+(defun vector-to-list (vector)
+ (let ((list nil)
+ (size (length vector)))
+ (dotimes (i size (reverse list))
+ (push (aref vector i) list))))
+
+(defun list-to-vector (list)
+ (let ((v (make-array (length list)))
+ (i 0))
+ (dolist (x list v)
+ (aset v i x)
+ (incf i))))
+
;;; Like CONCAT, but prefix each line with four spaces. Two versions
;;; of this function are available, because the Ecmalisp version is
;;; very slow and bootstraping was annoying.
(prin1-to-string (car last))
(concat (prin1-to-string (car last)) " . " (prin1-to-string (cdr last)))))
")"))
+ ((arrayp form)
+ (concat "#" (prin1-to-string (vector-to-list form))))
((packagep form)
(concat "#<PACKAGE " (package-name form) ">"))))
(ecase (%read-char stream)
(#\'
(list 'function (ls-read stream)))
+ (#\( (list-to-vector (%read-list stream)))
(#\\
(let ((cname
(concat (string (%read-char stream))
(ls-compile-block body t)) *newline*
"})"))))
-(define-compilation setq (var val)
+
+(defun setq-pair (var val)
(let ((b (lookup-in-lexenv var *environment* 'variable)))
(if (eq (binding-type b) 'lexical-variable)
(concat (binding-value b) " = " (ls-compile val))
(ls-compile `(set ',var ,val)))))
+(define-compilation setq (&rest pairs)
+ (let ((result ""))
+ (while t
+ (cond
+ ((null pairs) (return))
+ ((null (cdr pairs))
+ (error "Odd paris in SETQ"))
+ (t
+ (concatf result
+ (concat (setq-pair (car pairs) (cadr pairs))
+ (if (null (cddr pairs)) "" ", ")))
+ (setq pairs (cddr pairs)))))
+ (concat "(" result ")")))
+
;;; FFI Variable accessors
(define-compilation js-vref (var)
var)
c
(let ((v (genlit)))
(toplevel-compilation (concat "var " v " = " c))
- v))))))
+ v))))
+ ((arrayp sexp)
+ (let ((elements (vector-to-list sexp)))
+ (let ((c (concat "[" (join (mapcar #'literal elements) ", ") "]")))
+ (if recursive
+ c
+ (let ((v (genlit)))
+ (toplevel-compilation (concat "var " v " = " c))
+ v)))))))
(define-compilation quote (sexp)
(literal sexp))
(lambda (,args)
(concat "return " ,@body ";" *newline*))))
-
-(define-raw-builtin plus (&rest numbers)
- (variable-arity numbers
- (join numbers "+")))
-
-(define-raw-builtin minus (x &rest others)
- (let ((args (cons x others)))
- (variable-arity args
- (if (null others)
- (concat "-" (car args))
- (join args "+")))))
-
-
(defun num-op-num (x op y)
(type-check (("x" "number" x) ("y" "number" y))
(concat "x" op "y")))
(concat "-" (car args))
(join args "-")))))
+(define-raw-builtin * (&rest numbers)
+ (if (null numbers)
+ "1"
+ (variable-arity numbers
+ (join numbers "*"))))
-(define-builtin * (x y) (num-op-num x "*" y))
-(define-builtin / (x y) (num-op-num x "/" y))
+(define-raw-builtin / (x &rest others)
+ (let ((args (cons x others)))
+ (variable-arity args
+ (if (null others)
+ (concat "1 /" (car args))
+ (join args "/")))))
(define-builtin mod (x y) (num-op-num x "%" y))
+
+(defun comparison-conjuntion (vars op)
+ (cond
+ ((null (cdr vars))
+ "true")
+ ((null (cddr vars))
+ (concat (car vars) op (cadr vars)))
+ (t
+ (concat (car vars) op (cadr vars)
+ " && "
+ (comparison-conjuntion (cdr vars) op)))))
+
(defmacro define-builtin-comparison (op sym)
- `(define-raw-builtin ,op (&rest args)
- (js!bool
- (let ((x (car args))
- (res "true"))
- (dolist (y (cdr args))
- (setq res (concat "("
- (ls-compile x) " " ,sym " " (ls-compile y) ")" " && " res))
- (setq x y))
- res))))
+ `(define-raw-builtin ,op (x &rest args)
+ (let ((args (cons x args)))
+ (variable-arity args
+ (js!bool (comparison-conjuntion args ,sym))))))
(define-builtin-comparison > ">")
(define-builtin-comparison < "<")
(type-check (("x" "string" x))
"lisp.write(x)"))
+(define-builtin make-array (n)
+ (js!selfcall
+ "var r = [];" *newline*
+ "for (var i = 0; i < " n "; i++)" *newline*
+ (indent "r.push(" (ls-compile nil) ");" *newline*)
+ "return r;" *newline*))
+
+(define-builtin arrayp (x)
+ (js!bool
+ (js!selfcall
+ "var x = " x ";" *newline*
+ "return typeof x === 'object' && 'length' in x;")))
+
+(define-builtin aref (array n)
+ (js!selfcall
+ "var x = " "(" array ")[" n "];" *newline*
+ "if (x === undefined) throw 'Out of range';" *newline*
+ "return x;" *newline*))
+
+(define-builtin aset (array n value)
+ (js!selfcall
+ "var x = " array ";" *newline*
+ "var i = " n ";" *newline*
+ "if (i < 0 || i >= x.length) throw 'Out of range';" *newline*
+ "return x[i] = " value ";" *newline*))
+
+
(defun macro (x)
(and (symbolp x)
(let ((b (lookup-in-lexenv x *environment* 'function)))
(ls-compile `(symbol-value ',sexp))))))
((integerp sexp) (integer-to-string sexp))
((stringp sexp) (concat "\"" (escape-string sexp) "\""))
+ ((arrayp sexp) (literal sexp))
((listp sexp)
(let ((name (car sexp))
(args (cdr sexp)))
(t
(if (macro name)
(ls-compile (ls-macroexpand-1 sexp))
- (compile-funcall name args))))))))
+ (compile-funcall name args))))))
+ (t
+ (error "How should I compile this?"))))
(defun ls-compile-toplevel (sexp)
(let ((*toplevel-compilations* nil))
(ls-compile-toplevel x))))
(js-eval code)))
- (export '(&rest &optional &body * *gensym-counter* *package* + - / 1+ 1- < <= =
-= > >= and append apply assoc atom block boundp boundp butlast caar
-cadddr caddr cadr car car case catch cdar cdddr cddr cdr cdr char
-char-code char= code-char cond cons consp copy-list decf declaim
-defparameter defun defvar digit-char-p disassemble documentation
-dolist dotimes ecase eq eql equal error eval every export fdefinition
-find-package find-symbol first fourth fset funcall function functionp
-gensym go identity if in-package incf integerp integerp intern
-keywordp lambda last length let let* list-all-packages list listp
-make-package make-symbol mapcar member minusp mod nil not nth nthcdr
-null numberp or package-name package-use-list packagep plusp
-prin1-to-string print proclaim prog1 prog2 pron push quote remove
-remove-if remove-if-not return return-from revappend reverse second
-set setq some string-upcase string string= stringp subseq
-symbol-function symbol-name symbol-package symbol-plist symbol-value
-symbolp t tagbody third throw truncate unless unwind-protect variable
-warn when write-line write-string zerop
-arithmetic plus minus
-))
+ (export '(&rest &optional &body * *gensym-counter* *package* + - /
+ 1+ 1- < <= = = > >= and append apply aref arrayp aset
+ assoc atom block boundp boundp butlast caar cadddr caddr
+ cadr car car case catch cdar cdddr cddr cdr cdr char
+ char-code char= code-char cond cons consp copy-list decf
+ declaim defparameter defun defvar digit-char-p disassemble
+ documentation dolist dotimes ecase eq eql equal error eval
+ every export fdefinition find-package find-symbol first
+ fourth fset funcall function functionp gensym go identity
+ if in-package incf integerp integerp intern keywordp
+ lambda last length let let* list-all-packages list listp
+ make-array make-package make-symbol mapcar member minusp
+ mod nil not nth nthcdr null numberp or package-name
+ package-use-list packagep plusp prin1-to-string print
+ proclaim prog1 prog2 progn psetq push quote remove remove-if
+ remove-if-not return return-from revappend reverse second
+ set setq some string-upcase string string= stringp subseq
+ symbol-function symbol-name symbol-package symbol-plist
+ symbol-value symbolp t tagbody third throw truncate unless
+ unwind-protect variable warn when write-line write-string
+ zerop))
(setq *package* *user-package*)