mirror of
https://github.com/cincheo/jsweet.git
synced 2025-12-15 07:19:22 +00:00
update language specifications for v2 (WIP)
This commit is contained in:
parent
9871841448
commit
b5ee497366
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -63,7 +63,7 @@
|
||||
|
||||
\begin{document}
|
||||
|
||||
\title{JSweet Language Specifications\\{\large Version 1.2.x}}
|
||||
\title{JSweet Language Specifications\\{\large Version 2.0.x}}
|
||||
\author{%
|
||||
Renaud Pawlak\\
|
||||
{\normalsize renaud.pawlak@jsweet.org}\\
|
||||
@ -76,11 +76,13 @@ Renaud Pawlak\\
|
||||
|
||||
\chapter{Basic concepts}
|
||||
|
||||
This section presents the JSweet language basic concepts. One must keep in mind that JSweet, as a Java-to-JavaScript transpiler, is an extension of Java at compile-time, and executes as JavaScript at runtime. Thus, most Java typing and syntactic constraints will apply at compile time, but some JavaScript semantics may apply at runtime. This document will mention JSweet-specific semantics.
|
||||
This section presents the JSweet language basic concepts. One must keep in mind that JSweet, as a Java-to-JavaScript transpiler, is an extension of Java at compile-time, and executes as JavaScript at runtime. JSweet aims at being a trade-off between Java and JavaScript, by respecting as much as possible the Java semantics, but without loosing interoperability with JavaScript. So, in a way, JSweet can be seen as a fusion between Java and JavaScript, trying to get the best of both worlds in one unique and consistent language. In some cases, it is hard to get the best of both worlds and JSweet makes convenient and practical choices.
|
||||
|
||||
Because JSweet is an open JavaScript transpiler, the user can tune the JavaScript generation without much efforts, thus making other choices than default ones to map Java to JavaScript. For example, if the way JSweet implements Java maps does not suit your context or use case, you can program a JSweet extension to override the default strategy. Programming and activating a JSweet extension is fully explained in Section \ref{extension}.
|
||||
|
||||
\section{Core types and objects}
|
||||
|
||||
JSweet allows the use of primitive Java types, core Java objects and of core JavaScript objects, which are defined in the \texttt{jsweet.lang} package. Next, we describe the use of such core types and objects.
|
||||
JSweet allows the use of primitive Java types, core Java objects (defined in \texttt{java.lang}, many JDK classes (especially \texttt{java.util} but not only), and of core JavaScript objects, which are defined in the \texttt{def.js} package. Next, we describe the use of such core types and objects.
|
||||
|
||||
\subsection{Primitive Java types}
|
||||
|
||||
@ -93,7 +95,7 @@ JSweet allows the use of Java primitive types (and associated literals).
|
||||
\item \texttt{java.lang.String} corresponds to the JavaScript \texttt{string}. (not per say a primitive type, but is immutable and used as the class of string literals in Java)
|
||||
\end{itemize}
|
||||
|
||||
A direct consequence of that conversion is that it is not possible in JSweet to safely overload methods with numbers or chars/strings. For instance, the methods \texttt{pow(int, int)} and \texttt{pow(double, double)} will be considered as the same method at runtime and should not have different implementations for that reason. Also, there will be no difference between \texttt{n instanceof Integer} and \texttt{n instanceof Double}, because it both means \texttt{typeof n === 'number'}. These behavior ensure low impedance between JSweet programs and JavaScript ones.
|
||||
A direct consequence of that conversion is that it is not always possible in JSweet to safely overload methods with numbers or chars/strings. For instance, the methods \texttt{pow(int, int)} and \texttt{pow(double, double)} may raise overloading issues. With a JSweet context, the transpiler will be able to select the right method, but the JavaScript interoperability may be a problem. In short, since there is no difference between \texttt{n instanceof Integer} and \texttt{n instanceof Double} (it both means \texttt{typeof n === 'number'}) calling \texttt{pow(number, number)} from JavaScript will randomly select one implementation or the other. This should not be always a problem, but in some particular cases, it can raise subtle errors. Note that in these cases, the programmers will be able to tune the JavaScript generation, as it is fully explained in Section \ref{extension}.
|
||||
|
||||
\noindent
|
||||
Examples of valid statements:
|
||||
@ -110,288 +112,27 @@ boolean b = false;
|
||||
assert !b;
|
||||
\end{lstlisting}
|
||||
|
||||
Note that since JSweet 1.1.0, the \texttt{==} operator behaves like the JavaScript strict equals operator \texttt{===} so that it is close to the Java semantics. Similarly, \texttt{!=} is mapped to \texttt{!==}. There is an exception to that behavior which is when comparing an object to a \texttt{null} literal. In that case, JSweet translates to the loose equality operators so that the programmers see no distinction between \texttt{null} and \texttt{undefined} (which are different in JavaScript but it may be confusing to Java programmers). To control whether JSweet generates strict or loose operators, you can use the following helper methods: \texttt{jsweet.\-util.\-Globals.\-equalsStrict} (\texttt{===}), \texttt{jsweet.\-util.\-Globals.\-notEqualsStrict} (\texttt{!==}), \texttt{jsweet.\-util.\-Globals.\-equalsLoose} (\texttt{==}), and \texttt{jsweet.\-util.\-Globals.\-notEqualsLoose} (\texttt{!=}). For example:
|
||||
The \texttt{==} operator behaves like the JavaScript strict equals operator \texttt{===} so that it is close to the Java semantics. Similarly, \texttt{!=} is mapped to \texttt{!==}. There is an exception to that behavior which is when comparing an object to a \texttt{null} literal. In that case, JSweet translates to the loose equality operators so that the programmers see no distinction between \texttt{null} and \texttt{undefined} (which are different in JavaScript but it may be confusing to Java programmers). To control whether JSweet generates strict or loose operators, you can use the following helper methods: \texttt{jsweet.\-util.\-Lang.\-\$strict} and \texttt{jsweet.\-util.\-Lang.\-\$loose}. Wrapping a comparison operator in such a macro will force JSweet to generate a strict or loose operator.. For example:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.equalsLoose;
|
||||
import static jsweet.util.Lang.$loose;
|
||||
[...]
|
||||
int i = 2;
|
||||
assert i == 2; // generates i === 2
|
||||
assert !((Object)"2" == i);
|
||||
assert equalsLoose("2", i); // generates "2" == i
|
||||
assert $loose((Object)"2" == i); // generates "2" == i
|
||||
\end{lstlisting}
|
||||
|
||||
\subsection{Allowed Java objects}
|
||||
|
||||
By default, JSweet maps core Java objects and methods to JavaScript through the use of built-in macros. It means that the Java code is directly substituted with a valid JavaScript code that implements similar behavior. Here is the list of accepted Java core classes and methods in a JSweet program:
|
||||
By default, JSweet maps core Java objects and methods to JavaScript through the use of built-in macros. It means that the Java code is directly substituted with a valid JavaScript code that implements similar behavior. A default mapping is implemented for most useful core Java classes (\texttt{java.lang}, \texttt{java.util}). When possible (and when it makes sense), some partial mapping is implemented for other JDK classes such as input and output streams, locales, calendars, reflection, etc.
|
||||
|
||||
With the default behavior, we can point the following limitations:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{java.lang.Object}
|
||||
\begin{itemize}
|
||||
\item allowed methods: \texttt{boolean equals()}
|
||||
\item allowed methods: \texttt{Class<?> getClass()}
|
||||
\item allowed methods: \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.CharSequence}
|
||||
\begin{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{char charAt(int index)}
|
||||
\item \texttt{int length()} (transpiles to \texttt{length})
|
||||
\item \texttt{CharSequence subSequence(int beginIndex, int endIndex)}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.String}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{String()}
|
||||
\item \texttt{String(byte[] bytes)}
|
||||
\item \texttt{String(byte[] bytes, int offset, int length)}
|
||||
\item \texttt{String(char[] value)}
|
||||
\item \texttt{String(char[] value, int offset, int count)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{char charAt(int index)}
|
||||
\item \texttt{int codePointAt(int index)}
|
||||
\item \texttt{int compareTo(String anotherString)}
|
||||
\item \texttt{int compareToIgnoreCase(String str)}
|
||||
\item \texttt{String concat(String str)}
|
||||
\item \texttt{boolean equals(String anotherString)}
|
||||
\item \texttt{boolean equalsIgnoreCase(String anotherString)}
|
||||
\item \texttt{byte[] getBytes()}
|
||||
\item \texttt{int indexOf(int ch)}
|
||||
\item \texttt{int indexOf(String str)}
|
||||
\item \texttt{boolean isEmpty()}
|
||||
\item \texttt{int lastIndexOf(int ch)}
|
||||
\item \texttt{int lastIndexOf(int ch, int fromIndex)}
|
||||
\item \texttt{int lastIndexOf(String str)}
|
||||
\item \texttt{int lastIndexOf(String str, int fromIndex)}
|
||||
\item \texttt{int length()} (transpiles to \texttt{length})
|
||||
\item \texttt{String replace(CharSequence target, CharSequence replacement)}
|
||||
\item \texttt{CharSequence subSequence(int beginIndex, int endIndex)}
|
||||
\item \texttt{String substring(int beginIndex)}
|
||||
\item \texttt{String substring(int beginIndex, int endIndex)} (with the JavaScript behavior)
|
||||
\item \texttt{String[] split(String regex)}
|
||||
\item \texttt{boolean startsWith(String prefix)}
|
||||
\item \texttt{boolean startsWith(String prefix, int toffset)}
|
||||
\item \texttt{char[] toCharArray()}
|
||||
\item \texttt{String toLowerCase()}
|
||||
\item \texttt{String toString()}
|
||||
\item \texttt{String toUpperCase()}
|
||||
\item \texttt{String trim()}
|
||||
\item \texttt{static String valueOf(boolean b)}
|
||||
\item \texttt{static String valueOf(char c)}
|
||||
\item \texttt{static String valueOf(char[] data)}
|
||||
\item \texttt{static String valueOf(char[] data, int offset, int count)}
|
||||
\item \texttt{static String valueOf(double d)}
|
||||
\item \texttt{static String valueOf(float f)}
|
||||
\item \texttt{static String valueOf(int i)}
|
||||
\item \texttt{static String valueOf(long l)}
|
||||
\item \texttt{static String valueOf(Object obj)}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Class}
|
||||
\begin{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{String getName()}
|
||||
\item \texttt{String getSimpleName()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Boolean}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Boolean(value value)}
|
||||
\item \texttt{Boolean(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Void}
|
||||
\begin{itemize}
|
||||
\item allowed methods: none
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Integer}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Integer(int value)}
|
||||
\item \texttt{Integer(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Long}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Long(long value)}
|
||||
\item \texttt{Long(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Double}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Double(double value)}
|
||||
\item \texttt{Double(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{boolean isInfinite()}
|
||||
\item \texttt{boolean isNaN()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Number}
|
||||
\begin{itemize}
|
||||
\item allowed methods: none
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Float}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Float(float value)}
|
||||
\item \texttt{Float(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{boolean isInfinite()}
|
||||
\item \texttt{boolean isNaN()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Byte}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Byte(byte value)}
|
||||
\item \texttt{Byte(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Short}
|
||||
\begin{itemize}
|
||||
\item allowed constructors:
|
||||
\begin{itemize}
|
||||
\item \texttt{Short(short value)}
|
||||
\item \texttt{Short(String s)}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{boolean equals()}
|
||||
\item \texttt{int hashCode()}
|
||||
\item \texttt{String toString()}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Iterable}
|
||||
\begin{itemize}
|
||||
\item allowed methods: none (for using the \emph{foreach} loop on indexed objects)
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Runnable}
|
||||
\begin{itemize}
|
||||
\item allowed methods: none (for declaring lambdas)
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Throwable} and all sub-classes
|
||||
\begin{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{getMessage()}
|
||||
\item \texttt{getCause()}: valid but always return \texttt{null} by default
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.lang.Math}
|
||||
\begin{itemize}
|
||||
\item allowed fields:
|
||||
\begin{itemize}
|
||||
\item \texttt{static double E}
|
||||
\item \texttt{static double PI}
|
||||
\end{itemize}
|
||||
\item allowed methods:
|
||||
\begin{itemize}
|
||||
\item \texttt{static double abs(double a)}
|
||||
\item \texttt{static float abs(float a)}
|
||||
\item \texttt{static int abs(int a)}
|
||||
\item \texttt{static long abs(long a)}
|
||||
\item \texttt{static double acos(double a)}
|
||||
\item \texttt{static double asin(double a)}
|
||||
\item \texttt{static double atan(double a)}
|
||||
\item \texttt{static double atan2(double y, double x)}
|
||||
\item \texttt{static double cbrt(double a)}
|
||||
\item \texttt{static double ceil(double a)}
|
||||
\item \texttt{static double copySign(double magnitude, double sign)}
|
||||
\item \texttt{static double cos(double a)}
|
||||
\item \texttt{static double cosh(double x)}
|
||||
\item \texttt{static double exp(double a)}
|
||||
\item \texttt{static double expm1(double x)}
|
||||
\item \texttt{static double floor(double a)}
|
||||
\item \texttt{static double hypot(double x, double y)}
|
||||
\item \texttt{static double log(double a)}
|
||||
\item \texttt{static double log10(double a)}
|
||||
\item \texttt{static double log1p(double a)}
|
||||
\item \texttt{static double max(double a, double b)}
|
||||
\item \texttt{static float max(float a, float b)}
|
||||
\item \texttt{static int max(int a, int b)}
|
||||
\item \texttt{static long max(long a, long b)}
|
||||
\item \texttt{static double min(double a, double b)}
|
||||
\item \texttt{static float min(float a, float b)}
|
||||
\item \texttt{static int min(int a, int b)}
|
||||
\item \texttt{static long min(long a, long b)}
|
||||
\item \texttt{static double pow(double a, double b)}
|
||||
\item \texttt{static double random()}
|
||||
\item \texttt{static double rint(double a)}
|
||||
\item \texttt{static long round(double a)}
|
||||
\item \texttt{static int round(float a)}
|
||||
\item \texttt{static double scalb(double d, int scaleFactor)}
|
||||
\item \texttt{static float scalb(float f, int scaleFactor)}
|
||||
\item \texttt{static double signum(double d)}
|
||||
\item \texttt{static float signum(float f)}
|
||||
\item \texttt{static double sin(double a)}
|
||||
\item \texttt{static double sinh(double x)}
|
||||
\item \texttt{static double sqrt(double a)}
|
||||
\item \texttt{static double tan(double a)}
|
||||
\item \texttt{static double tanh(double x)}
|
||||
\item \texttt{static double toDegrees(double angrad)}
|
||||
\item \texttt{static double toRadians(double angdeg)}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item \texttt{java.util.function.*} (for declaring lambdas)
|
||||
\begin{itemize}
|
||||
\item prohibited method names:
|
||||
\begin{itemize}
|
||||
\item \texttt{and}
|
||||
\item \texttt{negate}
|
||||
\item \texttt{or}
|
||||
\item \texttt{andThen}
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\item Extending a JDK class is in general not possible, except for some particular contexts. If extending a JDK class is required, should should consider to refactor your program, or use the J4TS runtime, which would allow it.
|
||||
\item The Java reflection API (\texttt{java.lang.reflect}) is limited to very basic operations. It is possible to access the classes and the members, but it is not possible to access types. A more complete support of Java reflection would be possible, but it would require a JSweet extension.
|
||||
\item Java 8 streams are not supported yet, but it would be simple to support them partially (contributions are welcome).
|
||||
\end{itemize}
|
||||
|
||||
\noindent
|
||||
@ -429,38 +170,46 @@ for (int intItem : arrayOfInts) {
|
||||
|
||||
\subsection{Core JavaScript API}
|
||||
|
||||
The core JavaScript API is defined in \texttt{jsweet.lang} (the full documentation can be found at \url{http://www.jsweet.org/core-api-javadoc/}). Main JavaScript classes are:
|
||||
The core JavaScript API is defined in \texttt{def.js} (the full documentation can be found at \url{http://www.jsweet.org/core-api-javadoc/}). Main JavaScript classes are:
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{jsweet.lang.Object}: JavaScript Object class. Common ancestor for JavaScript objects functions and properties.
|
||||
\item \texttt{jsweet.lang.Boolean}: JavaScript Boolean class. A wrapper for boolean values.
|
||||
\item \texttt{jsweet.lang.Number}: JavaScript Number class. A wrapper for numerical values.
|
||||
\item \texttt{jsweet.lang.String}: JavaScript String class. A wrapper and constructor for strings.
|
||||
\item \texttt{jsweet.lang.Function}: JavaScript Function class. A constructor for functions.
|
||||
\item \texttt{jsweet.lang.Date}: JavaScript Date class, which enables basic storage and retrieval of dates and times.
|
||||
\item \texttt{jsweet.lang.Array<T>}: JavaScript Array class. It is used in the construction of arrays, which are high-level, list-like objects.
|
||||
\item \texttt{jsweet.lang.Error}: JavaScript Error class. This class implements \texttt{java.lang.RuntimeException} and can be thrown and caught with \texttt{try} ... \texttt{catch} statements.
|
||||
\item \texttt{def.js.Object}: JavaScript Object class. Common ancestor for JavaScript objects functions and properties.
|
||||
\item \texttt{def.js.Boolean}: JavaScript Boolean class. A wrapper for boolean values.
|
||||
\item \texttt{def.js.Number}: JavaScript Number class. A wrapper for numerical values.
|
||||
\item \texttt{def.js.String}: JavaScript String class. A wrapper and constructor for strings.
|
||||
\item \texttt{def.js.Function}: JavaScript Function class. A constructor for functions.
|
||||
\item \texttt{def.js.Date}: JavaScript Date class, which enables basic storage and retrieval of dates and times.
|
||||
\item \texttt{def.js.Array<T>}: JavaScript Array class. It is used in the construction of arrays, which are high-level, list-like objects.
|
||||
\item \texttt{def.js.Error}: JavaScript Error class. This class implements \texttt{java.lang.RuntimeException} and can be thrown and caught with \texttt{try} ... \texttt{catch} statements.
|
||||
\end{itemize}
|
||||
|
||||
When using JavaScript frameworks, programmers should use this API most of the time, which is HTML5 compatible and follows the JavaScript latest supported versions. However, for objects that need to be used with Java literals (numbers, booleans, and strings), the use of the \texttt{java.lang} package classes is recommended. For instance, the jQuery API declares \texttt{\$(java.lang.String)} instead of \texttt{\$(jsweet.\-lang.\-String)}. This allows the programmer to write expressions using literals, such as \texttt{\$($"$a$"$)} (for selecting all links in a document).
|
||||
When using JavaScript frameworks, programmers should use this API most of the time, which is HTML5 compatible and follows the JavaScript latest supported versions. However, for objects that need to be used with Java literals (numbers, booleans, and strings), the use of the \texttt{java.lang} package classes is recommended. For instance, the jQuery API declares \texttt{\$(java.lang.String)} instead of \texttt{\$(def.\-js.\-String)}. This allows the programmer to write expressions using literals, such as \texttt{\$($"$a$"$)} (for selecting all links in a document).
|
||||
|
||||
As a consequence, programmers need to be able to switch to the JavaScript API when coming from a Java object. The \texttt{jsweet.util.Globals} class defines convenient static methods to cast back and forth core Java objects to their corresponding JSweet objects. For instance the \texttt{string(...)} method will allow the programmer to switch from the Java to the JSweet strings and conversely.
|
||||
With JSweet, programmers can easily switch from the Java to JavaScript API (and conversely) depending on their needs. The \texttt{jsweet.util.Lang} class defines convenient static methods to cast back and forth core Java objects to their corresponding JavaScript objects. For instance the \texttt{string(...)} method will allow the programmer to switch from the Java to the JavaScript strings and conversely.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.string;
|
||||
String str = "This is a test string"; // str is actually a JavaScript string at runtime
|
||||
str.toLowerCase(); // valid: toLowerCase it defined both in Java and JavaScript
|
||||
str.substr(1); // this is ok, but it is a macro that will generate JavaScript code
|
||||
string(str).substr(1); // direct call to the substr method on the JavaScript string
|
||||
import static jsweet.util.Lang.string;
|
||||
// str is a Java string, but is actually a JavaScript string at runtime
|
||||
String str = "This is a test string";
|
||||
// str is exactly the same string object, but shown through the JS API
|
||||
def.js.String str2 = string(str);
|
||||
// valid: toLowerCase it defined both in Java and JavaScript
|
||||
str.toLowerCase();
|
||||
// this method is not JS-compatible, so a macro generates the JS code
|
||||
str.equalsIgnoreCase("abc");
|
||||
// direct call to the JS substr method on the JavaScript string
|
||||
string(str).substr(1);
|
||||
// or
|
||||
str2.substr(1);
|
||||
\end{lstlisting}
|
||||
|
||||
Note: for code sharing between a JavaScript client and a Java server for instance, it is better to use Java APIs only and not JavaScript ones.
|
||||
Note: for code sharing between a JavaScript client and a Java server for instance, it is better to use Java APIs only and avoid JavaScript ones. JavaScript API will compile valid Java bytecode but trying to execute them on a JVM will raise unsatisfied link errors.
|
||||
|
||||
\noindent
|
||||
Here is another example that shows the use of the \texttt{array} method to access the \texttt{push} method available on JavaScript arrays.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.array;
|
||||
import static jsweet.util.Lang.array;
|
||||
String[] strings = { "a", "b", "c" };
|
||||
array(strings).push("d");
|
||||
assert strings[3] == "d";
|
||||
@ -496,7 +245,7 @@ var BankAccount = (function () {
|
||||
})();
|
||||
\end{lstlisting}
|
||||
|
||||
Classes can define constructors, have super classes and be instantiated exactly like in Java. Similarly to Java, inner classes and anonymous classes are allowed in JSweet since version 1.1.0. JSweet supports both static and regular inner/anonymous classes, which can share state with enclosing classes. Still like in Java, anonymous classes can access final variables declared in their scope. For example, the following declarations are valid in JSweet and will mimic the Java semantics at runtime so that Java programmers can benefit all the features of the Java language.
|
||||
Classes can define constructors, have super classes and be instantiated exactly like in Java. Similarly to Java, inner classes and anonymous classes are allowed in JSweet (since version 1.1.0). JSweet supports both static and regular inner/anonymous classes, which can share state with enclosing classes. Still like in Java, anonymous classes can access final variables declared in their scope. For example, the following declarations are valid in JSweet and will mimic the Java semantics at runtime so that Java programmers can benefit all the features of the Java language.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
abstract class C {
|
||||
@ -521,65 +270,35 @@ public class ContainerClass {
|
||||
|
||||
\section{Interfaces}
|
||||
|
||||
In JSweet, an interface (a.k.a. object type) can be seen as object signature, that is to say the accessible functions and properties of an object (without specifying any implementation). An interface is defined for typing only and has no runtime representation (no instances), however, they can be used to type objects.
|
||||
In JSweet, an interface can be use like in Java. However, on contrary to Java, there is no associated class available as runtime. When using interfaces, JSweet generates code to emulate specific Java behaviors (such as \texttt{instanceof} on interfaces).
|
||||
|
||||
JSweet interfaces can be defined as regular Java interfaces, but also as Java classes annotated with \texttt{@jsweet.lang.Interface}, so that is is possible to define properties as fields. Such classes impose many constraints, as shown in the following code.
|
||||
JSweet supports Java 8 static and default methods. However default methods are experimental so far and you should use them at your own risks.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
@Interface
|
||||
public class WrongConstructsInInterfaces {
|
||||
native public void m1(); // OK
|
||||
// error: field initializers are not allowed
|
||||
public long l = 4;
|
||||
// error: statics are not allowed
|
||||
static String s1;
|
||||
// error: private are not allowed
|
||||
private String s2;
|
||||
// error: constructors are not allowed
|
||||
public WrongConstructsInInterfaces() {
|
||||
l = 4;
|
||||
}
|
||||
// error: bodies are not allowed
|
||||
public void m2() {
|
||||
l = 4;
|
||||
}
|
||||
// error: statics are not allowed
|
||||
native static void m3();
|
||||
// error: initializers are not allowed
|
||||
{
|
||||
l = 4;
|
||||
}
|
||||
// error: static initializers are not allowed
|
||||
static {
|
||||
s1 = "";
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\subsection{Object typing}
|
||||
|
||||
In JSweet, typed objects can be constructed out of interfaces. If we take the following interface:
|
||||
In JSweet, interfaces are more similar to interfaces in TypeScript than in Java. It means that they must be seen as object signatures, which can specify functions, but also properties. In order to allow using fields as properties when defining interfaces, JSweet allows the use of regular classes annotated with \texttt{@jsweet.lang.Interface}. For example, the following interface types an object \texttt{Point} with 2 properties.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
@Interface
|
||||
public class Point {
|
||||
public double x;
|
||||
public double y;
|
||||
public double y;
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\noindent
|
||||
We can create an object typed after the interface. Note that the following code is not actually creating an instance of the \texttt{Point} interface, it is creating an object that conforms to the interface.
|
||||
To Java programmers, this may look like a very odd way to define an object, but you must remember that it is not a class, but a type for a JavaScript object. As such, it does not go against the OOP principles. We can create a JavaScript object typed after the interface. Note that the following code is not actually creating an instance of the \texttt{Point} interface, it is creating an object that conforms to the interface.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
Point p1 = new Point() {{ x=1; y=1; }};
|
||||
\end{lstlisting}
|
||||
|
||||
This object creation mechanism is a TypeScript/JavaScript mechanism and shall not be confused with anonymous classes, which is a Java-like construction.
|
||||
This object creation mechanism is a TypeScript/JavaScript mechanism and shall not be confused with anonymous classes, which is a Java-like construction. Because \texttt{Point} is annotated with \texttt{@Interface}, the transpiled JavaScript code will be similar to:
|
||||
|
||||
Note also that, for each object, JSweet keeps track of which interface it was created from and of all the potential interfaces implemented by its class. This interface tracking system is implemented as a special object property called \texttt{\_\_interfaces}. Using that property, JSweet allows the use of the \texttt{instanceof} operator on interfaces, exactly like in Java, as we will see later in this document.
|
||||
\begin{lstlisting}[language=Java]
|
||||
var p1 = Object.defineProperty({ x:1, y:1 }, "_interfaces", ["Point"]);
|
||||
\end{lstlisting}
|
||||
|
||||
\subsection{Optional fields}
|
||||
Note that, for each object, JSweet keeps track of which interface it was created from and of all the potential interfaces implemented by its class. This interface tracking system is implemented as a special object property called \texttt{\_\_interfaces}. Using that property, JSweet allows the use of the \texttt{instanceof} operator on interfaces like in Java.
|
||||
|
||||
\subsection{Optional fields in interfaces}
|
||||
|
||||
Interfaces can define \emph{optional fields}, which are used to report errors when the programmer forgets to initialize a mandatory field in an object. Supporting optional fields in JSweet is done through the use of \texttt{@jsweet.lang.Optional} annotations. For instance:
|
||||
|
||||
@ -602,18 +321,44 @@ Point p1 = new Point() {{ x=1; y=1; }};
|
||||
Point p2 = new Point() {{ x=1; z=1; }};
|
||||
\end{lstlisting}
|
||||
|
||||
\subsection{Special functions in interfaces}
|
||||
\subsection{Special JavaScript functions in interfaces}
|
||||
|
||||
In JavaScript, objects can have properties and functions, but can also (not exclusively), be used as constructors and functions themselves. This is not possible in Java, so JSweet defines special functions for handling these cases.
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{apply} is used to state that the object can be used as a function.
|
||||
\item \texttt{\$apply} is used to state that the object can be used as a function.
|
||||
\item \texttt{\$new} is used to state that the object can be used as a constructor.
|
||||
\end{itemize}
|
||||
|
||||
For instance, if an object \texttt{o} is of interface \texttt{O} that defines \texttt{\$apply()}, writing:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
o.$apply();
|
||||
\end{lstlisting}
|
||||
|
||||
Will transpile to:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
o();
|
||||
\end{lstlisting}
|
||||
|
||||
Similarly, if \texttt{O} defines \texttt{\$new()}:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
o.$new();
|
||||
\end{lstlisting}
|
||||
|
||||
Will transpile to:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
new o();
|
||||
\end{lstlisting}
|
||||
|
||||
Yes, it does not make sense in Java, but in JavaScript it does!
|
||||
|
||||
\section{Untyped objects (maps)}
|
||||
|
||||
In JavaScript, object can be seen as maps containing key-value pairs (key is often called \emph{index}, especially when it is a number). So, in JSweet, all objects define the special functions (defined on \texttt{jsweet.lang.Object}):
|
||||
In JavaScript, object can be seen as maps containing key-value pairs (key is often called \emph{index}, especially when it is a number). So, in JSweet, all objects define the special functions (defined on \texttt{def.js.Object}):
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{\$get(key)} accesses a value with the given key.
|
||||
@ -623,12 +368,12 @@ In JavaScript, object can be seen as maps containing key-value pairs (key is oft
|
||||
|
||||
\subsection{Reflective/untyped accesses}
|
||||
|
||||
The functions \texttt{\$get(key)}, \texttt{\$set(key,value)} and \texttt{\$delete(key)} can be seen as a simple reflective API to access object fields and state. Note also the static method \texttt{jsweet.lang.Object.keys(object)}, which returns all the keys defined on a given object.
|
||||
The functions \texttt{\$get(key)}, \texttt{\$set(key,value)} and \texttt{\$delete(key)} can be seen as a simple reflective API to access object fields and state. Note also the static method \texttt{def.js.Object.keys(object)}, which returns all the keys defined on a given object.
|
||||
|
||||
The following code uses this API to introspect the state of an object \texttt{o}.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
for(String key : jsweet.lang.Object.keys(o)) {
|
||||
for(String key : def.js.Object.keys(o)) {
|
||||
console.log("key=" + key + " value=" + o.$get(key));
|
||||
});
|
||||
\end{lstlisting}
|
||||
@ -640,17 +385,24 @@ When not having the typed API of a given object, this API can be useful to manip
|
||||
One can use the \texttt{\$set(key,value)} function to create new untyped object. For instance:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
Object point = new jsweet.lang.Object() {{ $set("x", 1); $set("y", 1); }};
|
||||
Object point = new def.js.Object() {{ $set("x", 1); $set("y", 1); }};
|
||||
\end{lstlisting}
|
||||
|
||||
As a shortcut, one can use the \texttt{jsweet.util.Global.\$map} function:
|
||||
It transpiles also to:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Global.$map;
|
||||
var point = { "x": 1, "y": 1};
|
||||
\end{lstlisting}
|
||||
|
||||
As a shortcut, one can use the \texttt{jsweet.util.Lang.\$map} function, which transpiles to the exact same JavaScript code:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Lang.$map;
|
||||
[...]
|
||||
Object point = $map("x", 1, "y", 1);
|
||||
\end{lstlisting}
|
||||
|
||||
|
||||
\subsection{Indexed objects}
|
||||
|
||||
The type of keys and values can be overloaded for every object. For example, the \texttt{Array<T>} class, will define keys as numbers and values as objects conforming to type \texttt{T}.
|
||||
@ -792,39 +544,39 @@ String m(String s) { return s; }
|
||||
|
||||
\chapter{Bridging to external JavaScript elements}
|
||||
|
||||
It can be the case that programmers need to use existing libraries from JSweet. In most cases, one should look up in the available candies (\url{http://www.jsweet.org/candies-releases/} and \url{http://www.jsweet.org/candies-snapshots/}), which are automatically generated from TypeScript's DefinitelyTyped. When the candy does not exist, or does not entirely cover what is needed, one can use the \texttt{@jsweet.lang.Ambient} annotation, which will make available to the programmers a class definition or an interface.
|
||||
It can be the case that programmers need to use existing libraries from JSweet. In most cases, one should look up in the available candies, a.k.a. bridges at \url{http://www.jsweet.org/jsweet-candies/}. When the candy does not exist, or does not entirely cover what is needed, one can create new definitions in the program just by placing them in the \texttt{def.libname} package. Definitions only specify the types of external libraries, but no implementations. Definitions are similar to TypeScript's \texttt{*.d.ts} definition files (actually JSweet generates intermediate TypeScript definition files for compilation purposes). Definitions can also be seen as similar to \texttt{*.h} C/C++ header files.
|
||||
|
||||
\section{Ambient declarations}
|
||||
\section{Examples}
|
||||
|
||||
The following example shows the backbone store class made accessible to the JSweet programmer with a simple ambient declaration. This class is only for typing and will be erased during the JavaScript generation.
|
||||
The following example shows the backbone store class made accessible to the JSweet programmer with a simple definition. This class is only for typing and will be generated as a TypeScript definition, and erased during the JavaScript generation.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
@Ambient
|
||||
package def.backbone;
|
||||
class Store {
|
||||
public Store(String dbName) {}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
Note that ambient classes constructors must have an empty body. Also, ambient classes methods must be \texttt{abstract} or \texttt{native}. For instance:
|
||||
Note that definition classes constructors must have an empty body. Also, definition classes methods must be \texttt{native}. For instance:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
@Ambient
|
||||
package def.mylib;
|
||||
class MyExternalJavaScriptClass {
|
||||
public native myExternalJavaScriptMethod();
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
\section{Definitions}
|
||||
It is possible to define properties in definitions, however, these properties cannot be initialized.
|
||||
|
||||
By convention, putting the classes in a \texttt{def.libname} package defines a set of definitions for the \texttt{libname} external JavaScript library called \texttt{libname}. Definitions are by default all ambient declarations and do not need to be annotated with \texttt{@jsweet.lang.Ambient} annotations since they are implicit in \texttt{def.*} packages and sub-packages. Note that this mechanism is similar to the TypeScript \texttt{d.ts} definition files.
|
||||
\section{Rules for writing definitions (a.k.a. bridges)}
|
||||
|
||||
By convention, putting the classes in a \texttt{def.libname} package defines a set of definitions for the \texttt{libname} external JavaScript library called \texttt{libname}. Note that this mechanism is similar to the TypeScript \texttt{d.ts} definition files.
|
||||
|
||||
Candies (bridges to external JavaScript libraries) use definitions. For instance, the jQuery candy defines all the jQuery API in the \texttt{def.jquery} package.
|
||||
|
||||
Here is a list of rules and constraints that need to be followed when writing definitions.
|
||||
|
||||
\begin{itemize}
|
||||
\item The \texttt{def.libname} package must be annotated with a \texttt{@jsweet.lang.Root} (to be placed in a \texttt{package-info.java} file).
|
||||
\item Within a \texttt{def.*} package, \texttt{@Ambient} annotations are not required. By conventions all declarations are ambient.
|
||||
\item Interfaces are preferred over classes, because interfaces can be merged and classes can be instantiated. Classes should be used only if the API defines an explicit constructor (objects can be created with \texttt{new}). To define an interface in JSweet, just annotate a class with \texttt{@jsweet.lang.Interface}.
|
||||
\item Top-level functions and variables must be defined as \texttt{public static} members in a \texttt{Globals} class.
|
||||
\item All classes, interfaces and packages, should be documented with comments following the Javadoc standard.
|
||||
@ -834,7 +586,7 @@ Here is a list of rules and constraints that need to be followed when writing de
|
||||
\item In an interface, optional fields can be defined with the \texttt{@jsweet.lang.Optional} annotation.
|
||||
\end{itemize}
|
||||
|
||||
Definitions can be embedded directly in a JSweet project to access an external library in a typed way. In that case, you should specify the \texttt{definitions} compilation option so that these definitions can be generated and used by the TypeScript transpiler.
|
||||
Definitions can be embedded directly in a JSweet project to access an external library in a typed way.
|
||||
|
||||
Definitions can also be packaged in a candy (a Maven artifact), so that they can be shared by other projects. See the \emph{Packaging} section for full details on how to create a candy. Note that you do not need to write definitions when a library is written with JSweet because the Java API is directly accessible and the TypeScript definitions can be automatically generated by JSweet using the \texttt{declaration} option.
|
||||
|
||||
@ -842,34 +594,34 @@ Definitions can also be packaged in a candy (a Maven artifact), so that they can
|
||||
|
||||
Sometimes, definitions are not available or are not correct, and just a small patch is required to access a functionality. Programmers have to keep in mind that JSweet is just a syntactic layer and that it is always possible to bypass typing in order to access a field or a function that is not explicitly specified in an API.
|
||||
|
||||
Although, having a well-typed API is the preferred and advised way, when such an API is not available, the use of \texttt{jsweet.\-lang.\-Object.\$get} allows reflective access to methods and properties that can then be cast to the right type. For accessing functions in an untyped way, one can cast to \texttt{jsweet.\-lang.\-Function} and call the generic and untyped method \texttt{apply} on it. For example, here is how to invoke the jQuery \texttt{\$} method when the jQuery API is not available :
|
||||
Although, having a well-typed API is the preferred and advised way, when such an API is not available, the use of \texttt{def.\-js.\-Object.\$get} allows reflective access to methods and properties that can then be cast to the right type. For accessing functions in an untyped way, one can cast to \texttt{def.\-js.\-Function} and call the generic and untyped method \texttt{\$apply} on it. For example, here is how to invoke the jQuery \texttt{\$} method when the jQuery API is not available :
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import jsweet.dom.Globals.window;
|
||||
import def.dom.Globals.window;
|
||||
[...]
|
||||
Function $ = (Function)window.$get("$");
|
||||
$.apply("aCssSelector"):
|
||||
$.$apply("aCssSelector"):
|
||||
\end{lstlisting}
|
||||
|
||||
The \texttt{\$get} function is available on instances of \texttt{jsweet.lang.Object} (or subclasses). For a \texttt{java.lang.Object}, you can cast it using the \texttt{jsweet.util.Globals.object} helper method. For example:
|
||||
The \texttt{\$get} function is available on instances of \texttt{def.js.Object} (or subclasses). For a \texttt{def.js.Object}, you can cast it using the \texttt{jsweet.util.Lang.object} helper method. For example:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.dom.Globals.object;
|
||||
import static jsweet.dom.Lang.object;
|
||||
[...]
|
||||
object(anyObject).$get("$");
|
||||
\end{lstlisting}
|
||||
|
||||
The other way it to use the \texttt{jsweet.util.Globals.\$get} helper method. Using helper methods can be convenient to easily write typical (untyped JavaScript statement). For example:
|
||||
In last resort, the \texttt{jsweet.util.Lang.\$insert} helper method allows the user to insert any TypeScript expression within the program. Invalid expressions will raise a TypeScript compilation error, but it is however not recommended to use this technique.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.dom.Globals.$get;
|
||||
import static jsweet.dom.Globals.$apply;
|
||||
import static jsweet.dom.Lang.$get;
|
||||
import static jsweet.dom.Lang.$apply;
|
||||
[...]
|
||||
// generate anyObject["prop"]("param");
|
||||
$apply($get(anyObject, "prop"), "param");
|
||||
\end{lstlisting}
|
||||
|
||||
Finally, note also the use of the \texttt{jsweet.util.Globals.any} helper method, which can be extremely useful to erase typing. Since the \texttt{any} method generates a cast to the \texttt{any} type in TypeScript, it is more radical than a cast to \texttt{Object} for instance. The following example shows how to use the \texttt{any} method to cast an \texttt{Int32Array} to a Java \texttt{int[]} (and then allow direct indexed accesses to it.
|
||||
Finally, note also the use of the \texttt{jsweet.util.Lang.any} helper method, which can be extremely useful to erase typing. Since the \texttt{any} method generates a cast to the \texttt{any} type in TypeScript, it is more radical than a cast to \texttt{Object} for instance. The following example shows how to use the \texttt{any} method to cast an \texttt{Int32Array} to a Java \texttt{int[]} (and then allow direct indexed accesses to it.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
ArrayBuffer arb = new ArrayBuffer(2 * 2 * 4);
|
||||
@ -881,7 +633,7 @@ int whatever = array[0];
|
||||
|
||||
In JavaScript, it is common practice to enhance an existing class with news elements (field and methods). It is an extension mechanism used when a framework defines plugins for instance. Typically, jQuery plugins add new elements to the \texttt{JQuery} class. For example the jQuery timer plugin adds a \texttt{timer} field to the \texttt{JQuery} class. As a consequence, the \texttt{JQuery} class does not have the same prototype if you are using jQuery alone, or jQuery enhanced with its timer plugin.
|
||||
|
||||
In Java, this extension mechanism is problematic because Java cannot dynamically enhance a given class.
|
||||
In Java, this extension mechanism is problematic because the Java language does not support mixins or any extension of that kind by default.
|
||||
|
||||
\subsection{Untyped accesses to mixins}
|
||||
|
||||
@ -903,7 +655,7 @@ JQuery jq = (JQuery) obj;
|
||||
jq.menu();
|
||||
\end{lstlisting}
|
||||
|
||||
However, these solutions are not satisfying because clearly unsafe in terms of typing.
|
||||
However, these solutions are not fully satisfying because clearly unsafe in terms of typing.
|
||||
|
||||
\subsection{Typed accesses with mixins}
|
||||
|
||||
@ -911,16 +663,16 @@ When cross-candy dynamic extension is needed, JSweet defines the notion of a mix
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
package def.jqueryui;
|
||||
import jsweet.dom.MouseEvent;
|
||||
import jsweet.lang.Function;
|
||||
import jsweet.lang.Date;
|
||||
import jsweet.lang.Array;
|
||||
import jsweet.lang.RegExp;
|
||||
import jsweet.dom.Element;
|
||||
import def.dom.MouseEvent;
|
||||
import def.js.Function;
|
||||
import def.js.Date;
|
||||
import def.js.Array;
|
||||
import def.js.RegExp;
|
||||
import def.dom.Element;
|
||||
import def.jquery.JQueryEventObject;
|
||||
@jsweet.lang.Interface
|
||||
@jsweet.lang.Mixin(target=def.jquery.JQuery.class)
|
||||
public abstract class JQuery extends jsweet.lang.Object {
|
||||
public abstract class JQuery extends def.jquery.JQuery {
|
||||
native public JQuery accordion();
|
||||
native public void accordion(jsweet.util.StringTypes.destroy methodName);
|
||||
native public void accordion(jsweet.util.StringTypes.disable methodName);
|
||||
@ -933,28 +685,13 @@ public abstract class JQuery extends jsweet.lang.Object {
|
||||
|
||||
One can notice the \texttt{@jsweet.lang.Mixin(target=def.jquery.JQuery.class)} that states that this mixin will be merged to the \texttt{def.jquery.JQuery} so that users will be able to use all the UI plugin members directly and in a well-typed way.
|
||||
|
||||
\subsection{Implementation and how to use}
|
||||
\subsection{How to use}
|
||||
|
||||
JSweet merges mixins using a bytecode manipulation tool called Javassist. It takes the mixin classes bytecode, copies all the members to the target classes, and writes the resulting merged classes bytecode to the \texttt{.jsweet/candies/processed} directory. As a consequence, in order to benefit the JSweet mixin mechanism, one must add the \texttt{.jsweet/candies/processed} directory to the compilation classpath. This directory should be placed before all the other classpath elements so that the mixined results override the original classes (for example the \texttt{def.jquery.JQuery} should be overridden and, as a consequence, \texttt{.jsweet/candies/processed/def/jquery/JQuery.class} must be found first in the classpath).
|
||||
TBD.
|
||||
|
||||
The JSweet transpiler automatically adds the \texttt{.jsweet/candies/processed} directory to the compilation classpath so that you do not have to do anything special when using JSweet with Maven. However, when using mixins within an IDE, you must force your project classpath to include this directory in order to ensure compilation of mixin-ed elements. When using the JSweet Eclipse plugin for instance, this is done automatically and transparently for the user. But when not using any plugins, this configuration must be done manually.
|
||||
\section{Generating JSweet candies from existing TypeScript definitions}
|
||||
|
||||
For example, with Eclipse (similar configuration can be made with other IDEs):
|
||||
|
||||
\begin{enumerate}
|
||||
\item Right-click on the project \textgreater Build path \textgreater Configure build path... \textgreater Libraries (tab) \textgreater Add class folder (button). Then choose the \texttt{.jsweet/candies/processed} directory.
|
||||
\item In the "order and export" tab of the build path dialog, make sure that the \texttt{.jsweet/candies/processed} directory appears at the top of the list (or at least before the Maven dependencies).
|
||||
\end{enumerate}
|
||||
|
||||
NOTE: you do not have to configure anything if you are not using mixins or if you are using the Eclipse plugin.
|
||||
|
||||
Once this configuration is done, you can safely use mixins. For instance, if using the jQuery candy along with jQuery UI, you will be able to write statements such as:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
$("#myMenu").menu();
|
||||
\end{lstlisting}
|
||||
|
||||
This is neat compared to the untyped access solution because it is checked by the Java compiler (and you will also have completion on mixin-ed elements).
|
||||
TBD.
|
||||
|
||||
\chapter{Auxiliary types}
|
||||
|
||||
@ -1169,10 +906,10 @@ public void m(Integer p) {...}
|
||||
|
||||
In the previous case, the use of explicit union types is not required. For more general cases, JSweet defines an auxiliary interface \texttt{Union<T1, T2>} (and \texttt{UnionN<T1, ... TN>}) in the \texttt{jsweet.\-util.\-union} package. By using this auxiliary type and a \texttt{union} utility method, programmers can cast back and forth between union types and union-ed type, so that JSweet can ensure similar properties as TypeScript union types.
|
||||
|
||||
The following code shows a typical use of union types in JSweet. It simply declares a variable as a union between a string and a number, which means that the variable can actually be of one of that types (but of no other types). The switch from a union type to a regular type is done through the \texttt{jsweet\-.util\-.Globals\-.union} helper method. This helper method is completely untyped, allowing from a Java perspective any union to be transformed to another type. It is actually the JSweet transpiler that checks that the union type is consistently used.
|
||||
The following code shows a typical use of union types in JSweet. It simply declares a variable as a union between a string and a number, which means that the variable can actually be of one of that types (but of no other types). The switch from a union type to a regular type is done through the \texttt{jsweet\-.util\-.Lang\-.union} helper method. This helper method is completely untyped, allowing from a Java perspective any union to be transformed to another type. It is actually the JSweet transpiler that checks that the union type is consistently used.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.union;
|
||||
import static jsweet.util.Lang.union;
|
||||
import jsweet.util.union.Union;
|
||||
[...]
|
||||
Union<String, Number> u = ...;
|
||||
@ -1187,7 +924,7 @@ Date d = union(u); // JSweet error
|
||||
The \texttt{union} helper can also be used the other way, to switch from a regular type back to a union type, when expected.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.union;
|
||||
import static jsweet.util.Lang.union;
|
||||
import jsweet.util.union.Union3;
|
||||
[...]
|
||||
public void m(Union3<String, Number, Date>> u) { ... }
|
||||
@ -1213,7 +950,7 @@ native public void m(Date d);
|
||||
|
||||
TypeScript defines the notion of type intersection. When types are intersected, it means that the resulting type is a larger type, which is the sum of all the intersected types. For instance, in TypeScript, \texttt{A \& B} corresponds to a type that defines both \texttt{A} and \texttt{B} members.
|
||||
|
||||
Intersection types in Java cannot be implemented easily for many reasons. So, the practical choice being made here is to use union types in place of intersection types. In JSweet, \texttt{A \& B} is thus defined as \texttt{Union<A, B>}, which means that the programmer can access both \texttt{A} and \texttt{B} members by using the \texttt{jsweet\-.util\-.Globals\-.union} helper method. It is of course less convenient than the TypeScript version, but it is still type safe.
|
||||
Intersection types in Java cannot be implemented easily for many reasons. So, the practical choice being made here is to use union types in place of intersection types. In JSweet, \texttt{A \& B} is thus defined as \texttt{Union<A, B>}, which means that the programmer can access both \texttt{A} and \texttt{B} members by using the \texttt{jsweet\-.util\-.Lang\-.union} helper method. It is of course less convenient than the TypeScript version, but it is still type safe.
|
||||
|
||||
\chapter{Semantics}
|
||||
\label{semantics}
|
||||
@ -1296,10 +1033,10 @@ strings[0][0] = "a";
|
||||
assert strings[0][0] == "a";
|
||||
\end{lstlisting}
|
||||
|
||||
The JavaScript API can be used on an array by casting to a \texttt{jsweet.\-lang.\-Array} with \texttt{jsweet.\-util.\-Globals.\-array}.
|
||||
The JavaScript API can be used on an array by casting to a \texttt{def.\-js.\-Array} with \texttt{jsweet.\-util.\-Lang.\-array}.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.array;
|
||||
import static jsweet.util.Lang.array;
|
||||
[...]
|
||||
String[] strings = { "a", "b", "c" };
|
||||
assert strings.length == 3;
|
||||
@ -1308,7 +1045,7 @@ assert strings.length == 4;
|
||||
assert strings[3] == "d";
|
||||
\end{lstlisting}
|
||||
|
||||
In some cases it is preferable to use the \texttt{jsweet.\-lang.\-Array} class directly.
|
||||
In some cases it is preferable to use the \texttt{def.\-js.\-Array} class directly.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
Array<String> strings = new Array<String>("a", "b", "c");
|
||||
@ -1414,11 +1151,11 @@ To test the type of a given object at runtime, one can use the \texttt{instanceo
|
||||
|
||||
The \texttt{instanceof} is the advised and preferred way to test types at runtime. JSweet will transpile to a regular \texttt{instanceof} or to a \texttt{typeof} operator depending on the tested type (it will fallback on \texttt{typeof} for \texttt{number}, \texttt{string}, and \texttt{boolean} core types).
|
||||
|
||||
Although not necessary, it is also possible to directly use the \texttt{typeof} operator from JSweet with the \texttt{jsweet.\-util.\-Globals.\-typeof} utility method. Here are some examples of valid type tests:
|
||||
Although not necessary, it is also possible to directly use the \texttt{typeof} operator from JSweet with the \texttt{jsweet.\-util.\-Lang.\-typeof} utility method. Here are some examples of valid type tests:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
import static jsweet.util.Globals.typeof;
|
||||
import static jsweet.util.Globals.equalsStrict;
|
||||
import static jsweet.util.Lang.typeof;
|
||||
import static jsweet.util.Lang.equalsStrict;
|
||||
[...]
|
||||
Number n1 = 2;
|
||||
Object n2 = 2;
|
||||
@ -1586,7 +1323,7 @@ When compiling JSweet programs with the \texttt{module} options, all external li
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
package def.jquery;
|
||||
public final class Globals extends jsweet.lang.Object {
|
||||
public final class Globals extends def.js.Object {
|
||||
...
|
||||
@jsweet.lang.Module("jquery")
|
||||
native public static def.jquery.JQuery $(java.lang.String selector);
|
||||
@ -1667,6 +1404,115 @@ We provide a quick start project to help you starting with such a use case: \url
|
||||
|
||||
We provide a quick start project to help you starting with such a use case: \url{https://github.com/cincheo/jsweet-candy-js-quickstart}
|
||||
|
||||
\chapter{Extending the transpiler}
|
||||
\label{extension}
|
||||
|
||||
JSweet is an Open Transpiler. It means that it provides ways for programmers to tune/extend how JSweet generates the intermediate TypeScript code. Tuning the transpiler is a solution to avoid repetitive tasks and automatize them. For instance, say you have a legacy Java code that uses the Java API for serializing objects (\texttt{writeObject}/\texttt{readObject}). With JSweet, you can easily erase these methods from your program, so that the generated JavaScript code is free from any Java-specific serialization idioms. As another example, say you have a Java legacy code base that uses a Java API, which is close to (but not exactly) a JavaScript API you want to use in your final JavaScript code. With JSweet, you can write an adapter that will automatically map all the Java calls to the corresponding JavaScript calls. Last but not least, you can tune JSweet to take advantage of some specific APIs depending on the context. For instance, you may use ES6 maps if you know that your targeted browser supports them, or just use an emulation or a simpler implementation in other cases. You may adapt the code to avoid using some canvas or WebGL primitives when knowing they are not well supported for a given mobile browser. An so on... Using an Open Transpiler such as JSweet has many practical applications, which you may or may not have to use, but in any case it is good to be aware of what is possible.
|
||||
|
||||
Tuning can be done declaratively (as opposed to programmatically) using annotations. Annotations can be added to the Java program (hard-coded), or they can be centralized in a unique configuration file so that they don't even appear in the Java code (we call them soft annotations). Using annotations is quite simple and intuitive. However, when complex customization of the transpiler is required, it is most likely that annotations are not sufficient anymore. In that case, programmers shall use the JSweet extension API, which entails all the tuning that can be done with annotations, and much more. The extension API gives access to a Java AST (Abstract Syntax Tree) withing the context of so-called printer adapters. Printer adapters follow a decorator pattern so that they can be chained to extend and/or override the way JSweet will print out the intermediate TypeScript code.
|
||||
|
||||
\section{Core annotations}
|
||||
|
||||
The package \texttt{jsweet.lang} defines various annotation that can be used to tune the way JSweet generates the intermediate TypeScript code. Here we explain these annotations and give examples on how to use them.
|
||||
|
||||
\begin{itemize}
|
||||
\item \texttt{@Erased}: This annotation type is used on elements that should be erased at generation time. It can be applied to any program element. If applied to a type, casts and constructor invocations will automatically be removed, potentially leading to program inconsistencies. If applied to a method, invocations will be removed, potentially leading to program inconsistency, especially when the invocation's result is used in an expression. Because of potential inconsistencies, programmers should use this annotation carefully, and applied to unused elements (also erasing using elements).
|
||||
|
||||
\item \texttt{@Root}: This package annotation is used to specify a root package for the transpiled TypeScript/JavaScript, which means that all transpiled references in this package and subpackages will be relative to this root package. As an example, given the \texttt{org.mycompany.mylibrary} root package (annotated with \texttt{@Root}), the class \texttt{org\-.mycompany\-.mylibrary\-.MyClass} will actually correspond to \texttt{MyClass} in the JavaScript runtime. Similarly, the \texttt{org\-.mycompany\-.mylibrary\-.mypackage\-.MyClass} will transpile to \texttt{mypackage\-.MyClass}.
|
||||
|
||||
\item \texttt{@Name(String value)}: This annotation allows the definition of a name that will be used for the final generated code (rather than the Java name). It can be used when the name of an element is not a valid Java identifier. By convention, JSweet implements a built-in convention to save the use of @Name annotations: \texttt{Keyword} in Java transpiles to \texttt{keyword}, when \texttt{keyword} is a Java keyword (such as \texttt{catch}, \texttt{finally}, \texttt{int}, \texttt{long}, and so forth).
|
||||
|
||||
\item \texttt{@Replace(String value)}: This annotation allows the programmer to substitute a method body implementation by a TypeScript implementation. The annotation's value contains TypeScript which is generated as is by the JSweet transpiler. The code will be checked by the TypeScript transpiler. The replacing code can contain variables substituted using a mustache-like convention (\texttt{\{\{variableName}\}\}). Here is the list of supported variables:
|
||||
\begin{itemize}
|
||||
\item \texttt{\{\{className\}\}}: the current class.
|
||||
\item \texttt{\{\{methodName\}\}}: the current method name.
|
||||
\item \texttt{\{\{body\}\}}: the body of the current method. A typical use of this variable
|
||||
is to wrap the original behavior in a lambda. For instance:
|
||||
\texttt{/* before code */ let \_result = () => \{ \{\{body\}\} \}(); /* after code */ return result;}.
|
||||
\item \texttt{\{\{baseIndent\}\}}: the indentation of the replaced method. Can be used to generate well-formatted code.
|
||||
\item \texttt{\{\{indent\}\}}: substituted with an indentation. Can be used to generate well-formatted code.
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Examples}
|
||||
|
||||
TBD
|
||||
|
||||
\section{Centralizing annotations in \texttt{jsweetconfig.json}}
|
||||
|
||||
JSweet supports the definition of annotations within a unique configuration file (\texttt{jsweetconfig.json}). There are many reasons why programmers would want to define annotations within that file instead of defining annotations in the Java source code.
|
||||
|
||||
\begin{enumerate}
|
||||
\item Annotations or annotation contents may differ depending on the context. It may be convenient to have different configuration files depending on the context. It is easier to switch a configuration file with another than having to change all the annotations in the program.
|
||||
\item Adding annotations to the Java program is convenient to tune the program locally (on a given element). However, in some cases, similar annotations should apply on a set of program elements, in order to automatize global tuning of the program. In that case, it is more convenient to install annotation by using an expression, that will match a set of program element at once. This will mechanism is similar to the \emph{pointcut} mechanism that can be found in Aspect Oriented Software Design. It allows capturing a global modification in a declarative manner.
|
||||
\item Using annotations in the Java source code entails a reference to the JSweet API (the \texttt{jsweet.lang} package) that may be seen as an unwanted dependency for some programmers who want their Java code to remain as "pure" as possible.
|
||||
\end{enumerate}
|
||||
|
||||
The JSweet configuration file (\texttt{jsweetconf.json}) is a JSON file containing a list of configuration entries. Among the configuration entries, so-called global filters can be defined using the following structure:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
<annotation>: {
|
||||
"include": <match_expressions>,
|
||||
"exclude": <match_expressions>
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
Where \texttt{<annotation>} is the annotation to be added, with potential parameters, and \texttt{include} and \texttt{exclude} are lists of match expressions. An element in the program will be annotated with the annotation, if its signature matches any of the expressions in the \texttt{include} list and does not match any the expressions in the \texttt{exclude} list.
|
||||
|
||||
A match expression is a sort of simplified regular expression, supporting the following wildcards:
|
||||
|
||||
\begin{enumerate}
|
||||
\item \texttt{*} matches any token or token sub-part in the signature of the program element (a token is an identifier part of a signature, for instance \texttt{A.m(java.lang.String)} contains the token \texttt{A}, \texttt{m}, and \texttt{java.lang.String}).
|
||||
\item \texttt{**} matches any list of tokens in signature of the program element.
|
||||
\item \texttt{..} matches any list of tokens in signature of the program element. (same as \texttt{**})
|
||||
\item \texttt{!} negates the expression (first character only).
|
||||
\end{enumerate}
|
||||
|
||||
\noindent
|
||||
For example:
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
// all the elements and subelements (fields, methods, ...) in the x.y.z package
|
||||
x.y.z.**
|
||||
|
||||
// all the methods in the x.y.z.A class
|
||||
x.y.z.A.*(..)
|
||||
|
||||
// all the methods taking 2 arguments in the \texttt{x.y.z.A} class
|
||||
x.y.z.A.*(*,*)
|
||||
|
||||
// all fields called aField in all the classes of the program
|
||||
**.aField
|
||||
\end{lstlisting}
|
||||
|
||||
\noindent
|
||||
Here is a more complete example with a full \texttt{jsweetconfig.json} configuration file.
|
||||
|
||||
\begin{lstlisting}[language=Java]
|
||||
{
|
||||
// all classes and packages in x.y.z will become top level
|
||||
"@Root": {
|
||||
"include": [ "x.y.z" ]
|
||||
},
|
||||
// do not generate any TypeScript code for write/readObject methods
|
||||
"@Erase": {
|
||||
"include": [ "**.writeObject()", "**.readObject()" ]
|
||||
},
|
||||
// inject logging in all setters and getters of the x.y.z.A class
|
||||
"@Replace('console.info('entering {{methodName}}'); let _result = () => { {{body}} }(); console.info('returning '+result); return result;')": {
|
||||
"include": [ "x.y.z.A.set*(*)", "x.y.z.A.get*()", "x.y.z.A.is*()" ]
|
||||
}
|
||||
}
|
||||
\end{lstlisting}
|
||||
|
||||
Note that the annotation are defined with their simple name only. That's because they are core JSweet annotation (defined in \texttt{jsweet.lang}). Non-core annotations can be added the same way, but the programmer must use the fully qualified name.
|
||||
|
||||
\section{Programmatic tuning with adapters}
|
||||
|
||||
Declarative tuning through annotation rapidly hits limitations when tuning the generation for specific purposes (typically when supporting additional Java libraries). Hence, JSweet provides an API so that programmers can extend the way JSweet generates the intermediate TypeScript code. Writing such an adaptation program is similar to writing a regular Java program, except that it applies to other programs. As such, it falls into the category of so-called meta-programs (i.e. programs that work on programs). Since programmers may write extensions that leads to invalid code, that is where it becomes really handy to have an intermediate compilation layer. If the generated code is invalid, the TypeScript to JavaScript compilation will raise errors, thus allowing the programmer to fix their extension code.
|
||||
|
||||
TBD
|
||||
|
||||
\chapter*{Appendix 1: JSweet transpiler options}
|
||||
|
||||
\begin{small}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user