author | Alan Dipert
<alan@dipert.org> 2020-02-12 16:10:02 UTC |
committer | Alan Dipert
<alan@dipert.org> 2020-02-12 16:10:02 UTC |
parent | 81a7b921c6b1e993a2dfd589a4ce097cc313cdaf |
paper/jacl-els-2020.tex | +94 | -45 |
diff --git a/paper/jacl-els-2020.tex b/paper/jacl-els-2020.tex index d6aecb5..0597683 100644 --- a/paper/jacl-els-2020.tex +++ b/paper/jacl-els-2020.tex @@ -402,13 +402,14 @@ optimizers excel at. If JSCL oriented itself toward generating code optimizable by third party tools, then its own internals could be simplified to a degree. -\section{Design and implementation} +\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 design innovations in pursuit of this balance. +JACL proposes several innovations with respect to previous work in +pursuit of this balance. \subsection{Asynchronous reader} @@ -418,8 +419,8 @@ approach to this simple mechanism is hampered by JavaScript's asynchronous model of input. To resolve this difficulty, JACL's reader facility is completely -asynchronous. It is the ``pre-reader'' taken to its inevitable -conclusion. +asynchronous. Conceptually, it is the JSCL REPL ``pre-reader'' taken +to its inevitable conclusion. JACL's reader is implemented as a JavaScript class, \texttt{Reader}. \texttt{Reader} instances are parameterized by an @@ -427,19 +428,23 @@ 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 consumers of the availability of the datum. +its subscribers of the availability of the datum. The JACL reader implementation makes extensive use of modern -asynchronous JavaScript programming techniques including Promises, -iterators, async functions, async iterators, and the \texttt{await} -keyword. +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 [ref V8 async/await]. It is hoped that JACL will +eventually be written in itself, and that these features will be +accessible from Lisp. -This language support for asynchronous programming reduces verbosity -of asynchronous code, while also allowing it to be nearly as easy to -follow as comparable synchronous code. For example, the following is -an example of instantiaing a \texttt{BufferedStream} and -\texttt{Reader}, sending in characters asynchronously after a delay, -and then displaying the resulting Lisp data to the JavaScript console. +The following example demonstrates, in JavaScript, the mechanism 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} let bs = new BufferedStream(), @@ -462,14 +467,13 @@ Before the enqueued function is invoked, execution proceeds to the keyword. The \texttt{await} keyword expects a Promise object on its right side, -and will suspend JavaScript execution until the Promise has +and JavaScript execution remains suspended until the Promise has ``resolved'', or notified its subscribers that the pending computation -it represents has completed. \texttt{rdr.read()} returns such a -Promise. +it represents has completed. \texttt{rdr.read()} is an \texttt{async} +function that returns such a Promise. -Once \texttt{rdr} has completed a form, the \texttt{await} evaluates -to the number \texttt{123} and the number is printed to the JavaScript -console. +Once \texttt{rdr} has completed a form, execution continues, and the +number \texttt{123} is printed to the JavaScript console. The ``read'' portion of JACL's REPL is satisfied by first establishing \texttt{BufferedStream} and \texttt{Reader} objects. Then, in an @@ -484,19 +488,28 @@ Neither character input nor read object consumption impede other JavaScript operations, so the JACL REPL model supports embedding in applications. -It is hoped that in the future, JACL will be written in itself, and so -all of these techniques will be accessible from Lisp. +Because of the platform and implementation-dependent nature of JACL's +reader, JACL does not support Common Lisp's streams abstraction, nor +its standard \texttt{READ} and \texttt{READ-FROM-STRING} functions. + +Additionally, standard interfaces for extending the reader, such as +the \texttt{SET-MACRO-CHARACTER} function, are not directly +supported. However, the JACL reader does provide an +implementation-specific way to define reader macros. + +JACL's reader is far from supporting all of Common Lisp syntax, but +its fundamental design is complete and unlikely to substantially +change. \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. +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 -refined REPL interaction workflow, so it's not within the JACL project -scope to build a resident text editor or IDE in the style of +refined REPL interaction workflow, and so it's not within the JACL +project scope to build a resident text editor or IDE in the style of SLip. Even if a resident editor was a goal, the file system access restrictions imposed by the browser would present significant challenges. @@ -510,9 +523,9 @@ DevTools Protocol is a standard for JSON object interchange over WebSocket that makes all of the browser's debugging facilities available remotely, over the network. -JACL leverages this feature of Chrome to deliver a command-line REPL -client that may be run on the developer's host machine. The workflow -is the following: +JACL takes advantage of this feature of Chrome in order to deliver a +command-line REPL client that may be run on the developer's host +machine. The workflow is the following: \begin{enumerate} \item Run Google Chrome from the shell with the @@ -523,13 +536,13 @@ is the following: \item Be presented with a Lisp prompt. \end{enumerate} -As a simple command-line application, \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 sent from other -Emacs buffers for evaluation in the REPL. +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 sent from other Emacs buffers for evaluation in the REPL. -\texttt{jacl-repl} is currently an R script, but a standalone binary -executable is imagined in the future. +It could be also be run as part of a build process that pipes Lisp +sources over the WebSocket for batch compilation. An advantage of the reader approach taken by JACL with respect to the implementation of \texttt{jacl-client} is that the REPL client is @@ -539,15 +552,24 @@ Lisp system, and displays characters output from Lisp. While \texttt{jacl-client} presents a synchronous input/output interface, it is actually the frontend for bidirectional asynchronous data transfer. -\subsection{Analyzing compiler} +\texttt{jacl-repl} is currently an R script requiring an R +installation and the installation of two supporting R packages, +\texttt{websocket} and \texttt{chromote}. A standalone binary +executable is imagined in the future. + +JACL has yet to define a printer for its native types, or an +extensible print protocol. Currently, object string representations +are obtained by calling the generic JavaScript \texttt{toString()} +method, which produces a representation that can't be read back in. + +\subsection{High-level optimizing compiler} -The JACL compiler is organized to facilitate high-level optimizations, -such as those necessary for efficient compilation of -\texttt{TAGBODY}/\texttt{GO}. +Unlike JSCL, the JACL compiler is organized to facilitate high-level +optimizations such as those that would support efficient compilation +of \texttt{TAGBODY}/\texttt{GO}. -Low level optimizations are left to (optional) JavaScript optimizers -that can be applied to delivered executables, which I will outline -next. +Low level optimizations are deferred to (optional) JavaScript +optimizers that may be applied to deliverable executables. The compiler has one analysis pass that results in an AST. The AST is then converted to JavaScript strings by a code generation step. @@ -557,12 +579,39 @@ keys: \begin{itemize} \item \texttt{op}: The node name, a JavaScript string. - \item \texttt{env}: An \texttt{Environment} object that represents the node's lexical environment. + \item \texttt{env}: An \texttt{Env} JavaScript object that + represents the node's lexical environment. \item \texttt{parent}: The node's parent; this is \texttt{null} for the root. \item \texttt{form}: The node's original source data, a Lisp datum. \end{itemize} -TODO +\texttt{node} 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 Web +browser's object inspector. + +Currently, the \texttt{Env} object tracks 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. + +Unlike JSCL or SLip, JACL's 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{~\{\}} is distinct from any plausible +JavaScript sequence and so is used as placeholder syntax. \subsection{Delivery}