author | Alan Dipert
<alan@dipert.org> 2020-04-14 06:19:56 UTC |
committer | Alan Dipert
<alan@dipert.org> 2020-04-14 06:19:56 UTC |
parent | c96af85cc746df839d3e2c522ba297740631dcea |
paper/Makefile | +9 | -7 |
paper/jacl-demo-els-2020.tex | +591 | -0 |
paper/jacl-els-2020.bib | +7 | -0 |
paper/jacl-els-2020.tex | +20 | -4 |
diff --git a/paper/Makefile b/paper/Makefile index 65d9f90..12526f7 100644 --- a/paper/Makefile +++ b/paper/Makefile @@ -1,17 +1,19 @@ .PHONY=all deploy clean -DOC := jacl-els-2020.tex +DOCS := jacl-els-2020.tex jacl-demo-els-2020.tex +BIB := jacl-els-2020.bib +PDFS := $(DOCS:.tex=.pdf) CF_DIST := E6GOTXLS9MCZF -all: jacl-els-2020.pdf +all: $(PDFS) -jacl-els-2020.pdf: jacl-els-2020.tex jacl-els-2020.bib +%.pdf: %.tex $(BIB) rubber --pdf $< -deploy: jacl-els-2020.pdf - aws s3 cp jacl-els-2020.pdf s3://tailrecursion.com/\~alan/documents/jacl-els-2020-draft.pdf +deploy: $(PDFS) + aws s3 cp $< s3://tailrecursion.com/\~alan/documents/ aws cloudfront create-invalidation --distribution-id $(CF_DIST) --paths '/*' clean: - rm -f $(DOC:.tex=.out) - rubber --pdf --clean $(DOC) + rm -f $(DOCS:.tex=.out) + rubber --pdf --clean $(DOCS) diff --git a/paper/jacl-demo-els-2020.tex b/paper/jacl-demo-els-2020.tex new file mode 100644 index 0000000..367021f --- /dev/null +++ b/paper/jacl-demo-els-2020.tex @@ -0,0 +1,591 @@ + +\documentclass[sigconf]{acmart} +\usepackage{booktabs} + +\AtBeginDocument{% + \providecommand\BibTeX{{% + \normalfont B\kern-0.5em{\scshape i\kern-0.25em b}\kern-0.8em\TeX}}} + +\setcopyright{acmcopyright} +\copyrightyear{2020} +\acmYear{2020} +\acmDOI{10.1145/1122445.1122456} + +\acmConference[ELS '20]{ELS '20: European Lisp Symposium}{April 27--28, 2020}{Z\"{u}rich, Switzerland} +\acmBooktitle{ELS '20: European Lisp Symposium, April 27--28, 2020, Z\"{u}rich, Switzerland} +\acmPrice{15.00} +\acmISBN{978-1-4503-XXXX-X/18/06} + +%%\acmSubmissionID{123-A56-BU3} + +\begin{document} + +\title{JACL: A Common Lisp for Developing Single-Page Web Applications} + +\author{Alan Dipert} +\email{alan@dipert.org} + +\begin{abstract} + This paper demonstrates JavaScript-Assisted Common Lisp (JACL), a + new Web-browser based implementation of an extended subset of Common + Lisp. While still in the early stages of development, JACL is an + effort to facilitate the eventual use of Common Lisp in overcoming + the challenges of Single-page Web Application (SPA) + development. JACL promotes interactive development in the Web + browser environment with its \emph{asynchronous reader} and Chrome + DevTools-based REPL client. JACL includes an optimizing + Lisp-to-JavaScript compiler and supports interoperation with + JavaScript. +\end{abstract} + +\begin{CCSXML} + <ccs2012> + <concept> + <concept_id>10011007.10011006.10011041.10011045</concept_id> + <concept_desc>Software and its engineering~Dynamic compilers</concept_desc> + <concept_significance>500</concept_significance> + </concept> + <concept> + <concept_id>10011007.10011006.10011041.10011048</concept_id> + <concept_desc>Software and its engineering~Runtime environments</concept_desc> + <concept_significance>500</concept_significance> + </concept> + </ccs2012> +\end{CCSXML} + +\ccsdesc[500]{Software and its engineering~Dynamic compilers} +\ccsdesc[500]{Software and its engineering~Runtime environments} + +\keywords{Common Lisp, JavaScript, web applications} + +\maketitle + +\section{Motivation} + +The demand for SPAs in the past decade has only grown, and users and +stakeholders continually expect larger and more sophisticated +applications. Unfortunately, large-scale development on the Web +browser platform presents a particular set of challenges that are not +easily overcome. Developers have responded to these challenges by +creating a widening variety of special-purpose programming languages +that compile to JavaScript +\cite{Somasegar12,Czaplicki12,wiki:ReasonML}. Each new language +promotes one or more paradigms, application architectures, or +development workflows, and claims some advantage relative to the +status quo. + +This paper demonstrates one new such language, JavaScript-Assisted +Common Lisp (JACL), an implementation of an extended subset of Common +Lisp. The primary goal of the JACL project is to ease SPA development +by applying Common Lisp --- a proven\cite{Cannon07,Garnet90,Action} +substrate for UI innovation --- to the difficult challenges now faced +by developers. The JACL language is envisioned as the means to +achieving that goal. + +\section{Related Work} + +Many similar efforts to compile Lisp to JavaScript precede JACL. Lisps +that have either demonstrated industrial utility or that implement a +significant subset of Common Lisp are surveyed in appendix +\ref{appendix:lisps}. Compared to related work, JACL distinguishes +itself primarily by its emphasis on interactive development and its +\emph{asynchronous reader} facility. + +\section{Interactive Development} + +% Talk about the JACL reader architecture + +\section{Object Inspection} + +%\section{Design and Implementation} +% +%From a design perspective, JACL is an effort to balance the +%requirements of an interactive and practical Lisp development +%environment with the constraints imposed by the Web browser +%platform. JACL proposes several innovations with respect to previous +%work in pursuit of this balance. +% +%\subsection{Asynchronous reader} +% +%The basis for interactive development in Lisp is undeniably the REPL, +%but as the JSCL ``pre-reader'' demonstrates, even the direct approach +%to this simple mechanism is hampered by the asynchronous model of +%input imposed by JavaScript.\cite{EventLoop}. Traditionally, Lisp +%readers are implemented in environments with a blocking function for +%obtaining input, like \texttt{getc(1)} on Unix. The blocking nature of +%input consumption allows the reader to consume nested input +%recursively, using the call stack to accumulate structures. In +%JavaScript, input arrives asynchronously, and only when the call stack +%is empty. To mitigate this difficulty, the JACL reader facility is +%completely asynchronous. Conceptually, it is the JSCL REPL +%``pre-reader'' taken to its inevitable conclusion. +% +%\section{Design and Implementation} +% +%From a design perspective, JACL is an effort to balance the +%requirements of an interactive and practical Lisp development +%environment with the constraints imposed by the Web browser +%platform. JACL proposes several innovations with respect to previous +%work in pursuit of this balance. +% +%\subsection{Asynchronous reader} +% +%The basis for interactive development in Lisp is undeniably the REPL, +%but as the JSCL ``pre-reader'' demonstrates, even the direct approach +%to this simple mechanism is hampered by the asynchronous model of +%input imposed by JavaScript.\cite{EventLoop}. Traditionally, Lisp +%readers are implemented in environments with a blocking function for +%obtaining input, like \texttt{getc(1)} on Unix. The blocking nature of +%input consumption allows the reader to consume nested input +%recursively, using the call stack to accumulate structures. In +%JavaScript, input arrives asynchronously, and only when the call stack +%is empty. To mitigate this difficulty, the JACL reader facility is +%completely asynchronous. Conceptually, it is the JSCL REPL +%``pre-reader'' taken to its inevitable conclusion. +% +%The JACL reader is implemented as a JavaScript class, +%\texttt{Reader}. \texttt{Reader} instances are parameterized by an +%input source. One such input source is the \texttt{BufferedStream} +%class. The input source asynchronously notifies the reader instance +%when characters are available. The reader incrementally consumes these +%characters. Once the reader has accumulated a Lisp datum, it notifies +%its subscribers of the availability of the datum. +% +%The JACL reader implementation makes extensive use of modern +%JavaScript features to support asynchronous programming including +%promises, iterators, async functions, async iterators, and the +%\texttt{await} keyword. These features simplify the JACL +%implementation and aid its performance \cite{V8async}. It is hoped +%that JACL will eventually be written in itself, and that these +%features will be accessible from Lisp, perhaps as a set of +%implementation-dependent \emph{declaration specifiers} available in +%\texttt{DECLARE} expressions. +% +%The following example demonstrates, in JavaScript, the process by +%which the JACL reader consumes characters and produces Lisp objects. A +%\texttt{BufferedStream} and \texttt{Reader} are instantiated, sent +%characters asynchronously, and then the resulting Lisp object is +%printed to the JavaScript console. +% +%\begin{verbatim} +%(async () => { +% let bs = new BufferedStream(), +% rdr = new Reader(bs); +% +% window.setTimeout(() => bs.write("1"), 1000); +% window.setTimeout(() => bs.write("2"), 2000); +% window.setTimeout(() => bs.write("3"), 3000); +% window.setTimeout(() => bs.write(" "), 4000); +% +% console.log(await rdr.read()); +%})(); +%\end{verbatim} +% +%\noindent In the preceding example, \texttt{window.setTimeout()} is +%used to enqueue several JavaScript functions for execution after 1000, +%2000, 3000, and 4000 milliseconds. Each enqueued function writes a +%character of input to the \texttt{BufferedStream} \texttt{bs} when +%invoked. +% +%Before any enqueued function is invoked, execution proceeds to the +%\texttt{console.log} call, but is suspended by the \texttt{await} +%keyword. +% +%The \texttt{await} keyword expects a JavaScript \texttt{Promise} +%object on its right side, and JavaScript execution remains suspended +%until the \texttt{Promise} has ``resolved'', or notified its +%subscribers that the pending computation it represents has +%completed. \texttt{rdr.read()} is an \texttt{async} function that +%returns such a \texttt{Promise}. +% +%Once \texttt{rdr} has completed a form --- in this case, the number +%123, after about 4000 milliseconds have elapsed --- execution +%continues, and \texttt{123} is printed to the JavaScript console. +% +%The ``read'' portion of the JACL REPL is implemented by first +%instantiating \texttt{BufferedStream} and \texttt{Reader} +%objects. Then, in an asynchronous loop, objects are consumed from the +%\texttt{Reader}, analyzed, compiled, and evaluated. +% +%Concurrently, characters may be sent to the \texttt{BufferedStream} +%instantiated by the REPL by calling the \texttt{write()} or +%\texttt{writeEach()} methods of the \texttt{BufferedaStream} +%object. Neither character input nor read object consumption impede +%other JavaScript operations, so the JACL REPL is suitable for +%embedding in applications. +% +%Because of the platform and implementation-dependent nature of the +%JACL reader, JACL does not support Common Lisp input streams, nor its +%standard \texttt{READ} and \texttt{READ-FROM-STRING} +%functions. Standard interfaces for extending the reader, such as the +%\linebreak\texttt{SET-MACRO-CHARACTER} function, are not directly +%supported. However, the JACL reader does provide an +%implementation-specific way to define reader macros. +% +%\subsection{Chrome DevTools REPL} +% +%A browser-based REPL facilitates experimentation with the language by +%interested people, from the comfort of their Web browsers. It's also a +%useful debugging feature of a deployed application. +% +%However, most developers already have a preferred text editor and a +%REPL interaction workflow, and so it's not within the JACL project +%scope to build a resident IDE in the style of SLip. Even if a resident +%IDE was a goal, the file system access restrictions imposed by the +%browser would present significant challenges. +% +%Instead, JACL offers an alternative development REPL approach that +%requires minimal host tooling: the DevTools-based REPL. Google Chrome +%is capable of hosting a WebSocket-based debug server that implements +%the DevTools Protocol \cite{GDevTools}. DevTools Protocol clients may +%then connect to the server and interact with open tabs, such as by +%evaluating arbitrary JavaScript within the context of the tab. JACL +%leverages the DevTools Protocol to deliver a command-line REPL client +%that may be run on development machines. The workflow is the +%following: +% +%\begin{enumerate} +% \item Run Google Chrome from the shell with the \linebreak +% \texttt{--remote-debugging-port} parameter. +% \item Navigate to the Web site hosting the JACL system you wish to +% interact with. +% \item Run \texttt{jacl-repl} from the shell. +% \item Be presented with a Lisp prompt. +%\end{enumerate} +% +%As a simple command-line application with a textual interface, +%\texttt{jacl-repl} can be run in various contexts. For example, it +%could be run within an Emacs ``inferior-lisp'' buffer, and then Lisp +%forms could be sent from other Emacs buffers for evaluation in the +%REPL. It could also be run as part of a build process that pipes Lisp +%sources over the WebSocket for batch compilation. It is anticipated +%that additional host-side tools that depend on \texttt{jacl-client} +%will be necessary in the future to support loading source files in +%dependency order. +% +%Unlike the pre-readers of SLip and JSCL, \texttt{jacl-client} is +%completely ignorant of Lisp syntax. \texttt{jacl-client} merely +%transports characters between the host machine and the Lisp system and +%so is \emph{not} a pre-reader. +% +%There are a few obvious ways the JACL REPL experience could be +%improved. For example, \texttt{jacl-repl} is currently an +%R\cite{Rstats} script requiring an R installation and the +%\texttt{chromote}\cite{Rchromote} package. A standalone binary +%executable is imagined in the future in order to make it easier for +%developers to start working on JACL projects. Additionally, JACL has +%yet to define a printer for its native types, or an extensible print +%protocol. Object string representations are obtained by calling the +%generic JavaScript \texttt{toString()} method, which doesn't always +%produce a representation that can be read back in. +% +%\subsection{Analyzing compiler} +% +%Unlike JSCL, the JACL compiler is organized to facilitate high-level +%optimizations such as those that could support efficient compilation +%of \texttt{TAGBODY} and other fundamental Common Lisp operators. +% +%The first compiler pass expands macros and produces an AST. The second +%compiler pass performs optimizations and produces a new AST. The final +%pass produces JavaScript code. AST nodes are represented by generic +%JavaScript objects with at least the following keys: +% +%\begin{itemize} +% \item \texttt{op}: The name of the node, as a JavaScript string. +% \item \texttt{env}: An object of class \texttt{Env} that represents +% the lexical environment of the node. +% \item \texttt{parent}: The parent of the node; this is \texttt{null} +% for the root. +% \item \texttt{form}: The original source data of the node, a Lisp +% datum. +%\end{itemize} +% +%\noindent Nodes and \texttt{Env} objects are immutable by +%convention. Functions are provided for modifying and merging these +%objects so as only to produce new objects. This convention reduces the +%possibility of optimization passes interfering with one another. It +%also eases understanding the AST, since every AST node contains a copy +%of all relevant context. As JavaScript objects, AST nodes are easily +%introspected using the object inspector of the Web browser. +% +%Currently, the \texttt{Env} object tracks evaluation context --- one +%of \emph{statement}, \emph{expression}, or \emph{return} --- lexical +%variables, and \texttt{TAGBODY} tags. In the future, it will track the +%remaining aspects of the lexical environment, such as lexical +%functions and macros. +% +%\subsubsection{Embedding JavaScript with \texttt{JACL:\%JS}} +% +%Unlike JSCL or SLip, the JACL compiler supports a special operator for +%constructing fragments of JavaScript code, verbatim, from Lisp. The +%semantics of this operator, \texttt{JACL:\%JS}, are inspired by a +%similar feature of ClojureScript, \texttt{js*}. For example, the +%following JACL code displays the number 3 in an alert box: +% +%\begin{verbatim} +%(JACL:%JS "window.alert(~{})" 3) +%\end{verbatim} +% +%The character sequence \texttt{\textasciitilde\{\}} is distinct from +%any plausible \linebreak JavaScript syntax and so is used as placeholder +%syntax. There must be as many placeholders as there are arguments to +%\texttt{JACL:\%JS}. +% +%\subsubsection{Other interoperation support} +% +%In addition to \texttt{JACL:\%JS}, the JACL compiler currently +%supports three more special operators for interacting with the host +%platform: \texttt{JACL:\%NEW}, \texttt{JACL:\%DOT} and +%\texttt{JACL:\%CALL}. These operators perform JavaScript object +%instantiation, field access, and function calls, respectively. Since +%JACL functions compile into JavaScript functions, \texttt{JACL:\%CALL} +%is the basis for \texttt{FUNCALL} in JACL, and for function calls +%generally. +% +%JACL also supplies a convenience macro, \texttt{JACL:\textbackslash.} +%or ``the dot macro'' for performing a series of field accesses and +%method calls\footnote{Strictly speaking, JavaScript ``method calls'' +% are normal function calls but with a particular value of +% \texttt{this}.} concisely. The dot macro takes direct inspiration +%from the \texttt{..} macro of Clojure. \texttt{JACL:\textbackslash.} +%expands to zero or more nested \texttt{JACL:\%DOT} or +%\texttt{JACL:\%CALL} forms. Here is an example of a +%\texttt{JACL:\textbackslash.} form --- equivalent to the JavaScript +%expression \texttt{(123).toString().length} --- and its corresponding +%expansion: +% +%\begin{verbatim} +%(\. 123 (|toString|) |length|) +%(%DOT (%CALL 123 |toString|) |length|) +%\end{verbatim} +% +%\noindent Note that JavaScript identifiers are case sensitive, and so +%case-preserving, pipe-delimited Lisp symbols must be used to refer to +%JavaScript object field and method names. The \emph{readtable case} of +%the JACL reader cannot currently be modified. The dot macro also +%recognizes Lisp or JavaScript strings as JavaScript identifiers. +% +%\subsubsection{\texttt{TAGBODY} compilation strategy} +% +%Consider the following Common Lisp program that decrements the local +%variable \texttt{X} 10 times: +% +%\begin{verbatim} +%(let ((x 10)) +% (tagbody +% start +% (when (zerop x) (go end)) +% (setq x (1- x)) +% (go start) +% end)) +%\end{verbatim} +% +%\noindent JSCL, the existing Lisp closest to JACL, would compile the +%preceding code into approximately\footnote{Actual JSCL output is not +% used because it includes type checks, generated variable names, and +% other code that would obscure the relevant machinery.} the following +%JavaScript: +% +%\begin{verbatim} +%function Jump(id, label) { +% this.id = id; +% this.label = label; +%} +% +%var X = 10; +%var id = []; +%var label = 0; +%LOOP: while (true) { +% try { +% switch(label) { +% case 0: +% if (X === 0) throw new Jump(id, 1); +% X = X-1; +% throw new Jump(id, 0); +% case 1: +% default: +% break LOOP; +% } +% } catch (e) { +% if (e instanceof Jump && e.id === id) { +% label = e.label; +% } else { +% throw e; +% } +% } +%} +%\end{verbatim} +% +%\noindent The mechanism is ingenious. \texttt{GO} tags became +%\texttt{switch} labels, and jumps became \texttt{throw} +%statements. The thrown objects are instances of \texttt{Jump}. Each +%instance of \texttt{Jump} contains a destination label. +% +%Unfortunately, in this scheme, every jump requires a JavaScript +%exception to be thrown, severely penalizing \texttt{TAGBODY} as +%previously discussed. Fortunately, a straightforward \emph{local jump +% optimization} can be applied that yields a tremendous performance +%benefit. Local jump optimization is a known +%technique\cite{SICLTagbody}, but JACL is the first Lisp targeting +%JavaScript to apply it. +% +%In order to perform this optimization, the JACL compiler first +%identifies local \texttt{GO}s in its analysis pass. These are +%\texttt{GO} nodes with no intervening \texttt{LAMBDA} +%nodes\footnote{Note that \texttt{LAMBDA} doesn't necessarily preclude +% local jump optimization if the \texttt{LAMBDA} is inlined, but JACL +% currently does not inline functions.} between them and their +%respective, lexically-enclosing \texttt{TAGBODY}s. Then, +%\texttt{TAGBODY}s are identified that consist of only local +%\texttt{GO}s. +% +%JavaScript generated for local \texttt{GO}s does not throw an +%exception, but instead leverages the labeled form of the JavaScript +%\texttt{continue}\cite{MozLabel} statement to transfer control +%appropriately. JavaScript generated for \texttt{TAGBODY}s that have +%been determined to consist only of local jumps omits the +%\texttt{try/catch} block, saving on generated code size. +% +%The following code is similar\footnote{Once more, actual compiler +% output has been significantly modified and reformatted for brevity.} +%to that generated by the JACL compiler. Cursory benchmarks +%\ref{appendix:benchmarks} show JACL code runs several orders of +%magnitude faster than JSCL, and that JACL code is almost as fast as +%the JavaScript statement \texttt{while(X--)}: +% +%\begin{verbatim} +%var X = 10; +%var label = 0; +%LOOP: while (true) { +% switch(label) { +% case 0: +% if (X === 0) { +% label = 1; +% continue LOOP; +% } +% X = X - 1; +% label = 0; +% continue LOOP; +% case 1: +% default: +% break LOOP; +% } +%} +%\end{verbatim} +% +%\section{Conclusion} +% +%We introduced JACL, a new Common Lisp created to ease SPA development. +%JACL is designed as an efficient, practical tool, with the needs of +%industrial SPA developers in mind. JACL integrates tightly with the +%Web browser platform and interoperates easily with +%JavaScript. Compared to other browser-based Lisps, JACL places a +%higher emphasis on the value of the REPL, and introduces new +%techniques for integrating the REPL into the development workflow. +% +%\section{Future Work} +% +%In order to be practical for application development, JACL must +%support the creation of standalone executables. In the case of JACL, +%these would be single JavaScript files that may be included in an HTML +%page and are executed on page load. Fortunately, since JACL +%development is image-based, JACL should support the traditional +%approach of specifying a Lisp function entrypoint and dumping the Lisp +%image to native (JavaScript) code. The +%\texttt{SAVE-LISP-AND-DIE}\cite{SBCLManual} function in SBCL and the +%\texttt{DELIVER}\cite{LispWorksDeliver} function in LispWorks are two +%examples of this functionality in other implementations. +% +%JACL should be able to perform rudimentary optimizations such as +%global function and variable tree shaking\cite{wiki:TreeShaking} in +%order to reduce the size of generated executables. In addition, JACL +%should make dynamic function and variable references in executables +%static, so that third party tools like Google Closure +%Compiler\cite{Bolin10} may optionally be used to perform additional +%optimization. +% +%Other than the ability to produce optimized standalone executables, +%many other design and implementation tasks remain, such as support for +%special variables in lambda lists, \texttt{EVAL-WHEN}, macro lambda +%lists, \texttt{DECLARE} et al, CLOS, various other data types, +%compiler macros, etc. The list of tasks is enormous, but it is +%anticipated that these features can be implemented over time, in the +%order demanded by application development. + +\section{Acknowledgments} + +The author wishes to thank Micha Niskin, Bart Botta, Kevin Lynagh, +Lionel Henry, and Andy Keep for invaluable feedback on early versions +of this paper. + +The author wishes to express particular thanks to Robert Strandh not +only for his feedback, but also for his guidance on the writing +process. + +Finally, the author wishes to express special gratitude to his +beautiful wife, Sandra Dipert, for her encouragement and support. + +\bibliographystyle{ACM-Reference-Format} +\bibliography{jacl-els-2020} + +\appendix + +\section{Survey of Related Lisps} +\label{appendix:lisps} + +\subsection{Parenscript} + +Released in 2005\cite{Baringer05}, Parenscript\cite{ParenScriptManual} +was the first Common Lisp compiler to target JavaScript. Parenscript +is not bootstrapped and its compiler is not written in JavaScript, and +so it relies on a hosting Common Lisp system for compilation. Only +JavaScript types are available to Parenscript programs at runtime, and +so Parenscript is more of a syntax frontend for JavaScript than it is +an interactive Lisp system. While Parenscript is not positioned to +facilitate large-scale SPA development, it remains a popular way to +add dynamic JavaScript-based behaviors to static Web sites. + +\subsection{SLip} + +SLip\cite{SLipHome,SLipImpl} is arguably the most ambitious Common +Lisp-on-JavaScript system created to date, even though it +intentionally diverges\cite{SLipVsCl} from Common Lisp in certain +ways. It offers a stunning array of powerful features including a +self-hosting compiler, a full set of control operators, JavaScript +Foreign-Function Interface (FFI), tail-call optimization, green +threads, and perhaps most impressively, a resident Emacs clone, +\emph{Ymacs}. SLip is based originally on the compiler and bytecode +interpreter presented in Chapter 23 of \emph{Paradigms of Artificial + Intelligence Programming: Case studies in Common + Lisp}\cite{Norvig92}. + +\subsection{JSCL} + +JSCL\cite{JSCLGitHub,JSCLTalk} compiles directly to JavaScript and is +self-hosting, includes the major control operators, and integrates +tightly with JavaScript. JSCL includes a reader, compiler, and +printer, and evaluation is performed by the JavaScript \texttt{eval()} +function. Between these, a Read Eval Print Loop (REPL) is possible, +and the JSCL distribution includes an implementation of one. + +\subsection{ClojureScript} + +ClojureScript \cite{CljsRelease,Cljs} is probably the most successful +Lisp dialect for building SPAs by number of commercial users +\cite{CljsUsers}. ClojureScript is a dialect of an earlier language, +Clojure\cite{Clojure}, which targets Java Virtual Machine (JVM) +bytecode. The ClojureScript reader and macro systems were both +originally hosted in Clojure, in a manner similar to Parenscript. +ClojureScript prioritizes the ability to produce high-performance +deliverables. + +\subsection{Valtan} + +Valtan\cite{valtanGitHub} compiles to JavaScript and includes a suite +of FFI operators for interoperating with JavaScript. It is +self-hosting and features a sophisticated, CLOS-based compiler +architecture. It also includes a REPL and several example +applications. + +\end{document} +\endinput diff --git a/paper/jacl-els-2020.bib b/paper/jacl-els-2020.bib index 227887d..477b365 100644 --- a/paper/jacl-els-2020.bib +++ b/paper/jacl-els-2020.bib @@ -127,6 +127,13 @@ lastaccessed = {February 12, 2020}, } +@online{valtanGitHub, + author={cxxxr}, + title="cxxxr/valtan", + url="https://github.com/cxxxr/valtan", + lastaccessed="April 4, 2020", +} + @online{CljsUsers, author={{Cognitect, Inc.}}, year={2020}, diff --git a/paper/jacl-els-2020.tex b/paper/jacl-els-2020.tex index 1245598..c8415db 100644 --- a/paper/jacl-els-2020.tex +++ b/paper/jacl-els-2020.tex @@ -79,8 +79,8 @@ Lisp (JACL), an implementation of an extended subset of Common Lisp. The primary goal of the JACL project is to ease SPA development by applying Common Lisp --- a proven\cite{Cannon07,Garnet90,Action} substrate for UI innovation --- to the difficult challenges now faced -by developers. The JACL language is envisioned as the means to that -goal. +by developers. The JACL language is envisioned as the means to +achieving that goal. Most popular, contemporary compile-to-JavaScript languages are oriented around the affordances of static type checking; JACL, as a @@ -130,6 +130,22 @@ from producing competitively fast or small application deliverables. Consequently, SLip does not satisfy the JACL project goal of facilitating large-scale industrial SPA development. +\subsection{valtan} + +valtan\cite{valtanGitHub} + +%% Optimizes tagbody; HIR has loop/recur +%% https://github.com/cxxxr/valtan/blob/master/library/valtan-core/compiler/hir-optimize.lisp#L270 + +%% Includes full JavaScript FFI +%% https://github.com/cxxxr/valtan/blob/master/docs/js-interop.lisp + +%% Is it self-hosting? Yes, I think it is: +%% https://github.com/cxxxr/valtan/blob/8d8ba20ded78f53502a6004609b29bb50872f866/library/valtan-core/lisp/compilation.lisp + +%% Includes support for working with React and example tic-tac-toe application +%% https://github.com/cxxxr/valtan/tree/master/example + \subsection{JSCL} Of existing Common Lisps, JSCL\cite{JSCLGitHub,JSCLTalk} is the one @@ -194,7 +210,7 @@ other iteration operators are expressed in terms of \texttt{TAGBODY}, this performance problem pervades the JSCL system. More efficient ways of implementing \texttt{TAGBODY} are not hard to -imagine, but the JSCL compiler does not amene itself to the +imagine, but the JSCL compiler does not lend itself to the implementation of this or other high-level optimizations, as JSCL lacks a sufficiently expressive intermediate representation (IR). High-level optimizations and transformations are important for a @@ -438,7 +454,7 @@ following JACL code displays the number 3 in an alert box: \end{verbatim} The character sequence \texttt{\textasciitilde\{\}} is distinct from -any plausible JavaScript syntax and so is used as placeholder +any plausible \linebreak JavaScript syntax and so is used as placeholder syntax. There must be as many placeholders as there are arguments to \texttt{JACL:\%JS}.