-* Ecmalisp
+* JSCL
- Ecmalisp is a Common Lisp to Javascript compiler, which is
- bootstrapped from Common Lisp and executed from the browser.
+ JSCL is a Common Lisp to Javascript compiler, which is bootstrapped
+ from Common Lisp and executed from the browser.
** Getting started
-You can try a demo [[http://davazp.net/ecmalisp/ecmalisp.html][here]]. But if you want to hack ecmalisp, you will
-have to download the repository
+You can try a demo [[http://davazp.net/jscl/jscl.html][here]]. But if you want to hack JSCL, you will have
+to download the repository
-=git clone git@github.com:davazp/ecmalisp.git=
+=git clone git@github.com:davazp/jscl.git=
-/load/ ecmalisp.lisp in your Lisp, and call the bootstrap function to
+/load/ jscl.lisp in your Lisp, and call the bootstrap function to
compile the implementation itself:
=(bootstrap)=
-It will generate a ecmalisp.js file in the top of the source tree. Now
-you can open ecmalisp.html in your browser and use it.
+It will generate a jscl.js file in the top of the source tree. Now you
+can open JSCL.html in your browser and use it.
** Status
-Ecmalisp is and will be a subset of Common Lisp. Of course it is far
+JSCL is and will be a subset of Common Lisp. Of course it is far
from complete, but it supports partially most common special
operators, functions and macros. In particular:
+++ /dev/null
-<!doctype html>
-<html>
- <head>
- <style>
- /* The console container element */
- body { background-color: black; font-size: 16px; font-family: Courier; overflow: hidden; padding: 0 0 0 0;}
- #console {
- position: absolute;
- top: 0px;
- bottom: 0px;
- left: 0px;
- right: 0px;
- background-color:black;
- }
-
- .parents {
- font-weight: bold;
- }
-
- /* The inner console element. */
- .jqconsole {
- padding: 10px;
- }
- /* The cursor. */
- .jqconsole-cursor {
- background-color: gray;
- }
- /* The cursor color when the console looses focus. */
- .jqconsole-blurred .jqconsole-cursor {
- background-color: #666;
- }
- /* The current prompt text color */
- .jqconsole-prompt {
- color: White;
- }
- /* The command history */
- .jqconsole-old-prompt {
- color: White;
- font-weight: normal;
- }
- /* The text color when in input mode. */
- .jqconsole-input {
- color: White;
- }
- /* Previously entered input. */
- .jqconsole-old-input {
- color: White;
- font-weight: normal;
- }
- /* The text color of the output. */
- .jqconsole-output {
- color: green;
- }
- .jqconsole-return, .jqconsole-header {
- color: gray;
- }
- .jqconsole-error {
- color: red;
- }
-</style>
- </head>
-
- <body>
- <div id="console"></div>
- <script src="ecmalisp.js" type="text/javascript"></script>
- <script src="jquery.js" type="text/javascript" charset="utf-8"></script>
- <script src="jqconsole.min.js" type="text/javascript" charset="utf-8"></script>
- <script>
- $(function () {
- var jqconsole = $('#console').jqconsole('Welcome to Ecmalisp!\n\n', '');
- jqconsole.RegisterMatching('(', ')', 'parents');
-
- lisp.write = function(str){
- jqconsole.Write(str, 'jqconsole-output', false);
- return str;
- }
-
- var startPrompt = function () {
- // Start the prompt with history enabled.
- jqconsole.Write(lisp.evalString(pv, '(CL:PACKAGE-NAME CL:*PACKAGE*)') + '> ', 'jqconsole-prompt');
- jqconsole.Prompt(true, function (input) {
- // Output input with the class jqconsole-return.
- if (input[0] != ','){
- try {
- var vs = lisp.evalInput(mv, input);
- for (var i=0; i<vs.length; i++){
- jqconsole.Write(lisp.print(pv, vs[i]) + '\n', 'jqconsole-return');
- }
- } catch(error) {
- jqconsole.Write('ERROR: ' + (error.message || error) + '\n', 'jqconsole-error');
- }
- } else {
- jqconsole.Write(lisp.compileString(pv, input.slice(1)) + '\n', 'jqconsole-return');
- }
- // Restart the prompt.
- startPrompt();
- }, function(input){
- try {
- lisp.read(pv, input[0]==','? input.slice(1): input);
- } catch(error) {
- return 0;
- }
- return false;
- });
- };
- startPrompt();
- });
- </script>
- </body>
-</html>
+++ /dev/null
-;;; ecmalisp.lisp ---
-
-;; Copyright (C) 2012, 2013 David Vazquez
-;; Copyright (C) 2012 Raimon Grau
-
-;; This program is free software: you can redistribute it and/or
-;; modify it under the terms of the GNU General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-;;
-;; This program is distributed in the hope that it will be useful, but
-;; WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-;; General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-(defvar *source*
- '(("boot" :target)
- ("compat" :host)
- ("utils" :both)
- ("print" :target)
- ("read" :both)
- ("compiler" :both)
- ("toplevel" :target)))
-
-(defun source-pathname
- (filename &key (directory '(:relative "src")) (type nil) (defaults filename))
- (if type
- (make-pathname :type type :directory directory :defaults defaults)
- (make-pathname :directory directory :defaults defaults)))
-
-;;; Compile ecmalisp into the host
-(with-compilation-unit ()
- (dolist (input *source*)
- (when (member (cadr input) '(:host :both))
- (compile-file (source-pathname (car input))))))
-
-;;; Load ecmalisp into the host
-(dolist (input *source*)
- (when (member (cadr input) '(:host :both))
- (load (source-pathname (car input)))))
-
-(defun read-whole-file (filename)
- (with-open-file (in filename)
- (let ((seq (make-array (file-length in) :element-type 'character)))
- (read-sequence seq in)
- seq)))
-
-(defun ls-compile-file (filename out &key print)
- (let ((*compiling-file* t)
- (*compile-print-toplevels* print))
- (let* ((source (read-whole-file filename))
- (in (make-string-stream source)))
- (format t "Compiling ~a...~%" filename)
- (loop
- with eof-mark = (gensym)
- for x = (ls-read in nil eof-mark)
- until (eq x eof-mark)
- for compilation = (ls-compile-toplevel x)
- when (plusp (length compilation))
- do (write-string compilation out)))))
-
-(defun bootstrap ()
- (setq *environment* (make-lexenv))
- (setq *literal-symbols* nil)
- (setq *variable-counter* 0
- *gensym-counter* 0
- *literal-counter* 0
- *block-counter* 0)
- (with-open-file (out "ecmalisp.js" :direction :output :if-exists :supersede)
- (write-string (read-whole-file (source-pathname "prelude.js")) out)
- (dolist (input *source*)
- (when (member (cadr input) '(:target :both))
- (ls-compile-file (source-pathname (car input) :type "lisp") out)))))
--- /dev/null
+<!doctype html>
+<html>
+ <head>
+ <style>
+ /* The console container element */
+ body { background-color: black; font-size: 16px; font-family: Courier; overflow: hidden; padding: 0 0 0 0;}
+ #console {
+ position: absolute;
+ top: 0px;
+ bottom: 0px;
+ left: 0px;
+ right: 0px;
+ background-color:black;
+ }
+
+ .parents {
+ font-weight: bold;
+ }
+
+ /* The inner console element. */
+ .jqconsole {
+ padding: 10px;
+ }
+ /* The cursor. */
+ .jqconsole-cursor {
+ background-color: gray;
+ }
+ /* The cursor color when the console looses focus. */
+ .jqconsole-blurred .jqconsole-cursor {
+ background-color: #666;
+ }
+ /* The current prompt text color */
+ .jqconsole-prompt {
+ color: White;
+ }
+ /* The command history */
+ .jqconsole-old-prompt {
+ color: White;
+ font-weight: normal;
+ }
+ /* The text color when in input mode. */
+ .jqconsole-input {
+ color: White;
+ }
+ /* Previously entered input. */
+ .jqconsole-old-input {
+ color: White;
+ font-weight: normal;
+ }
+ /* The text color of the output. */
+ .jqconsole-output {
+ color: green;
+ }
+ .jqconsole-return, .jqconsole-header {
+ color: gray;
+ }
+ .jqconsole-error {
+ color: red;
+ }
+</style>
+ </head>
+
+ <body>
+ <div id="console"></div>
+ <script src="jscl.js" type="text/javascript"></script>
+ <script src="jquery.js" type="text/javascript" charset="utf-8"></script>
+ <script src="jqconsole.min.js" type="text/javascript" charset="utf-8"></script>
+ <script>
+ $(function () {
+ var jqconsole = $('#console').jqconsole('Welcome to JSCL!\n\n', '');
+ jqconsole.RegisterMatching('(', ')', 'parents');
+
+ lisp.write = function(str){
+ jqconsole.Write(str, 'jqconsole-output', false);
+ return str;
+ }
+
+ var startPrompt = function () {
+ // Start the prompt with history enabled.
+ jqconsole.Write(lisp.evalString(pv, '(CL:PACKAGE-NAME CL:*PACKAGE*)') + '> ', 'jqconsole-prompt');
+ jqconsole.Prompt(true, function (input) {
+ // Output input with the class jqconsole-return.
+ if (input[0] != ','){
+ try {
+ var vs = lisp.evalInput(mv, input);
+ for (var i=0; i<vs.length; i++){
+ jqconsole.Write(lisp.print(pv, vs[i]) + '\n', 'jqconsole-return');
+ }
+ } catch(error) {
+ jqconsole.Write('ERROR: ' + (error.message || error) + '\n', 'jqconsole-error');
+ }
+ } else {
+ jqconsole.Write(lisp.compileString(pv, input.slice(1)) + '\n', 'jqconsole-return');
+ }
+ // Restart the prompt.
+ startPrompt();
+ }, function(input){
+ try {
+ lisp.read(pv, input[0]==','? input.slice(1): input);
+ } catch(error) {
+ return 0;
+ }
+ return false;
+ });
+ };
+ startPrompt();
+ });
+ </script>
+ </body>
+</html>
--- /dev/null
+;;; jscl.lisp ---
+
+;; Copyright (C) 2012, 2013 David Vazquez
+;; Copyright (C) 2012 Raimon Grau
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+;;
+;; This program is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+;; General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+(defvar *source*
+ '(("boot" :target)
+ ("compat" :host)
+ ("utils" :both)
+ ("print" :target)
+ ("read" :both)
+ ("compiler" :both)
+ ("toplevel" :target)))
+
+(defun source-pathname
+ (filename &key (directory '(:relative "src")) (type nil) (defaults filename))
+ (if type
+ (make-pathname :type type :directory directory :defaults defaults)
+ (make-pathname :directory directory :defaults defaults)))
+
+;;; Compile jscl into the host
+(with-compilation-unit ()
+ (dolist (input *source*)
+ (when (member (cadr input) '(:host :both))
+ (compile-file (source-pathname (car input))))))
+
+;;; Load jscl into the host
+(dolist (input *source*)
+ (when (member (cadr input) '(:host :both))
+ (load (source-pathname (car input)))))
+
+(defun read-whole-file (filename)
+ (with-open-file (in filename)
+ (let ((seq (make-array (file-length in) :element-type 'character)))
+ (read-sequence seq in)
+ seq)))
+
+(defun ls-compile-file (filename out &key print)
+ (let ((*compiling-file* t)
+ (*compile-print-toplevels* print))
+ (let* ((source (read-whole-file filename))
+ (in (make-string-stream source)))
+ (format t "Compiling ~a...~%" filename)
+ (loop
+ with eof-mark = (gensym)
+ for x = (ls-read in nil eof-mark)
+ until (eq x eof-mark)
+ for compilation = (ls-compile-toplevel x)
+ when (plusp (length compilation))
+ do (write-string compilation out)))))
+
+(defun bootstrap ()
+ (setq *environment* (make-lexenv))
+ (setq *literal-symbols* nil)
+ (setq *variable-counter* 0
+ *gensym-counter* 0
+ *literal-counter* 0
+ *block-counter* 0)
+ (with-open-file (out "jscl.js" :direction :output :if-exists :supersede)
+ (write-string (read-whole-file (source-pathname "prelude.js")) out)
+ (dolist (input *source*)
+ (when (member (cadr input) '(:target :both))
+ (ls-compile-file (source-pathname (car input) :type "lisp") out)))))
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
-;;; This code is executed when ecmalisp compiles this file
-;;; itself. The compiler provides compilation of some special forms,
-;;; as well as funcalls and macroexpansion, but no functions. So, we
-;;; define the Lisp world from scratch. This code has to define enough
-;;; language to the compiler to be able to run.
+;;; This code is executed when JSCL compiles this file itself. The
+;;; compiler provides compilation of some special forms, as well as
+;;; funcalls and macroexpansion, but no functions. So, we define the
+;;; Lisp world from scratch. This code has to define enough language
+;;; to the compiler to be able to run.
(eval-when-compile
(%compile-defmacro 'defmacro
;;; of this function are available, because the Ecmalisp version is
;;; very slow and bootstraping was annoying.
-#+ecmalisp
+#+jscl
(defun indent (&rest string)
(let ((input (apply #'code string)))
(let ((output "")
(let ((b (global-binding name 'variable 'variable)))
(push 'constant (binding-declarations b)))))))
-#+ecmalisp
+#+jscl
(fset 'proclaim #'!proclaim)
(defun %define-symbol-macro (name expansion)
(push-to-lexenv b *environment* 'variable)
name))
-#+ecmalisp
+#+jscl
(defmacro define-symbol-macro (name expansion)
`(%define-symbol-macro ',name ',expansion))
(code "{name: \"" (escape-string (symbol-name sexp))
"\", 'package': '" (package-name package) "'}")
(code "{name: \"" (escape-string (symbol-name sexp)) "\"}")))
- #+ecmalisp
+ #+jscl
(let ((package (symbol-package sexp)))
(if (null package)
(code "{name: \"" (escape-string (symbol-name sexp)) "\"}")
;; us replace the list representation version of the
;; function with the compiled one.
;;
- #+ecmalisp (setf (binding-value macro-binding) compiled)
+ #+jscl (setf (binding-value macro-binding) compiled)
#+common-lisp (setf (gethash macro-binding *macroexpander-cache*) compiled)
(setq expander compiled))))
(values (apply expander (cdr form)) t))
((translate-function function)
(concat (translate-function function) arglist))
((and (symbolp function)
- #+ecmalisp (eq (symbol-package function) (find-package "COMMON-LISP"))
+ #+jscl (eq (symbol-package function) (find-package "COMMON-LISP"))
#+common-lisp t)
(code (ls-compile `',function) ".fvalue" arglist))
(t
-// This file is prepended to the result of compile ecmalisp.lisp, and
-// contain runtime code that ecmalisp assumes to exist.
+// This file is prepended to the result of compile jscl.lisp, and
+// contain runtime code that jscl assumes to exist.
var window = this;
var nil;
((string= feature "common-lisp")
(ls-read-1 stream) ;ignore
(ls-read-1 stream))
- ((string= feature "ecmalisp")
+ ((string= feature "jscl")
(ls-read-1 stream))
(t
(error "Unknown reader form.")))))))
(values (* sign value) index)
(values nil index)))))
-#+ecmalisp
+#+jscl
(defun parse-integer (string &key junk-allowed)
(multiple-value-bind (num index)
(!parse-integer string junk-allowed)
digits)))))
(defun float-to-string (x)
- #+ecmalisp
- (float-to-string x)
- #+common-lisp
- (format nil "~f" x))
+ #+jscl (float-to-string x)
+ #+common-lisp (format nil "~f" x))