git » jacl.git » commit f5ad13c

paper

author Alan Dipert
2020-04-14 06:19:56 UTC
committer Alan Dipert
2020-04-14 06:19:56 UTC
parent c96af85cc746df839d3e2c522ba297740631dcea

paper

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}.