cleanup of citations
This commit is contained in:
parent
04be5513e3
commit
1235d0f917
6 changed files with 239 additions and 142 deletions
BIN
build/report.pdf
BIN
build/report.pdf
Binary file not shown.
|
@ -36,7 +36,7 @@ A syntactic proposal, is a proposal that contains only changes to the syntax of
|
|||
|
||||
\subsection{Simple example of a syntactic proposal}
|
||||
|
||||
Consider a imaginary proposal \exProp. This proposal describes adding an optional keyword for declaring numerical variables if the expression of the declaration is a numerical literal.
|
||||
Consider an imaginary proposal \exProp. This proposal describes adding an optional keyword for declaring numerical variables if the expression of the declaration is a numerical literal.
|
||||
|
||||
This proposal will look something like this:
|
||||
|
||||
|
@ -184,15 +184,16 @@ await using void = x; // via: LexicalBinding : `void` Initializer
|
|||
\end{lstlisting}
|
||||
|
||||
\fi
|
||||
\subsection{Pipeline Proposal}
|
||||
\subsection{"Pipeline" Proposal}
|
||||
|
||||
The Pipeline proposal \cite{Pipeline} is a syntactic proposal which focuses on solving problems related to nesting of function calls and other expressions that take an expression as an argument.
|
||||
The "Pipeline" proposal~\cite{Pipeline} is a syntactic proposal which focuses on solving problems related to nesting of function calls and other expressions that take an expression as an argument.
|
||||
|
||||
This proposal aims to solve two problems with performing consecutive operations on a value. In ECMAScript there are two main styles of achieving this functionality currently: nesting calls and chaining calls, each of them come with a differing set of challenges when used.
|
||||
This proposal aims to solve two problems with performing consecutive operations on a value. In \emph{ECMAScript} there are two main styles of achieving this functionality currently: nesting calls and chaining calls, each of them come with a differing set of challenges when used.
|
||||
|
||||
Nesting calls is mainly an issue related to function calls with one or more arguments. When doing many calls in sequence the result will be a \textit{deeply nested} call expression.
|
||||
|
||||
Using nested calls has some specific challenges related to readability when used. The order of calls go from right to left, which is opposite of the natural reading direction a lot of the users of ECMAScript are used to day to day. This means it is difficult to switch the reading direction when working out which call happens in which order. When using functions with multiple arguments in the middle of the nested call, it is not intuitive to see what call its arguments belong to. These issues are the main challenges this proposal is trying to solve. On the other hand, nested calls can be simplified by using temporary variables. While this does introduce its own set of issues, it provides some way of mitigating the readability problem. Another positive side of nested calls is they do not require a specific design to be used, and a library developer does not have to design their library around this specific call style.
|
||||
Using nested calls has some specific challenges related to readability. The order of calls is from right to left, which is the opposite of the natural reading direction a lot of the users of ECMAScript are used to day to day. This means it is difficult to switch the reading direction when working out which call happens in which order. When using functions with multiple arguments in the middle of the nested call, it is not intuitive to see what call its arguments belong to. These issues are the main challenges this proposal is trying to solve. There are currently ways to improve readability with nested calls, as they can be simplified by using temporary variables. While this does introduce its own set of issues, it provides some way of mitigating the readability problem. Another positive side of nested calls is they do not require a specific design to be used, and a library developer does not have to design their library around this specific call style.
|
||||
|
||||
\noindent\begin{minipage}{.45\textwidth}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
// Deeply nested call with single arguments
|
||||
|
@ -208,7 +209,7 @@ f1(v5, f2(f3(v3, f4(v1, v2)), v4), v6);
|
|||
\end{minipage}\hfil
|
||||
|
||||
|
||||
Chaining solves some of these issues: indeed, as it allows for a more natural reading direction left to right when identifying the sequence of call, arguments are naturally grouped together with their respective function call, and it provides a way of untangling deep nesting. However, executing consecutive operations using chaining has its own set of challenges when used. In order to use chaining, the API of the code being called has to be designed to allow for chaining. This is not always the case however, making use of chaining when it has not been specifically designed for can be very difficult. There are also concepts in JavaScript not supported when using chaining, such as arithmetic operations, literals, \texttt{await} expressions, \texttt{yield} expressions and so on. This proves to be a significant downside of chaining, as it only allows for function calls when used, and if one wants to allow for use of other concepts temporary variables have to be used.
|
||||
Chaining solves some of these issues: indeed, as it allows for a more natural reading direction left to right when identifying the sequence of call, arguments are naturally grouped together with their respective function call, and it provides a way of untangling deep nesting. However, executing consecutive operations using chaining has its own set of challenges. To use chaining, the API of the code being called has to be designed to allow for chaining. This is not always the case however, making use of chaining when it has not been specifically designed for can be very difficult. There are also concepts in JavaScript not supported when using chaining, such as arithmetic operations, literals, \texttt{await} expressions, \texttt{yield} expressions and so on. This is because all of these concept would "break the chain", and one would have to use temporary variables.
|
||||
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
// Chaining calls
|
||||
|
@ -218,11 +219,11 @@ function1().function2().function3();
|
|||
function1(value1).function2().function3(value2).function4();
|
||||
\end{lstlisting}
|
||||
|
||||
The Pipeline proposal\cite{Pipeline} aims to combine the benefits of these two styles without the challenges each method faces.
|
||||
|
||||
The "Pipeline" proposal aims to combine the benefits of these two styles without the challenges each method faces.
|
||||
~
|
||||
The main benefit of the proposal is to allow for a similar style to chaining when chaining has not been specifically designed to be applicable. The essential idea is to use syntactic sugar to change the writing order of the calls without influencing the API of the functions. Doing so will allow each call to come in the direction of left to right, while still maintaining the modularity of deeply nested function calls.
|
||||
|
||||
The proposal introduces a \emph{pipe operator}, which takes the result of an expression on the left, and pipes it into an expression on the right. The location of where the result is piped to is where the topic token is located. All the specifics of the exact token used as a topic token and exactly what operator will be used as the pipe operator might be subject to change, and is currently under discussion \cite{PipelineBikeshedding}.
|
||||
The proposal introduces a \emph{pipe operator}, which takes the result of an expression on the left, and pipes it into an expression on the right. The location of where the result is piped to is where the topic token is located. All the specifics of the exact token used as a topic token and exactly what operator will be used as the pipe operator might be subject to change, and is currently under discussion~\cite{PipelineBikeshedding}.
|
||||
|
||||
The code snippets below showcase the machinery of the proposal.
|
||||
|
||||
|
@ -239,6 +240,8 @@ var loc = grunt.config('uglify.all') |> Object.keys(%)[0];
|
|||
\end{lstlisting}
|
||||
\end{minipage}\hfil
|
||||
|
||||
More intuitive ordering of function calls, to know exactly the order of execution.
|
||||
|
||||
\noindent\begin{minipage}{.45\textwidth}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
// Status quo
|
||||
|
@ -253,6 +256,8 @@ const json = pkgs[0] |> npa(%).escapedName |> await npmFetch.json(%, opts);
|
|||
\end{lstlisting}
|
||||
\end{minipage}\hfil
|
||||
|
||||
Seeing which argument is passed to which function call is is simpler when using pipes.
|
||||
|
||||
\noindent\begin{minipage}{.45\textwidth}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
// Status quo
|
||||
|
@ -266,6 +271,7 @@ return cb(predicate) |> _.negate(%) |> _.filter(obj, %, context);
|
|||
\end{lstlisting}
|
||||
\end{minipage}\hfil
|
||||
|
||||
Can be used with any number of function arguments, as long as a single topic token is used.
|
||||
|
||||
\noindent\begin{minipage}{.45\textwidth}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
|
@ -283,13 +289,15 @@ return xf
|
|||
\end{lstlisting}
|
||||
\end{minipage}\hfil
|
||||
|
||||
The pipe operator is not a new concept, and is present in many other languages such as F\# \cite{FPipeOperator} and Julia\cite{JuliaPipe} where the pipe operator is \texttt{|\>}. The main difference between the Julia and F\# pipe operator compared to this proposal, is the result of the left side expression has to be piped into a function with a single argument, the proposal suggests a topic reference to be used in stead of requiring a function.
|
||||
Complex call expressions are unraveled with pipes.
|
||||
|
||||
\subsection{Do Expressions}
|
||||
The pipe operator is present in many other languages such as F\#~\cite{FPipeOperator} and Julia~\cite{JuliaPipe}. The main difference between the Julia and F\# pipe operator compared to this proposal, is the result of the left side expression has to be piped into a function with a single argument, the proposal suggests a topic reference to be used in stead of requiring a function. ~
|
||||
|
||||
The Do Expressions\cite{Proposal:DoProposal} proposal, is a proposal meant to bring a style of \textit{expression oriented programming}\cite{ExpressionOriented} to ECMAScript. Expression oriented programming is a concept taken from functional programming which allows for combining expressions in a very free manor allowing for a highly malleable programming experience.
|
||||
\subsection{"Do Expression"}
|
||||
|
||||
The motivation of the "Do expression" proposal is to allow for local scoping of a code block that is treated as an expression. Thus, complex code requiring multiple statements will be confined inside its own scope\cite{ScopeECMA-262} and the resulting value is returned from the block implicitly as an expression, similarly to how a unnamed functions or arrow functions are currently used. In order to achieve this behavior in the current stable version of ECMAScript, one needs to use unnamed functions and invoke them immediately, or use an arrow function.
|
||||
The "Do Expression"~\cite{Proposal:DoProposal} proposal, is a proposal meant to bring a style of \textit{expression oriented programming}~\cite{ExpressionOriented} to ECMAScript. Expression oriented programming is a concept taken from functional programming which allows for combining expressions in a very free manner, resulting in a highly malleable programming experience.
|
||||
|
||||
The motivation of the "Do Expression" proposal is to allow for local scoping of a code block that is treated as an expression. Thus, complex code requiring multiple statements will be confined inside its own scope~\cite[8.2]{ecma262} and the resulting value is returned from the block implicitly as an expression, similarly to how a unnamed functions or arrow functions are currently used. In order to achieve this behavior in the current stable version of ECMAScript, one needs to use immediately invoked unnamed functions~\cite[15.2]{ecma262} and invoke them immediately, or use an arrow function~\cite[15.3]{ecma262}.
|
||||
|
||||
The codeblock of a \texttt{do} expression has one major difference from these equivalent functions, as it allows for implicit return of the final statement of the block, and is the resulting value of the entire \texttt{do} expression. The local scoping of this feature allows for a cleaner environment in the parent scope of the \texttt{do} expression. What is meant by this is for temporary variables and other assignments used once can be enclosed inside a limited scope within the \texttt{do} block. Allowing for a cleaner environment inside the parent scope where the \texttt{do} block is defined.
|
||||
|
||||
|
@ -336,10 +344,10 @@ let x = do {
|
|||
|
||||
\subsection{Await to Promise}
|
||||
|
||||
We discuss now an imaginary proposal that was used as a running example during the development of this thesis. This proposal is of just a pure JavaScript transformation example. The transformation this proposal is meant to display, is transforming a code using \texttt{await}\cite{Await}, into code which uses a promise\cite{Promise}.
|
||||
We discuss now an imaginary proposal that was used as a running example during the development of this thesis. This proposal is of just a pure JavaScript transformation example. The transformation this proposal is meant to display, is transforming a code using \texttt{await}~\cite[27.7.5.3]{ecma262}, into code which uses a promise~\cite[27.2]{ecma262}.
|
||||
|
||||
|
||||
To perform this transformation, we define an equivalent way of expressing an \texttt{await} expression as a promise. The equivalent way of expressing \texttt{await} with a promise, is removing \texttt{await} from the expression, this expression now will return a promise, which has a function \texttt{then()}, this function is executed when the promise resolves. We pass an arrow function as argument to \texttt{then()}, and append each following statement in the current scope\cite{ScopeECMA-262} inside the block of that arrow function. This will result in equivalent behavior to using \texttt{await}.
|
||||
To perform this transformation, we define an equivalent way of expressing an \texttt{await} expression as a promise. The equivalent way of expressing \texttt{await} with a promise, is removing \texttt{await} from the expression, this expression now will return a promise, which has a function \texttt{then()}, this function is executed when the promise resolves. We pass an arrow function as argument to \texttt{then()}, and append each following statement in the current scope~\cite[8.2]{ecma262} inside the block of that arrow function. This will result in equivalent behavior to using \texttt{await}.
|
||||
|
||||
\noindent\begin{minipage}{.45\textwidth}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
|
@ -375,7 +383,7 @@ In order to identify snippets of code in the user's code where a proposal is app
|
|||
|
||||
\paragraph*{Proposal Definition}
|
||||
|
||||
\DSL is designed to mimic the examples already provided in proposal descriptions \cite{TC39Process}. These examples can be seen in each of the proposals described in Section \ref{sec:proposals}. The idea is to allow a similar kind of notation to the examples in order to define the transformations.
|
||||
\DSL is designed to mimic the examples already provided in proposal descriptions~\cite{TC39Process}. These examples can be seen in each of the proposals described in Section \ref{sec:proposals}. The idea is to allow a similar kind of notation to the examples in order to define the transformations.
|
||||
|
||||
The first part of \DSL is defining the proposal, this is done by creating a named block containing all definitions of templates used for matching alongside their respective transformation. This section is used to contain everything relating to a specific proposal and is meant for easy proposal identification by tooling.
|
||||
|
||||
|
@ -447,11 +455,11 @@ Showcasing a proposal using a user's code requires some way of identifying appli
|
|||
|
||||
In order to identify sections of code a proposal is applicable to, we use \emph{templates}, which are snippets of JavaScript. These templates are used to identify and match applicable sections of a users code. A matching section for a template is one that produces an exactly equal AST structure, where each node of the AST sections has the same information contained within it. This means that templates are matched exactly against the users code, this does not really provide some way of querying the code and performing context based transformations, so for that we use \textit{wildcards} within the template.
|
||||
|
||||
Wildcards are interspliced into the template inside a block denoted by \texttt{$<$$<$ $>$$>$}. Each wildcard starts with an identifier, which is a way of referring to that wildcard in the definition of the transformation template later. This allows for transferring the context of parts matched to a wildcard into the transformed output, like identifiers, parts of statements, or even entire statements, can be transferred from the original user code into the transformation template. A wildcard also contains a type expression. A type expression is a way of defining exactly the types of AST nodes a wildcard will produce a match against. These type expressions use Boolean logic together with the AST node-types from BabelJS\cite{Babel} to create a very versatile of defining exactly what nodes a wildcard can match against.
|
||||
Wildcards are interspliced into the template inside a block denoted by \texttt{$<$$<$ $>$$>$}. Each wildcard starts with an identifier, which is a way of referring to that wildcard in the definition of the transformation template later. This allows for transferring the context of parts matched to a wildcard into the transformed output, like identifiers, parts of statements, or even entire statements, can be transferred from the original user code into the transformation template. A wildcard also contains a type expression. A type expression is a way of defining exactly the types of AST nodes a wildcard will produce a match against. These type expressions use Boolean logic together with the AST node-types from BabelJS~\cite{Babel} to create a very versatile of defining exactly what nodes a wildcard can match against.
|
||||
|
||||
\subsubsection*{Wildcard type expressions}
|
||||
|
||||
Wildcard expressions are used to match AST node types based on Boolean logic. This means an expression can be as simple as \texttt{VariableDeclaration}: this will match only against a node of type \texttt{VariableDeclaration}. Every type used in these expressions are compared against the AST node types from Babel\cite{Babel}, meaning every AST node type is supported. We also include the types \texttt{Statement} for matching against a statement, and \texttt{Expression} for matching any expression. The expressions also support binary and unary operators, an example \texttt{Statement \&\& !ReturnStatement} will match any statement which is not of type \texttt{ReturnStatement}. The expressions support the following operators, \texttt{\&\&} is logical AND, this means both parts of the expression have to evaluate to true, \texttt{||} means logical OR, so either side of expression can be true for the entire expression to be true, \texttt{!} is the only unary expression, and is logical NOT, so \texttt{!Statement} is any node that is NOT a Statement. The wildcards support matching multiple sibling nodes, this is done by using \texttt{(expr)+}, this is only valid at the top level of the expression. This is useful for matching against a series of one or more Statements, while not wanting to match an entire \texttt{BlockStatement}, this is written as \texttt{(Statement \&\& !ReturnStatement)+}.
|
||||
Wildcard expressions are used to match AST node types based on Boolean logic. This means an expression can be as simple as \texttt{VariableDeclaration}: this will match only against a node of type \texttt{VariableDeclaration}. Every type used in these expressions are compared against the AST node types from Babel~\cite{Babel}, meaning every AST node type is supported. We also include the types \texttt{Statement} for matching against a statement, and \texttt{Expression} for matching any expression. The expressions also support binary and unary operators, an example \texttt{Statement \&\& !ReturnStatement} will match any statement which is not of type \texttt{ReturnStatement}. The expressions support the following operators, \texttt{\&\&} is logical AND, this means both parts of the expression have to evaluate to true, \texttt{||} means logical OR, so either side of expression can be true for the entire expression to be true, \texttt{!} is the only unary expression, and is logical NOT, so \texttt{!Statement} is any node that is NOT a Statement. The wildcards support matching multiple sibling nodes, this is done by using \texttt{(expr)+}, this is only valid at the top level of the expression. This is useful for matching against a series of one or more Statements, while not wanting to match an entire \texttt{BlockStatement}, this is written as \texttt{(Statement \&\& !ReturnStatement)+}.
|
||||
|
||||
|
||||
\begin{lstlisting}
|
||||
|
@ -485,9 +493,9 @@ transform to {
|
|||
|
||||
\subsection{Using \DSL}
|
||||
|
||||
\DSL is designed to be used in tandem with proposal development, this means the users of \DSL will most likely be contributors to TC39\cite{TC39} or member of TC39.
|
||||
\DSL is designed to be used in tandem with proposal development, this means the users of \DSL will most likely be contributors to TC39~\cite{TC39} or member of TC39.
|
||||
|
||||
\DSL is designed to closely mimic the style of the examples required in the TC39 process\cite{TC39Process}. We chose to design it this way to specifically make this tool fit the use-case of the committee. The idea behind this project is to gather early user feedback on syntactic proposals, this would mean the main users of this kind of tool is the committee themselves.
|
||||
\DSL is designed to closely mimic the style of the examples required in the TC39 process~\cite{TC39Process}. We chose to design it this way to specifically make this tool fit the use-case of the committee. The idea behind this project is to gather early user feedback on syntactic proposals, this would mean the main users of this kind of tool is the committee themselves.
|
||||
|
||||
\DSL is just written using text, most modern Domain-specific languages have some form of tooling in order to make the process of using the DSL simpler and more intuitive. \DSL has an extension built for Visual Studio Code, see Figure \ref{fig:ExtensionExample}, this extension supports many common features of language servers, it supports auto completion, it will produce errors if fields are defined wrong or missing parameters. The extension performs validation of the wildcards, such as checking for wildcards with missing type parameters,wrong expression definitions, or usage of undeclared wildcards, a demonstration of this can be seen in \ref{fig:ExtensionError}.
|
||||
|
||||
|
@ -507,10 +515,10 @@ This section contains the definitions of the proposals used to evaluate the tool
|
|||
|
||||
\subsection{"Pipeline" Proposal}
|
||||
|
||||
The Pipeline proposal is the first we define of the proposals presented in Section \ref{sec:proposals}. This is due to the proposal being applicable to function calls, which is used all across JavaScript. This proposal is trying to solve readability when performing deeply nested function calls.
|
||||
The "Pipeline" proposal is the first we define of the proposals presented in Section \ref{sec:proposals}. This is due to the proposal being applicable to function calls, which is used all across JavaScript. This proposal is trying to solve readability when performing deeply nested function calls.
|
||||
|
||||
|
||||
\begin{lstlisting}[language={JavaScript}, caption={Example of Pipeline Proposal definition in \DSL}, label={def:pipeline}]
|
||||
\begin{lstlisting}[language={JavaScript}, caption={Example of "Pipeline" proposal definition in \DSL}, label={def:pipeline}]
|
||||
proposal Pipeline {
|
||||
|
||||
case SingleArgument {
|
||||
|
@ -539,7 +547,7 @@ In the Listing \ref{def:pipeline}, the first pair definition \texttt{SingleArgum
|
|||
|
||||
\subsection{"Do Expressions" Proposal}
|
||||
|
||||
The "Do Expressions" proposal\cite{Proposal:DoProposal} can be specified in our tool. Due to the nature of the proposal, it is not as applicable as the "Pipeline" proposal, as it does not re-define a style that is used quite as frequently as call expressions. This means the amount of transformed code snippets this specification in \DSL will be able to perform is expected to be lower. This is due to the Do Proposal introducing an entirely new way to write expression-oriented code in JavaScript. If the user running this tool has not used the current way of writing in an expression-oriented style in JavaScript, \DSL is limited in the amount of transformations it can perform. Nevertheless, if the user has been using an expression-oriented style, \DSL will transform parts of the code.
|
||||
The "Do Expressions" proposal~\cite{Proposal:DoProposal} can be specified in our tool. Due to the nature of the proposal, it is not as applicable as the "Pipeline" proposal, as it does not re-define a style that is used quite as frequently as call expressions. This means the amount of transformed code snippets this specification in \DSL will be able to perform is expected to be lower. This is due to the Do Proposal introducing an entirely new way to write expression-oriented code in JavaScript. If the user running this tool has not used the current way of writing in an expression-oriented style in JavaScript, \DSL is limited in the amount of transformations it can perform. Nevertheless, if the user has been using an expression-oriented style, \DSL will transform parts of the code.
|
||||
|
||||
\begin{lstlisting}[language={JavaScript}, caption={Definition of Do Proposal in \DSL}, label={def:doExpression}]
|
||||
proposal DoExpression {
|
||||
|
@ -577,7 +585,7 @@ proposal DoExpression {
|
|||
}
|
||||
\end{lstlisting}
|
||||
|
||||
In Listing \ref{def:doExpression}, the specification of "Do Expression" proposal in \DSL can be seen. It has two cases: the first case \texttt{arrowFunction}, applies to a code snippet using an arrow function\cite{ArrowFunction} with a return value. The wildcards of this template are \texttt{statements}, which is a wildcard that matches against one or more statements that are not of type \texttt{ReturnStatement}, the reason we limit the one or more match is we cannot match the final statement of the block to this wildcard, as that has to be matched against the return statement in the template. The second wildcard \texttt{returnVal} matches against any expressions. The reason for extracting the expression from the \texttt{return} statement, is to use it in the implicit return of the \texttt{do} block. In the transformation template, we replace the arrow function with with a \texttt{do} expression, this do expression has to be defined inside parenthesis, as a free floating do expression is not allowed due to ambiguous parsing against a \texttt{do {} while()} statement. We and insert the statements matched against \texttt{statements} wildcard into the block of the \texttt{do} expression, and the final statement of the block is the expression matched against the \texttt{returnVal} wildcard. This will produce an equivalent transformation of an arrow function into a \texttt{do} expression. The second case \texttt{immediatelyInvokedAnonymousFunction} follows the same principle as the first case, but is applied to immediately invoked anonymous functions, and produces the exact same output after the transformation as the first case. This is because immediately invoked anonymous functions are equivalent to arrow functions.
|
||||
In Listing \ref{def:doExpression}, the specification of "Do Expression" proposal in \DSL can be seen. It has two cases: the first case \texttt{arrowFunction}, applies to a code snippet using an arrow function~\cite[15.3]{ecma262} with a return value. The wildcards of this template are \texttt{statements}, which is a wildcard that matches against one or more statements that are not of type \texttt{ReturnStatement}, the reason we limit the one or more match is we cannot match the final statement of the block to this wildcard, as that has to be matched against the return statement in the template. The second wildcard \texttt{returnVal} matches against any expressions. The reason for extracting the expression from the \texttt{return} statement, is to use it in the implicit return of the \texttt{do} block. In the transformation template, we replace the arrow function with with a \texttt{do} expression, this do expression has to be defined inside parenthesis, as a free floating do expression is not allowed due to ambiguous parsing against a \texttt{do {} while()} statement. We and insert the statements matched against \texttt{statements} wildcard into the block of the \texttt{do} expression, and the final statement of the block is the expression matched against the \texttt{returnVal} wildcard. This will produce an equivalent transformation of an arrow function into a \texttt{do} expression. The second case \texttt{immediatelyInvokedAnonymousFunction} follows the same principle as the first case, but is applied to immediately invoked anonymous functions, and produces the exact same output after the transformation as the first case. This is because immediately invoked anonymous functions are equivalent to arrow functions.
|
||||
|
||||
|
||||
\subsection{"Await to Promise" imaginary proposal}
|
||||
|
@ -587,17 +595,17 @@ The imaginary proposal "Await to Promise" is created to transform code snippets
|
|||
This proposal was created in order to evaluate the tool, as it is quite difficult to define applicable code in this current template form. This definition is designed to create matches in code using await, and highlight how await could be written using a promise in stead. This actually highlights some of the issues with the current design of \DSL that will be described in Future Work.
|
||||
|
||||
\begin{lstlisting}[language={JavaScript}, caption={Definition of Await to Promise evaluation proposal in \DSL}, label={def:awaitToPromise}]
|
||||
proposal awaitToPromise {
|
||||
proposal awaitToPomise{
|
||||
case single{
|
||||
applicable to {
|
||||
"let <<ident:Identifier>> = await <<awaitedExpr: Expression>>;
|
||||
<<statements: (Statement && !ReturnStatement)*>>
|
||||
<<statements: (Statement && !ReturnStatement && !ContinueStatement &&!BreakStatement)+>>
|
||||
return <<returnExpr: Expression>>
|
||||
"
|
||||
}
|
||||
|
||||
transform to{
|
||||
"return <<awaitedExpr>>.then((<<ident>>) => {
|
||||
"return <<awaitedExpr>>.then(async <<ident>> => {
|
||||
<<statements>>
|
||||
return <<returnExpr>>
|
||||
});"
|
||||
|
@ -606,7 +614,9 @@ proposal awaitToPromise {
|
|||
}
|
||||
\end{lstlisting}
|
||||
|
||||
The specification of "Await to Promise" in \DSL is created to match asynchronous code inside a function. It is limited to match asynchronous functions containing a single await statement, and that await statement has to be stored in a \texttt{VariableDeclaration}. The second wildcard \texttt{statements}, is designed to match all statements following the \texttt{await} statement up to the return statement. This is done to move the statements into the callback function of \texttt{then()} in the transformation.
|
||||
The specification of "Await to Promise" in \DSL is created to match asynchronous code inside a function. It is limited to match asynchronous functions containing a single await statement, and that await statement has to be stored in a \texttt{VariableDeclaration}. The second wildcard \texttt{statements}, is designed to match all statements following the \texttt{await} statement up to the return statement. This is done to move the statements into the callback function of \texttt{then()} in the transformation. We include \texttt{\!ReturnStatement} because we do not want to consume the return as it would then be removed from the functions scope and into the callback function of \texttt{then()}. We also have to avoid matching where there exists loop specific statements such as \texttt{ContinueStatement} or \texttt{BreakStatement}.
|
||||
|
||||
The transformation definition has to use an async function in \texttt{.then()}, as there might be more await expressions contained within \texttt{statements}.
|
||||
|
||||
\section{\DSLSH}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ In this section, the implementation of the parser for \DSL will be described. Th
|
|||
|
||||
\subsection{Langium}
|
||||
|
||||
Langium \cite{Langium} is a language workbench primarily used to create parsers and Integrated Development Environments for domain specific languages. These kinds of parsers produce Abstract Syntax Trees that is later used to create interpreters or other tooling. In this project, we use Langium to generate an AST definition in the form of TypeScript Objects. These objects and their structure are used as definitions for the tool to do matching and transformation of user code.
|
||||
Langium~\cite{Langium} is a language workbench primarily used to create parsers and Integrated Development Environments for domain specific languages. These kinds of parsers produce Abstract Syntax Trees that is later used to create interpreters or other tooling. In this project, we use Langium to generate an AST definition in the form of TypeScript Objects. These objects and their structure are used as definitions for the tool to do matching and transformation of user code.
|
||||
|
||||
In order to generate this parser, Langium requires a definition of a grammar. A grammar is a specification that describes a valid program. The \DSL grammar describes the structure of \DSL, such as \texttt{proposals}, \texttt{cases}, \texttt{applicable to}, and \texttt{transform to}. A grammar in Langium starts by describing the \texttt{Model}. The model is the top entry of the grammar, this is where the description of all valid top level statements.
|
||||
|
||||
|
@ -209,7 +209,7 @@ export function parseInternal(code: string): InternalParseResult {
|
|||
|
||||
\paragraph*{Parsing wildcard}
|
||||
|
||||
Once a wildcard has been extracted from definitions inside \DSL, they have to be parsed into a simple Tree to be used when matching against the wildcard. This is accomplished by using a simple tokenizer and a \cite{RecursiveDescent}{recursive descent parser}.
|
||||
Once a wildcard has been extracted from definitions inside \DSL, they have to be parsed into a simple Tree to be used when matching against the wildcard. This is accomplished by using a simple tokenizer and a~\cite{RecursiveDescent}{recursive descent parser}.
|
||||
|
||||
Our tokenizer takes the raw stream of input characters extracted from the wildcard block within the template, and determines which part is what token. Due to the very simple nature of the type expressions, no ambiguity is present with the tokens, so determining what token is meant to come at what time is quite trivial. We use a switch case on the current token, if the token is of length one we accept it and move on to the next character. If the next character is an unexpected one it will produce an error. The tokenizer also groups tokens with a \textit{token type}, this allows for an simpler parsing of the tokens later.
|
||||
|
||||
|
@ -243,7 +243,7 @@ GroupExpr:
|
|||
|
||||
The grammar of the type expressions used by the wildcards can be seen in \figFull[ex:grammarTypeExpr], the grammar is written in something similar to Extended Backus-Naur form, where we define the terminals and non-terminals in a way that makes the entire grammar \textit{solvable} by the Recursive Descent parser.
|
||||
|
||||
Our recursive descent parser produces an \cite{AST1,AST2}{AST} which is later used to determine when a wildcard can be matched against a specific AST node, the full definition of this AST can be seen in Appendix \ref{ex:typeExpressionTypes}. We use this AST by traversing it using a \cite{VisitorPattern}{visitor pattern} and comparing each \texttt{Identifier} against the specific AST node we are currently checking, and evaluating all subsequent expressions and producing a boolean value, if this value is true, the node is matched against the wildcard, if not then we do not have a match.
|
||||
Our recursive descent parser produces an~\cite{AST1,AST2}{AST} which is later used to determine when a wildcard can be matched against a specific AST node, the full definition of this AST can be seen in Appendix \ref{ex:typeExpressionTypes}. We use this AST by traversing it using a~\cite{VisitorPattern}{visitor pattern} and comparing each \texttt{Identifier} against the specific AST node we are currently checking, and evaluating all subsequent expressions and producing a boolean value, if this value is true, the node is matched against the wildcard, if not then we do not have a match.
|
||||
|
||||
|
||||
|
||||
|
@ -260,14 +260,14 @@ The reason this is preferred is it allows us to avoid having to extract the wild
|
|||
\section{Using Babel to parse}
|
||||
\label{sec:BabelParse}
|
||||
|
||||
Allowing the tool to perform transformations of code requires the generation of an Abstract Syntax Tree from the users code, \texttt{applicable to} and \texttt{transform to}. This means parsing JavaScript into an AST, in order to do this we use a tool \cite[Babel]{Babel}.
|
||||
Allowing the tool to perform transformations of code requires the generation of an Abstract Syntax Tree from the users code, \texttt{applicable to} and \texttt{transform to}. This means parsing JavaScript into an AST, in order to do this we use a tool~\cite[Babel]{Babel}.
|
||||
|
||||
The most important reason for choosing to use Babel for the purpose of generating the AST's used for transformation is due to the JavaScript community surrounding Babel. As this tool is dealing with proposals before they are part of JavaScript, a parser that supports early proposals for JavaScript is required. Babel works closely with TC39 to support experimental syntax\cite{BabelProposalSupport} through its plugin system, which allows the parsing of code not yet part of the language.
|
||||
|
||||
|
||||
\subsection*{Custom Tree Structure}
|
||||
|
||||
Performing matching and transformation on each of the sections inside a \texttt{case} definition, they have to be parsed into and AST in order to allow the tool to match and transform accordingly. To do this the tool uses the library \cite[Babel]{Babel} to generate an AST data structure. However, this structure does not suit traversing multiple trees at the same time, this is a requirement for matching and transforming. Therefore we use this Babel AST and transform it into a simple custom tree structure to allow for simple traversal of the tree.
|
||||
Performing matching and transformation on each of the sections inside a \texttt{case} definition, they have to be parsed into and AST in order to allow the tool to match and transform accordingly. To do this the tool uses the library~\cite[Babel]{Babel} to generate an AST data structure. However, this structure does not suit traversing multiple trees at the same time, this is a requirement for matching and transforming. Therefore we use this Babel AST and transform it into a simple custom tree structure to allow for simple traversal of the tree.
|
||||
|
||||
As can be seen in \figFull[def:TreeStructure] we use a recursive definition of a \texttt{TreeNode} where a nodes parent either exists or is null (it is top of tree), and a node can have any number of children elements. This definition allows for simple traversal both up and down the tree. Which means traversing two trees at the same time can be done in the matcher and transformer section of the tool.
|
||||
|
||||
|
@ -286,9 +286,9 @@ export class TreeNode<T> {
|
|||
}
|
||||
\end{lstlisting}
|
||||
|
||||
Placing the AST generated by Babel into this structure means utilizing the library \cite{BabelTraverse}{Babel Traverse}. Babel Traverse uses the \cite{VisitorPattern}{visitor pattern} to allow for traversal of the AST. While this method does not suit traversing multiple trees at the same time, it allows for very simple traversal of the tree in order to place it into our simple tree structure.
|
||||
Placing the AST generated by Babel into this structure means utilizing the library~\cite{BabelTraverse}{Babel Traverse}. Babel Traverse uses the~\cite{VisitorPattern}{visitor pattern} to allow for traversal of the AST. While this method does not suit traversing multiple trees at the same time, it allows for very simple traversal of the tree in order to place it into our simple tree structure.
|
||||
|
||||
\cite{BabelTraverse}{Babel Traverse} uses the \cite{VisitorPattern}{visitor pattern} to visit each node of the AST in a \textit{depth first} manner, the idea of this pattern is one implements a \textit{visitor} for each of the nodes in the AST and when a specific node is visited, that visitor is then used. In the case of transferring the AST into our simple tree structure we simply have to use the same visitor for all nodes, and place that node into the tree.
|
||||
\cite{BabelTraverse}{Babel Traverse} uses the~\cite{VisitorPattern}{visitor pattern} to visit each node of the AST in a \textit{depth first} manner, the idea of this pattern is one implements a \textit{visitor} for each of the nodes in the AST and when a specific node is visited, that visitor is then used. In the case of transferring the AST into our simple tree structure we simply have to use the same visitor for all nodes, and place that node into the tree.
|
||||
|
||||
Visiting a node using the \texttt{enter()} function means we went from the parent to that child node, and it should be added as a child node of the parent. The node is automatically added to its parent list of children nodes from the constructor of \texttt{TreeNode}. Whenever leaving a node the function \texttt{exit()} is called, this means we are moving back up into the tree, and we have to update what node was the \textit{last} in order to generate the correct tree structure.
|
||||
|
||||
|
@ -488,7 +488,7 @@ return [currentPair, Match];
|
|||
|
||||
\subsection{Matching multiple Statements}
|
||||
|
||||
Using multiple statements in the template of \texttt{applicable to} means the tree of \texttt{applicable to} as multiple root nodes, to perform a match with this kind of template, we use a sliding window\cite{SlidingWindow} with size equal to the amount statements in the template. This window is applied at every \textit{BlockStatement} and \texttt{Program} of the code AST, as that is the only placement statements can reside in JavaScript\cite{ECMA262Statement}.
|
||||
Using multiple statements in the template of \texttt{applicable to} means the tree of \texttt{applicable to} as multiple root nodes, to perform a match with this kind of template, we use a sliding window\cite{SlidingWindow} with size equal to the amount statements in the template. This window is applied at every \textit{BlockStatement} and \texttt{Program} of the code AST, as that is the only placement statements can reside in JavaScript~\cite[14]{ecma262}.
|
||||
|
||||
The initial step of this algorithm is to search through the AST for ast nodes that contain a list of \textit{Statements}. Searching the tree is done by Depth-First search, at every level of the AST, we check the type of the node. Once a node of type \texttt{BlockStatement} or \texttt{Program} is discovered, we start the trying to match the statements.
|
||||
|
||||
|
@ -508,7 +508,7 @@ multiStatementMatcher(code, aplTo) {
|
|||
|
||||
\end{lstlisting}
|
||||
|
||||
\texttt{matchMultiHead} uses a sliding window \cite{SlidingWindow}. The sliding window will try to match every statement of the code AST against its corresponding statement in the \texttt{applicable to} AST. For every statement, we perform a DFS recursion algorithm is applied, similar to algorithm used in Section \ref{sec:singleMatcher}, however this search is not applied to all levels, and if it matches it has to match fully and immediately. If a match is not found, the current iteration of the sliding window is discarded and we move on to the next iteration by moving the window one further.
|
||||
\texttt{matchMultiHead} uses a sliding window~\cite{SlidingWindow}. The sliding window will try to match every statement of the code AST against its corresponding statement in the \texttt{applicable to} AST. For every statement, we perform a DFS recursion algorithm is applied, similar to algorithm used in Section \ref{sec:singleMatcher}, however this search is not applied to all levels, and if it matches it has to match fully and immediately. If a match is not found, the current iteration of the sliding window is discarded and we move on to the next iteration by moving the window one further.
|
||||
|
||||
One important case here is we might not know the width of the sliding window, this is due to wildcards using the Keene plus, as they can match one or more nodes against the wildcard. These wildcards might match against \texttt{(Statement)+}. Therefore, we use a similar technique to the one described in Section \ref{sec:singleMatcher}, where we have two pointers and match each statement depending on each pointer.
|
||||
|
||||
|
@ -534,7 +534,7 @@ export interface Match {
|
|||
|
||||
\section{Transforming}
|
||||
|
||||
To perform the transformation and replacement on each of the matches, we take the resulting list of matches, the template from the \texttt{transform to} section of the current case of the proposal, and the AST version of original code parsed by Babel. All the transformations are then applied to the code and we use \cite{BabelGenerate}{Babel generate} to generate JavaScript code from the transformed AST.
|
||||
To perform the transformation and replacement on each of the matches, we take the resulting list of matches, the template from the \texttt{transform to} section of the current case of the proposal, and the AST version of original code parsed by Babel. All the transformations are then applied to the code and we use~\cite{BabelGenerate}{Babel generate} to generate JavaScript code from the transformed AST.
|
||||
|
||||
An important discovery is to ensure we transform the leafs of the AST first, this is because if the transformation was applied from top to bottom, it might remove transformations done using a previous match. This means if we transform from top to bottom on the tree, we might end up with \texttt{a(b) |> c(\%)} in stead of \texttt{b |> a(\%) |> c(\%)} in the case of the pipeline proposal. This is quite easily solved in our case, as the matcher looks for matches from the top of the tree to the bottom of the tree, the matches it discovers are always in that order. Therefore when transforming, all that has to be done is reverse the list of matches, to get the ones closest to the leaves of the tree first.
|
||||
|
||||
|
@ -542,16 +542,17 @@ An important discovery is to ensure we transform the leafs of the AST first, thi
|
|||
|
||||
The transformations are performed by inserting the matched wildcards from the \texttt{applicable to} template into their respective locations in the \texttt{transform to} template. Then the entire transformed \texttt{transform to} template is placed into the original code AST where the root of the match was previously located. Doing this we are essentially doing a transformation that is a find and replace with context passed through the wildcards.
|
||||
|
||||
First we have to extract every node that was matched against the wildcards in the match. To do this we recursively search through the match until we encounter an \texttt{Identifier} that shares a name with a wildcard. We then take the AST node paired with that wildcard and store it inside a JavaScript \texttt{Map<string, t.Node[]>}.
|
||||
|
||||
First we have to extract every node that was matched against the wildcards in the match. To do this we recursively search through the match until we encounter an \texttt{Identifier} that shares a name with a wildcard.
|
||||
|
||||
To insert all nodes matched against wildcards, we use \texttt{@babel/traverse}\cite{BabelTraverse}, and traverse the AST of the \texttt{transform to} template. We use custom visitors for \textit{Identifier} and \textit{ExpressionStatement} with an \texttt{Identifier} as expression. Each visitor checks if the identifier is a registered wildcard, if it is, we perform a replacement of the \texttt{Identifier} with the node/s the wildcard was matched with.
|
||||
|
||||
|
||||
\subsubsection*{Inserting the template into the AST}
|
||||
|
||||
Having a transformed version of the users code, it has to be inserted into the full AST definition of the users code, again we use \cite{BabelTraverse}{babel/traverse} to traverse the entirety of the code AST using a visitor. This visitor does not apply to any node-type, as the matched section can be any type. Therefore we use a generic visitor, and use an equality check to find the exact part of the code this specific match comes from. Once we find where in the users code the match came from, we replace it with the transformed \texttt{transform to} nodes. This might be multiple statements, therefore the function \texttt{replaceWithMultiple} is used, to insert every Statement from the \texttt{transform to} body, and we are careful to remove any following sibling nodes that were part of the original match. This is done by removing the \textit{n-1} next siblings from where we inserted the transform to template.
|
||||
Having a transformed version of the users code, it has to be inserted into the full AST definition of the users code, again we use~\cite{BabelTraverse}{babel/traverse} to traverse the entirety of the code AST using a visitor. This visitor does not apply to any node-type, as the matched section can be any type. Therefore we use a generic visitor, and use an equality check to find the exact part of the code this specific match comes from. Once we find where in the users code the match came from, we replace it with the transformed \texttt{transform to} nodes. This might be multiple statements, therefore the function \texttt{replaceWithMultiple} is used, to insert every Statement from the \texttt{transform to} body, and we are careful to remove any following sibling nodes that were part of the original match. This is done by removing the \textit{n-1} next siblings from where we inserted the transform to template.
|
||||
|
||||
\subsubsection*{Generating source code from transformed AST}
|
||||
|
||||
To generate JavaScript from the transformed AST created by this tool, we use a JavaScript library titled \cite{BabelGenerate}{babel/generator}. This library is specifically designed for use with Babel to generate JavaScript from a Babel AST. The transformed AST definition of the users code is transformed, while being careful to apply all Babel plugins the current proposal might require.
|
||||
To generate JavaScript from the transformed AST created by this tool, we use a JavaScript library titled~\cite{BabelGenerate}{babel/generator}. This library is specifically designed for use with Babel to generate JavaScript from a Babel AST. The transformed AST definition of the users code is transformed, while being careful to apply all Babel plugins the current proposal might require.
|
||||
|
||||
|
|
234
chapter/ch5.tex
234
chapter/ch5.tex
|
@ -2,60 +2,31 @@
|
|||
|
||||
In this chapter we will discuss how we evaluated \DSL and its related tools. This chapter will include some testing of the tool on demo code snippets, as well as running each of the proposals discussed in this thesis on some large scale JavaScript projects.
|
||||
|
||||
\section*{Testing on code}
|
||||
|
||||
In this section, we will showcase some synthetic transformations applied to code made to fit each of the definitions discussed in this thesis.
|
||||
|
||||
|
||||
The pipeline proposal is meant to merge the readability of chaining with the practicality of deeply nested calls. This deep nesting can be seen in the input code Listing \ref{ex:deepNestingEval}. The resulting code can be seen in Listing \ref{ex:transformedDeepNestingEval}.
|
||||
|
||||
\begin{lstlisting}[language={JavaScript}, label={ex:deepNestingEval}]
|
||||
// Original JavaScript
|
||||
a(a(a(a(a(a(a(b)))))));
|
||||
c(c(c(c(c(d, b), b), b), b), b);
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}, label={ex:transformedDeepNestingEval}]
|
||||
// Transformed
|
||||
b |> a(%) |> a(%) |> a(%) |> a(%) |> a(%) |> a(%) |> a(%);
|
||||
d |> c(%, b) |> c(%, b) |> c(%, b) |> c(%, b) |> c(%, b);
|
||||
\end{lstlisting}
|
||||
|
||||
\section{Real Life source code}
|
||||
|
||||
In order to perform actual large scale trial of this program, we have collected some github projects containing many or large JavaScript files. Every JS file within the project is then passed through the entire tool, and we will evaluate it based upon the amount of matches discovered, as well as manual checking that the transformation resulted in correct code on the matches.
|
||||
|
||||
Each case study was evaluated by running this tool on every .js file in the repository, then collecting the number of matches found in total and how many files were successfully searched. Evaluating if the transformation was correct is done by manually sampling output files, and verifying that it passes through Babel Generate \cite{BabelGenerate} without error. You can see some highlighted transformations in Listing \textbf{INSERT FIGURE HERE}.
|
||||
Each case study was evaluated by running this tool on every .js file in the repository, then collecting the number of matches found in total and how many files were successfully searched. Evaluating if the transformation was correct is done by manually sampling output files, and verifying that it passes through Babel Generate~\cite{BabelGenerate} without error.
|
||||
|
||||
"Pipeline"~\cite{Pipeline} is very applicable to most files, as the concept it touches (fucntion calls) is widely used all across JavaScript. This is by far the best result, and it found matches in almost all files that Babel~\cite{BabelParser} managed to parse.
|
||||
|
||||
"Pipeline"\cite{Pipeline} is clearly very applicable to most files, as it is really only looking for function calls. This is by far the best result, and it found matches in almost all files that Babel \cite{BabelParser} managed to parse.
|
||||
|
||||
The Do proposal \cite{Proposal:DoProposal} is expected to not find many matches, as code that has not been written in expression-oriented programming style will not produce many matches.
|
||||
The Do proposal~\cite{Proposal:DoProposal} is expected to not find as many matches, as code that has not been written in expression-oriented programming style will not produce many matches. However, this also highlights how impactful this proposal is to previously written code compared to "Pipeline".
|
||||
|
||||
Await to promise also has an expected number of matches, but this evaluation proposal is not meant to be real life representative. As it is limited to functions containing only a single await statement and that statement has to be a \texttt{VariableDeclaration}.
|
||||
|
||||
When the amount of files searched is different for each of the proposals, it means either a transformation on that file, or generation of that file failed for some reason. This is probably due to bugs in the transform algorithm that creates this discrepancy.
|
||||
\paragraph*{Next.js}~\cite{NEXT.JS} is one of the largest projects on the web. It is used with React~\cite{React} to enable feature such as server-sire rendering and static site generation.
|
||||
|
||||
\paragraph*{Next.js}\cite{NEXT.JS} is one of the largest projects related to JavaScript. It is owned by Vercel and is used as a development platform for the web.
|
||||
|
||||
\paragraph*{Three.js}\cite{ThreeJS} is a library for 3D rendering in JavaScript. It is written purely in JavaScript and uses GPU for 3D calculations. It being a popular JavaScript library, and being written in mostly pure JavaScript makes it a good case study for our tool. It currently sits at over 1 million downloads weekly.
|
||||
|
||||
\paragraph*{React}\cite{React} is a graphical user interface library for JavaScript, it facilitates the creation of user interfaces for both web and native platforms. React is based upon splitting a user interface into components for simple development. It is currently one of the most popular libraries for creating web apps and has over 223000 stars on Github.
|
||||
|
||||
\paragraph*{Bootstrap}\cite{Bootstrap} is a front-end framework used for creating responsive and mobile-first websites, it comes with a variety of built-in components, as well as a built in styling. This styling is also customizable using CSS. This library is a good evaluation point for this thesis as it is written in pure JavaScript and is used by millions of developers.
|
||||
|
||||
\paragraph*{Atom}\cite{Atom} is a text editor made in JavaScript using the Electron framework. It was created to give a very minimal and modular text editor. It was bought by Microsoft, and later discontinued in favor for Visual Studio Code.
|
||||
|
||||
\begin{figure}
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|c|c|c|}
|
||||
\hline
|
||||
Proposal & Matches found & Files with matches & Files searched\\
|
||||
Proposal & Matches found & Files with matches & Files processed\\
|
||||
\hline \hline
|
||||
Pipeline & 55787 & 1327 & 2331 \\
|
||||
"Pipeline" & 242079 & 1912 & 3340 \\
|
||||
\hline
|
||||
Do & 131 & 74 & 2331 \\
|
||||
"Do" expression & 480 & 111 & 3340 \\
|
||||
\hline
|
||||
Await to Promise & 43 & 38 & 2331 \\
|
||||
Await to Promise & 7000 & 574 & 3340 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
@ -63,17 +34,21 @@ When the amount of files searched is different for each of the proposals, it mea
|
|||
\label{fig:evalNextJS}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
|
||||
|
||||
\paragraph*{Three.js}~\cite{ThreeJS} is a library for 3D rendering in JavaScript. It is written purely in JavaScript and uses GPU for 3D calculations. It being a popular JavaScript library, and being written in mostly pure JavaScript makes it a good case study for our tool. It currently sits at over 1 million downloads weekly.
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|c|c|}
|
||||
\hline
|
||||
Proposal & Matches found & Files with matches & Files searched \\
|
||||
\hline \hline
|
||||
Pipeline & 85050 & 1119 & 1262\\
|
||||
Pipeline & 84803 & 1117 & 1384 \\
|
||||
\hline
|
||||
Do & 278 & 55 & 1385 \\
|
||||
"Do" expression & 277 & 55 & 1384 \\
|
||||
\hline
|
||||
Await to Promise & 125 & 80 & 1262 \\
|
||||
Await to Promise & 186 & 114 & 1384 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
@ -81,17 +56,20 @@ When the amount of files searched is different for each of the proposals, it mea
|
|||
\label{fig:evalThreeJS}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
|
||||
\paragraph*{React}~\cite{React} is a graphical user interface library for JavaScript, it facilitates the creation of user interfaces for both web and native platforms. React is based upon splitting a user interface into components for simple development. It is currently one of the most popular libraries for creating web apps and has over 223000 stars on Github.
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|c|c|}
|
||||
\hline
|
||||
Proposal & Matches found & Files with matches & Files searched\\
|
||||
\hline \hline
|
||||
Pipeline & 16353 & 1266 & 2051 \\
|
||||
"Pipeline" & 16353 & 1266 & 3572 \\
|
||||
\hline
|
||||
Do & 79 & 60 & 2051 \\
|
||||
"Do" expression & 79 & 60 & 2051 \\
|
||||
\hline
|
||||
Await to Promise & 104 & 88 & 2051 \\
|
||||
Await to Promise & 107 & 89 & 3572 \\
|
||||
\hline
|
||||
\end{tabular}
|
||||
\end{center}
|
||||
|
@ -99,15 +77,18 @@ When the amount of files searched is different for each of the proposals, it mea
|
|||
\label{fig:evalReact}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
|
||||
\paragraph*{Bootstrap}~\cite{Bootstrap} is a front-end framework used for creating responsive and mobile-first websites, it comes with a variety of built-in components, as well as a built in styling. This styling is also customizable using CSS. This library is a good evaluation point for this thesis as it is written in pure JavaScript and is used by millions of developers.
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|c|c|}
|
||||
\hline
|
||||
Proposal & Matches found & Files with matches & Files searched\\
|
||||
\hline \hline
|
||||
Pipeline & 13794 & 109 & 115 \\
|
||||
""Pipeline" & 13794 & 109 & 115 \\
|
||||
\hline
|
||||
Do & 13 & 8 & 115 \\
|
||||
"Do" expression & 13 & 8 & 115 \\
|
||||
\hline
|
||||
Await to Promise & 0 & 0 & 115 \\
|
||||
\hline
|
||||
|
@ -117,15 +98,17 @@ When the amount of files searched is different for each of the proposals, it mea
|
|||
\label{fig:evalBootstrap}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}
|
||||
\paragraph*{Atom}~\cite{Atom} is a text editor made in JavaScript using the Electron framework. It was created to give a very minimal and modular text editor. It was bought by Microsoft, and later discontinued in favor for Visual Studio Code.
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{center}
|
||||
\begin{tabular}{|c|c|c|c|}
|
||||
\hline
|
||||
Proposal & Matches found & Files with matches & Files searched\\
|
||||
\hline \hline
|
||||
Pipeline & 40606 & 361 & 401 \\
|
||||
"Pipeline" & 40606 & 361 & 401 \\
|
||||
\hline
|
||||
Do & 46 & 26 & 401 \\
|
||||
"Do" expression & 46 & 26 & 401 \\
|
||||
\hline
|
||||
Await to Promise & 8 & 6 & 401 \\
|
||||
\hline
|
||||
|
@ -133,4 +116,149 @@ When the amount of files searched is different for each of the proposals, it mea
|
|||
\end{center}
|
||||
\caption{Evaluation with Atom source code}
|
||||
\label{fig:evalAtom}
|
||||
\end{figure}
|
||||
\end{figure}
|
||||
|
||||
\subsection{Example transformations}
|
||||
\label{sec:RealLifeTransformations}
|
||||
|
||||
|
||||
\subsection*{Highlights of transformations from evaluation}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
tracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
frameTime
|
||||
|> (jsonTracks[i] |> parseKeyframeTrack(%)).scale(%)
|
||||
|> tracks.push(%);
|
||||
\end{lstlisting}
|
||||
\caption*{Transformation taken from \texttt{three.js/src/animation/AnimationClip.js}}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
const logger = createLogger({
|
||||
storagePath: join(__dirname, '.progress-estimator'),
|
||||
});
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
const logger = {
|
||||
storagePath: __dirname |> join(%, '.progress-estimator')
|
||||
} |> createLogger(%);
|
||||
\end{lstlisting}
|
||||
\caption*{"Pipeline" transformation, taken from \texttt{react/scripts/devtools/utils.js}}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
if (isElement(content)) {
|
||||
this._putElementInTemplate(getElement(content), templateElement)
|
||||
return
|
||||
}
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
if (content |> isElement(%)) {
|
||||
content |> getElement(%) |> this._putElementInTemplate(%, templateElement);
|
||||
return;
|
||||
}
|
||||
\end{lstlisting}
|
||||
\caption*{"Pipeline" transformation, taken from \texttt{bootstrap/js/src/util/template-factory.js}}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
for (const file of typeFiles) {
|
||||
const content = await fs.readFile(join(styledJsxPath, file), 'utf8')
|
||||
await fs.writeFile(join(typesDir, file), content)
|
||||
}
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
for (const file of typeFiles) {
|
||||
const content = await (styledJsxPath |> join(%, file) |> fs.readFile(%, 'utf8'));
|
||||
await (typesDir |> join(%, file) |> fs.writeFile(%, content));
|
||||
}
|
||||
\end{lstlisting}
|
||||
\caption*{"Pipeline" transformation, taken from \texttt{next.js/packages/next/taskfile.js}}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
if (repo && repo.onDidDestroy) {
|
||||
repo.onDidDestroy(() =>
|
||||
this.repositoryPromisesByPath.delete(pathForDirectory)
|
||||
);
|
||||
}
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
if (repo && repo.onDidDestroy) {
|
||||
(() => pathForDirectory |> this.repositoryPromisesByPath.delete(%)) |> repo.onDidDestroy(%);
|
||||
}
|
||||
\end{lstlisting}
|
||||
\caption*{"Pipeline" transformation, taken from \texttt{atom/src/project.js}}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
await check(async () => {
|
||||
const html = await browser.eval('document.documentElement.innerHTML')
|
||||
return html.match(/iframe/) ? 'fail' : 'success'
|
||||
}, /success/)
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
await check(do {
|
||||
const html = await browser.eval('document.documentElement.innerHTML');
|
||||
html.match(/iframe/) ? 'fail' : 'success'
|
||||
}, /success/);
|
||||
\end{lstlisting}
|
||||
\caption*{"Do expression" transformation, taken from \texttt{next.js/test/integration/typescript-hmr/index.test.js}}
|
||||
\end{figure}
|
||||
|
||||
\begin{figure}[H]
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
async function getCurrentRules() {
|
||||
const res = await fetch(
|
||||
`https://api.github.com/repos/vercel/next.js/branches/canary/protection`,
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(
|
||||
`Failed to check for rule ${res.status} ${await res.text()}`
|
||||
)
|
||||
}
|
||||
const data = await res.json()
|
||||
|
||||
return {
|
||||
// Massive JS Object
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
\begin{lstlisting}[language={JavaScript}]
|
||||
async function getCurrentRules() {
|
||||
return fetch(`https://api.github.com/repos/vercel/next.js/branches/canary/protection`, {
|
||||
headers: {
|
||||
Accept: 'application/vnd.github+json',
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
'X-GitHub-Api-Version': '2022-11-28'
|
||||
}
|
||||
}).then(async res => {
|
||||
if (!res.ok) {
|
||||
throw new Error(`Failed to check for rule ${res.status} ${await res.text()}`);
|
||||
}
|
||||
const data = await res.json();
|
||||
return {
|
||||
// Massive JS object
|
||||
};
|
||||
});
|
||||
}
|
||||
\end{lstlisting}
|
||||
\caption*{"Await to Promise" transformation, taken from \texttt{next.js/test/integration/typescript-hmr/index.test.js}}
|
||||
\end{figure}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
\textbf{Provide access and gather feedback}. This project is build upon creating a tool for users of EcmaScript to see new proposals within their own codebase. The idea behind this is to use the users familiarity to showcase new syntactic proposals, and get valuable feedback to the committee developing the ECMA-262 standard. This means making the definitions of a proposal in \DSL and this tool available to end-users to execute using their own code. This can come in multiple forms, we suggest some ideas, such as a playground on the web, an extension for Visual Studio Code, or to be used in github pull requests.
|
||||
|
||||
\textbf{Supporting other languages}. The idea of showcasing changes to a programming language by transforming user code is not only limited to EcmaScript, and could be applied to many other programming languages using a similar developement method to EcmaScript. The developers of a language could write definitions of new changes for their respective language, and use a similar tool to the one discussed in this thesis to showcase possible new changes.
|
||||
\textbf{Supporting other languages}. The idea of showcasing changes to a programming language by transforming user code is not only limited to EcmaScript, and could be applied to many other programming languages using a similar development method to EcmaScript. The developers of a language could write definitions of new changes for their respective language, and use a similar tool to the one discussed in this thesis to showcase possible new changes.
|
||||
|
||||
\textbf{Parameterized specifications}. The current form of \DSL supports writing each template as its own respective case, but multiple templates might be very similar and could be written using generics that are shared between case definitions. Introducing this might give a simpler way of writing more complex definitions of a proposal transformation by re-using generic type parameters for the wildcards used in the transformations.
|
||||
|
||||
|
|
|
@ -78,14 +78,6 @@
|
|||
doi = {10.1145/3093742.3095107}
|
||||
}
|
||||
|
||||
@misc{ECMA262Statement,
|
||||
title = {{ECMAScript{\ifmmode\circledR\else\textregistered\fi} 2025 Language Specification}},
|
||||
year = {2024},
|
||||
month = apr,
|
||||
urldate = {2024-05-13},
|
||||
note = {[Online; accessed 13. May 2024]},
|
||||
url = {https://tc39.es/ecma262/#sec-ecmascript-language-statements-and-declarations}
|
||||
}
|
||||
|
||||
@misc{BabelParser,
|
||||
title = {{@babel/parser {$\cdot$} Babel}},
|
||||
|
@ -338,40 +330,13 @@
|
|||
doi = {10.1145/290229.290237}
|
||||
}
|
||||
|
||||
@misc{ScopeECMA-262,
|
||||
@misc{ecma262,
|
||||
title = {{ECMAScript{\ifmmode\circledR\else\textregistered\fi} 2025 Language Specification}},
|
||||
year = {2024},
|
||||
month = may,
|
||||
urldate = {2024-05-24},
|
||||
note = {[Online; accessed 24. May 2024]},
|
||||
url = {https://tc39.es/ecma262/#sec-syntax-directed-operations-scope-analysis}
|
||||
}
|
||||
|
||||
@misc{CompletionRecord,
|
||||
title = {{ECMAScript{\ifmmode\circledR\else\textregistered\fi} 2025 Language Specification}},
|
||||
year = {2024},
|
||||
month = may,
|
||||
urldate = {2024-05-24},
|
||||
note = {[Online; accessed 24. May 2024]},
|
||||
url = {https://tc39.es/ecma262/#sec-completion-record-specification-type}
|
||||
}
|
||||
|
||||
@misc{Await,
|
||||
title = {{ECMAScript{\ifmmode\circledR\else\textregistered\fi} 2025 Language Specification}},
|
||||
year = {2024},
|
||||
month = may,
|
||||
urldate = {2024-05-24},
|
||||
note = {[Online; accessed 24. May 2024]},
|
||||
url = {https://tc39.es/ecma262/#await}
|
||||
}
|
||||
|
||||
@misc{Promise,
|
||||
title = {{ECMAScript{\ifmmode\circledR\else\textregistered\fi} 2025 Language Specification}},
|
||||
year = {2024},
|
||||
month = may,
|
||||
urldate = {2024-05-24},
|
||||
note = {[Online; accessed 24. May 2024]},
|
||||
url = {https://tc39.es/ecma262/#sec-promise-objects}
|
||||
urldate = {2024-05-28},
|
||||
note = {[Online; accessed 28. May 2024]},
|
||||
url = {https://tc39.es/ecma262}
|
||||
}
|
||||
|
||||
@misc{TC39Process,
|
||||
|
@ -382,14 +347,7 @@
|
|||
note = {[Online; accessed 24. May 2024]},
|
||||
url = {https://tc39.es/process-document}
|
||||
}
|
||||
@misc{ArrowFunction,
|
||||
title = {{ECMAScript{\ifmmode\circledR\else\textregistered\fi} 2025 Language Specification}},
|
||||
year = {2024},
|
||||
month = may,
|
||||
urldate = {2024-05-25},
|
||||
note = {[Online; accessed 25. May 2024]},
|
||||
url = {https://tc39.es/ecma262/multipage/ecmascript-language-functions-and-classes.html#sec-arrow-function-definitions}
|
||||
}
|
||||
|
||||
|
||||
@misc{TC39,
|
||||
title = {{TC39 - Specifying JavaScript.}},
|
||||
|
|
Loading…
Reference in a new issue