Skip to content
VitoVan edited this page Apr 26, 2023 · 17 revisions

JSCL HOW-TO

This page is not intent to be a comprehensive JSCL user documentation, nor a page of FAQ (since those Lisp wizards never ask, they just dig into the code and cast the spell).

This is a page for those non-wizard JSCL users to find some clues to do something, with extra links for them to find out more.

Please feel free to edit this page, add more examples or more questions.

How to alert?

(#j:alert "this is an alert")

How to access JS object in JSCL?

With #j: and replace dot . with :, you can access almost everything.

CL-USER> #j:navigator:appVersion
"5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
CL-USER> 

Read more: JSCL and manipulations with JS objects, FFI Design Discussions

How to access JS object properties? (without reader syntax)

Use jscl::oget to read, jscl::oset to set.

Syntax:

(jscl::oget obj key)

(jscl::oset value obj key)

Also, jscl::oget is setf-able:

(setf (jscl::oget obj key) value)

How to call methods of JS objects? (without reader syntax)

Use jscl::oget to get the method and then call it:

((jscl::oget obj method-name) &rest args)

Example, call send method of websocket object, passing message as argument:

((jscl::oget websocket "send") message)

How to convert between JS and Lisp representations?

Use jscl::js-to-lisp and jscl::lisp-to-js.

How to add JSCL function to DOM event listener as callback?

Use lambda:

(#j:document:body:addEventListener "mousedown" (lambda (ev) (#j:console:log "Mouse down")))
(#j:setTimeout (lambda () (#j:alert "Timeout")) 2000)

Or function:

(defun on-mousedown (event) (format t "mouse is down: ~A~%" event))
(#j:document:body:addEventListener "mousedown" #'on-mousedown)

How to access a Lisp variable from JavaScript world?

in JSCL REPL:

CL-USER> (defparameter *counter* 0)
*COUNTER*
CL-USER> 

then in JavaScript Console:

>> jscl.packages["CL-USER"].symbols["*COUNTER*"].value

This seems to be working, but I don't know if this is appropriate.

How to expose a Lisp function to JavaScript world?

Set the value of #j:myJSFunction to the Lisp function.

Example:

(setf #j:myJSFunction (lambda (x y z) (format nil "~a, ~a and ~a" x y z)))

Then we can access the function from Javascript. At the console evaluate:

myJSFunction(1,2,3) => "1, 2 and 3"

How to compile my Lisp file?

sbcl --load jscl.lisp \
     --eval '(jscl:bootstrap)' \
     --eval '(jscl:compile-application (list "~/source/file1.lisp" "~/source/file2.lisp" "~/source/file3.lisp") "~/source/app.js")' \
     --eval '(quit)'

add the generated app.js to your HTML:

    <script>
      var jqconsole = $("#console").jqconsole("", "");
    </script>
     <script src="jscl.js" type="text/javascript"></script>
+    <script src="app.js" type="text/javascript"></script>
    <script src="jscl-web.js" type="text/javascript"></script>

How to compile my Lisp file and expose functions/macros to the REPL?

This is tricky, but feasible, and problematic.

sbcl --load jscl.lisp \
     --eval '(jscl:bootstrap)' \
     --load bundle.lisp \
     --eval '(jscl:bundle-application (list "~/source/file1.lisp" "~/source/file2.lisp" "~/source/file3.lisp") "~/source/app.js")' \
     --eval '(quit)'

get bundle.lisp

REPLACE jscl.js with the generated app.js to your HTML:

    <script>
      var jqconsole = $("#console").jqconsole("", "");
    </script>
-     <script src="jscl.js" type="text/javascript"></script>
+     <script src="app.js" type="text/javascript"></script>
    <script src="jscl-web.js" type="text/javascript"></script>

Read more: REPL exposure, downside of bundle-application