projects
/
jscl.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
Add `remhash' function
[jscl.git]
/
src
/
compiler
/
codegen.lisp
diff --git
a/src/compiler/codegen.lisp
b/src/compiler/codegen.lisp
index
51e5c65
..
e3c450a
100644
(file)
--- a/
src/compiler/codegen.lisp
+++ b/
src/compiler/codegen.lisp
@@
-1,6
+1,6
@@
;;; compiler-codege.lisp --- Naive Javascript unparser
;;; 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
;; 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/>.
;; 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.
;;; 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!")
(/debug "loading compiler-codegen.lisp!")
+
(defvar *js-macros* nil)
(defmacro define-js-macro (name lambda-list &body body)
(let ((form (gensym)))
(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-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)
;;; Two seperate functions are needed for escaping strings:
;;; One for producing JavaScript string literals (which are singly or
;;; doubly quoted)
@@
-99,6
+103,9
@@
(defun js-format (fmt &rest args)
(apply #'format *js-output* fmt args))
(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))
(defun valid-js-identifier (string-designator)
(let ((string (typecase string-designator
(symbol (symbol-name string-designator))
@@
-111,9
+118,15
@@
(if (plusp (length string))
(not (digit-char-p (char string 0)))
t))
(if (plusp (length string))
(not (digit-char-p (char string 0)))
t))
- (values (format nil "~a" string) t)
+ (values string t)
(values nil nil)))))
(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)
(defun js-identifier (string-designator)
(multiple-value-bind (string valid)
(valid-js-identifier string-designator)
@@
-199,6
+212,10
@@
(case (length (cdr form))
(1 `(unary- ,(cadr form)))
(t (reduce (lambda (x y) `(- ,x ,y)) (cdr form)))))
(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)
((and or)
(reduce (lambda (x y) `(,(car form) ,x ,y)) (cdr form)))
((progn comma)
@@
-207,6
+224,10
@@
(js-macroexpand form)))
form))
(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)))
(defun js-operator-expression (op args precedence associativity operand-order)
(let ((op1 (car args))
(op2 (cadr args)))
@@
-358,6
+379,15
@@
(t
(js-operator-expression (car form) (cdr form) precedence associativity operand-order)))))
(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))
(defun js-expand-stmt (form)
(cond
((and (consp form) (eq (car form) 'progn))
@@
-372,6
+402,11
@@
(t
(js-macroexpand form))))
(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)))
(defun js-stmt (form &optional parent)
(let ((form (js-expand-stmt form)))
(flet ((js-stmt (x) (js-stmt x form)))
@@
-379,11
+414,11
@@
((null form)
(unless (or (and (consp parent) (eq (car parent) 'group))
(null parent))
((null form)
(unless (or (and (consp parent) (eq (car parent) 'group))
(null parent))
- (js-format ";")))
+ (js-end-stmt)))
((atom form)
(progn
(js-expr form)
((atom form)
(progn
(js-expr form)
- (js-format ";")))
+ (js-end-stmt)))
(t
(case (car form)
(label
(t
(case (car form)
(label
@@
-397,12
+432,12
@@
(when label
(js-format " ")
(js-identifier 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)
(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)
(var
(flet ((js-var (spec)
(destructuring-bind (variable &optional initial)
@@
-417,7
+452,7
@@
(dolist (var vars)
(js-format ",")
(js-var var))
(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 (")
(if
(destructuring-bind (condition true &optional false) (cdr form)
(js-format "if (")
@@
-495,11
+530,13
@@
(destructuring-bind (object) (cdr form)
(js-format "throw ")
(js-expr object)
(destructuring-bind (object) (cdr form)
(js-format "throw ")
(js-expr object)
- (js-format ";")))
+ (js-end-stmt)))
(t
(js-expr form)
(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)
(defun js (&rest stmts)
(mapc #'js-stmt stmts)
nil)