Rewrite the REPL in Lisp using FFI
authorDavid Vázquez <davazp@gmail.com>
Wed, 19 Feb 2014 01:48:57 +0000 (02:48 +0100)
committerDavid Vázquez <davazp@gmail.com>
Wed, 19 Feb 2014 01:48:57 +0000 (02:48 +0100)
jscl.html
src/compiler/compiler.lisp
src/stream.lisp
src/toplevel.lisp

index ade16ec..a8d109b 100644 (file)
--- a/jscl.html
+++ b/jscl.html
 
   <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="jscl.js" type="text/javascript"></script>
     <script src="jqconsole.min.js" type="text/javascript" charset="utf-8"></script>
     <script>
-      var jqconsole;
-      $(function () {
-        jqconsole = $('#console').jqconsole('Welcome to JSCL!\n\n', '');
-        jqconsole.RegisterMatching('(', ')', 'parents');
-        if (localStorage.getItem("jqhist"))
-           jqconsole.SetHistory(JSON.parse(localStorage.getItem("jqhist")));
-      
-        lisp.write = function(str){
-           jqconsole.Write(xstring(str), 'jqconsole-output', false);
-           return str;
-        }
-
-        var startPrompt = function () {
-          // Start the prompt with history enabled.
-          jqconsole.Write(lisp.evalString('(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(input);
-                    // for (var i=0; i<vs.length; i++){
-                       jqconsole.Write(lisp.print(vs) + '\n', 'jqconsole-return');
-                       localStorage.setItem("jqhist", JSON.stringify(jqconsole.GetHistory()));
-                    // }
-                } catch(error) {
-                    var msg = error.message || error || 'Unknown error';
-                    if (typeof(msg) != 'string') msg = xstring(msg);
-                    jqconsole.Write('ERROR: ' + msg + '\n', 'jqconsole-error');
-                }
-            } else
-                jqconsole.Write(lisp.compileString(input.slice(1)) + '\n', 'jqconsole-return');
-
-            // Restart the prompt.
-            startPrompt();
-          }, function(input){
-            try {
-                lisp.read(input[0]==','? input.slice(1): input);
-            } catch(error) {
-                return 0;
-            }
-            return false;
-          });
-        };
-        startPrompt();
-      });
+      var jqconsole = $('#console').jqconsole(';; Welcome to JSCL!\n\n', '');
     </script>
   </body>
 </html>
index 1ea5259..222f660 100644 (file)
 (define-builtin functionp (x)
   `(bool (=== (typeof ,x) "function")))
 
-(define-builtin %write-string (x)
-  `(method-call |lisp| "write" ,x))
-
 (define-builtin /debug (x)
   `(method-call |console| "log" (call |xstring| ,x)))
 
index 086b145..d08f52c 100644 (file)
@@ -21,6 +21,9 @@
 
 (/debug "loading stream.lisp!")
 
+(defun %write-string (string)
+  (#j:jqconsole:Write string "jqconsole-output"))
+
 (defvar *standard-output*
   (vector 'stream
           (lambda (ch) (%write-string (string ch)))
index 7dddf6e..42864e6 100644 (file)
 
 (defvar *root* (%js-vref "window"))
 
-;;; Set some external entry point to the Lisp implementation to the
-;;; console. It would not be necessary when FFI is finished.
-(let ((*root* #j:lisp))
-  (setf #j:read #'ls-read-from-string)
-  (setf #j:print #'prin1-to-string)
-  (setf #j:eval #'eval)
-  (setf #j:compile (lambda (s) (compile-toplevel s t)))
-  (setf #j:evalString (lambda (str) (eval (ls-read-from-string str))))
-  (setf #j:evalInput (lambda (str) (eval-interactive (ls-read-from-string str))))
-  (setf #j:compileString (lambda (str) (compile-toplevel (ls-read-from-string str) t))))
 
+(defun load-history ()
+  (#j:jqconsole:SetHistory (#j:JSON:parse (#j:localStorage:getItem "jqhist"))))
+
+(defun save-history ()
+  (#j:localStorage:setItem "jqhist" (#j:JSON:stringify (#j:jqconsole:GetHistory))))
+
+(defun toplevel ()
+  (let ((prompt (format nil "~a> " (package-name *package*))))
+    (#j:jqconsole:Write prompt "jqconsole-prompt"))
+  (flet ((process-input (input)
+           (let* ((form (read-from-string input))
+                  (result (multiple-value-list (eval-interactive form))))
+             (dolist (x result)
+               (#j:jqconsole:Write (format nil "~S~%" x) "jqconsole-return"))
+             (save-history)) 
+           (toplevel)))
+    (#j:jqconsole:Prompt t #'process-input)))
+
+
+;;; KLUDGE: I tried
+;;; 
+;;;   (#j:document.addEventListener "load" #'topevel nil)
+;;; 
+;;; but it is not working. So I am using this temporarily to wait
+;;; until the DOM is ready before starting the REPL.
+
+(#j:setTimeout (lambda ()
+                 (#j:jqconsole:RegisterMatching "(" ")" "parents")
+                 (load-history)
+                 (toplevel))
+               0)