Warming up: Comment codegen.lisp a little bit
[jscl.git] / src / compiler / codegen.lisp
index 51e5c65..e3c450a 100644 (file)
@@ -1,6 +1,6 @@
 ;;; compiler-codege.lisp --- Naive Javascript unparser
 
-;; copyright (C) 2013 David Vazquez
+;; Copyright (C) 2013, 2014 David Vazquez
 
 ;; JSCL is free software: you can redistribute it and/or
 ;; modify it under the terms of the GNU General Public License as
@@ -15,6 +15,7 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with JSCL.  If not, see <http://www.gnu.org/licenses/>.
 
+
 ;;; This code generator takes as input a S-expression representation
 ;;; of the Javascript AST and generates Javascript code without
 ;;; redundant syntax constructions like extra parenthesis.
@@ -24,6 +25,7 @@
 
 (/debug "loading compiler-codegen.lisp!")
 
+
 (defvar *js-macros* nil)
 (defmacro define-js-macro (name lambda-list &body body)
   (let ((form (gensym)))
@@ -49,6 +51,8 @@
 
 (defvar *js-output* t)
 
+(defvar *js-pretty-print* t)
+
 ;;; Two seperate functions are needed for escaping strings:
 ;;;  One for producing JavaScript string literals (which are singly or
 ;;;   doubly quoted)
 (defun js-format (fmt &rest args)
   (apply #'format *js-output* fmt args))
 
+;;; Check if STRING-DESIGNATOR is valid as a Javascript identifier. It
+;;; returns a couple of values. The identifier itself as a string and
+;;; a boolean value with the result of this check.
 (defun valid-js-identifier (string-designator)
   (let ((string (typecase string-designator
                   (symbol (symbol-name string-designator))
                (if (plusp (length string))
                    (not (digit-char-p (char string 0)))
                    t))
-          (values (format nil "~a" string) t)
+          (values string t)
           (values nil nil)))))
 
+
+;;; Expression generators
+;;;
+;;; `js-expr' and the following auxiliary functions are the
+;;; responsible for generating Javascript expression.
+
 (defun js-identifier (string-designator)
   (multiple-value-bind (string valid)
       (valid-js-identifier string-designator)
          (case (length (cdr form))
            (1 `(unary- ,(cadr form)))
            (t (reduce (lambda (x y) `(- ,x ,y)) (cdr form)))))
+        (*
+         (case (length (cdr form))
+           (0 1)
+           (t (reduce (lambda (x y) `(* ,x ,y)) (cdr form)))))
         ((and or)
          (reduce (lambda (x y) `(,(car form) ,x ,y)) (cdr form)))
         ((progn comma)
          (js-macroexpand form)))
       form))
 
+;;; It is the more complicated function of the generator. It takes a
+;;; operator expression and generate Javascript for it. It will
+;;; consider associativity and precedence in order not to generate
+;;; unnecessary parenthesis.
 (defun js-operator-expression (op args precedence associativity operand-order)
   (let ((op1 (car args))
         (op2 (cadr args)))
       (t
        (js-operator-expression (car form) (cdr form) precedence associativity operand-order)))))
 
+
+
+;;; Statements generators
+;;; 
+;;; `js-stmt' generates code for Javascript statements. A form is
+;;; provided to label statements. Remember that in particular,
+;;; expressions can be used as statements (semicolon suffixed).
+;;; 
+
 (defun js-expand-stmt (form)
   (cond
     ((and (consp form) (eq (car form) 'progn))
     (t
      (js-macroexpand form))))
 
+(defun js-end-stmt ()
+  (js-format ";")
+  (when *js-pretty-print*
+    (js-format "~%")))
+
 (defun js-stmt (form &optional parent)
   (let ((form (js-expand-stmt form)))
     (flet ((js-stmt (x) (js-stmt x form)))
         ((null form)
          (unless (or (and (consp parent) (eq (car parent) 'group))
                      (null parent))
-           (js-format ";")))
+           (js-end-stmt)))
         ((atom form)
          (progn
            (js-expr form)
-           (js-format ";")))
+           (js-end-stmt)))
         (t
          (case (car form)
            (label
               (when label
                 (js-format " ")
                 (js-identifier label))
-              (js-format ";")))
+              (js-end-stmt)))
            (return
              (destructuring-bind (value) (cdr form)
                (js-format "return ")
                (js-expr value)
-               (js-format ";")))
+               (js-end-stmt)))
            (var
             (flet ((js-var (spec)
                      (destructuring-bind (variable &optional initial)
                 (dolist (var vars)
                   (js-format ",")
                   (js-var var))
-                (js-format ";"))))
+                (js-end-stmt))))
            (if
             (destructuring-bind (condition true &optional false) (cdr form)
               (js-format "if (")
                (destructuring-bind (object) (cdr form)
                  (js-format "throw ")
                  (js-expr object)
-                 (js-format ";")))
+                 (js-end-stmt)))
            (t
             (js-expr form)
-            (js-format ";"))))))))
+            (js-end-stmt))))))))
+
 
+;;; It is intended to be the entry point to the code generator. 
 (defun js (&rest stmts)
   (mapc #'js-stmt stmts)
   nil)