JSCL

A Lisp-to-Javascript compiler bootstrapped from Common Lisp

@PuercoPop

Algunas Características

  • Necesita de un 'run-time'
  • Corre en Node y en el Navegador
  • Un FFI para llamar código escrito en JS
  • Viene con un REPL para Node y el Navegador 
(defvar *source*
  '(("boot"          :target)
    ("compat"        :host)
    ("setf"          :target)
    ("utils"         :both)
    ("defstruct"     :both)
    ("lambda-list"   :both)
    ("numbers"       :target)
    ("char"          :target)
    ("list"          :target)
    ("array"         :target)
    ("string"        :target)
    ("sequence"      :target)
    ("stream"        :target)
    ("hash-table"    :target)
    ("print"         :target)
    ("misc"          :target)
    ("ffi"           :target)
    ("symbol"        :target)
    ("package"       :target)
    ("read"          :both)
    ("conditions"    :both)
    ("backquote"     :both)
    ("compiler"
     ("codegen"      :both)
     ("compiler"     :both))
    ("documentation" :target)
    ("toplevel"      :target)))

Boostraping



;; Tests
(compile-application (append (directory "tests.lisp")
                             (directory "tests/*.lisp")
                             (directory "tests-report.lisp"))
                     (merge-pathnames "tests.js" *base-directory*))

;; Web REPL
(compile-application (list #P"repl-web/repl.lisp")
                     (merge-pathnames "repl-web.js" *base-directory*))

;; Node REPL
(compile-application (list #P"repl-node/repl.lisp")
                     (merge-pathnames "repl-node.js" *base-directory*))

Compilando tu código

(defun compile-application (files output)
  (with-compilation-environment
    (with-open-file (out output :direction :output :if-exists :supersede)
      (format out "(function(jscl){~%")
      (format out "'use strict';~%")
      (format out "(function(values, internals){~%")
      (dolist (input files)
        (!compile-file input out))
      (format out "})(jscl.internals.pv, jscl.internals);~%")
      (format out "})( typeof require !== 'undefined'? require('./jscl'): window.jscl )~%"))))

Compilando tu código

FFI: Call to JS

  • #j:<function>

  • (oget <obj> &rest keys)

  • js-vref

  • js-vset

  • new

Llamar a una función de JS




(defmacro async (&body body)
  `(#j:setTimeout (lambda () ,@body)))

Acceder a una propiedad de un objecto de JS


;; Retrieve a property
(defun length (array)
  (oget array "length"))

;; Set a property
(setf (oget my-array 2) "foo")

Crear objectos JS



(let ((obj (new)))
  (setf (oget obj "a") 1) obj)


;; Retrieve a variable
(%js-vref "window")                                                     

;; Set a variable
(%js-vset "eval_in_lisp"
          (lambda (form) (eval (read-from-string form))))

Acceder a variables de JS

Compilador

Tradicionalmente

Lexer -> Parser -> AST -> AST -> Codegen

Lisp

Read -> Macroexpansion -> Compile

compiler.lisp: Rescribiendo S-expressions

define-raw-builtin

define-builtin

codegen.lisp: S-expressions a Javscript

literales

operadores

special forms?

  • Projectos Similares

JSCL

By puercopop

JSCL

  • 725