Merge pull request #604 from cincheo/dev/20200607

Moving forward version 2.4
This commit is contained in:
Renaud Pawlak 2020-07-21 19:13:53 +02:00 committed by GitHub
commit 7d42942707
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 33154 additions and 200 deletions

View File

@ -24,7 +24,9 @@ import java.lang.annotation.Target;
/** /**
* This annotation type is used on elements that should be erased at generation * This annotation type is used on elements that should be erased at generation
* time (casts and constructor invocations are removed). * time. For erased types, casts and constructor invocations are removed. For
* erased methods, invocation are removed, except if the {@link KeepUses}
* annotation is also defined on the erased method..
* *
* @author Renaud Pawlak * @author Renaud Pawlak
*/ */

View File

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.jsweet</groupId> <groupId>org.jsweet</groupId>
<artifactId>jsweet-transpiler</artifactId> <artifactId>jsweet-transpiler</artifactId>
<version>2.3.10-SNAPSHOT</version> <version>2.4.0-SNAPSHOT</version>
<name>JSweet transpiler</name> <name>JSweet transpiler</name>
<description>A Java to TypeScript/JavaScript Open Transpiler</description> <description>A Java to TypeScript/JavaScript Open Transpiler</description>
<url>http://www.jsweet.org</url> <url>http://www.jsweet.org</url>
@ -264,6 +264,12 @@
<scope>test</scope> <scope>test</scope>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.jsweet</groupId>
<artifactId>j4ts</artifactId>
<version>0.6.0</version>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.jsweet.candies</groupId> <groupId>org.jsweet.candies</groupId>
<artifactId>jquery</artifactId> <artifactId>jquery</artifactId>

View File

@ -321,8 +321,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Java compiler's encoding // Java compiler's encoding
optionArg = new FlaggedOption("encoding"); optionArg = new FlaggedOption(JSweetOptions.encoding);
optionArg.setLongFlag("encoding"); optionArg.setLongFlag(JSweetOptions.encoding);
optionArg.setStringParser(JSAP.STRING_PARSER); optionArg.setStringParser(JSAP.STRING_PARSER);
optionArg.setRequired(false); optionArg.setRequired(false);
optionArg.setDefault("UTF-8"); optionArg.setDefault("UTF-8");
@ -330,8 +330,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Output encoding // Output encoding
optionArg = new FlaggedOption("outEncoding"); optionArg = new FlaggedOption(JSweetOptions.outEncoding);
optionArg.setLongFlag("outEncoding"); optionArg.setLongFlag(JSweetOptions.outEncoding);
optionArg.setStringParser(JSAP.STRING_PARSER); optionArg.setStringParser(JSAP.STRING_PARSER);
optionArg.setRequired(false); optionArg.setRequired(false);
optionArg.setDefault("UTF-8"); optionArg.setDefault("UTF-8");
@ -388,9 +388,9 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Definition directories // Definition directories
optionArg = new FlaggedOption("defInput"); optionArg = new FlaggedOption(JSweetOptions.defInput);
optionArg.setShortFlag('d'); optionArg.setShortFlag('d');
optionArg.setLongFlag("defInput"); optionArg.setLongFlag(JSweetOptions.defInput);
optionArg.setList(true); optionArg.setList(true);
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
optionArg.setListSeparator(File.pathSeparatorChar); optionArg.setListSeparator(File.pathSeparatorChar);
@ -400,16 +400,16 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Skip empty root dirs // Skip empty root dirs
switchArg = new Switch("noRootDirectories"); switchArg = new Switch(JSweetOptions.noRootDirectories);
switchArg.setLongFlag("noRootDirectories"); switchArg.setLongFlag(JSweetOptions.noRootDirectories);
switchArg.setHelp( switchArg.setHelp(
"Skip the root directories (i.e. packages annotated with @jsweet.lang.Root) so that the generated file hierarchy starts at the root directories rather than including the entire directory structure."); "Skip the root directories (i.e. packages annotated with @jsweet.lang.Root) so that the generated file hierarchy starts at the root directories rather than including the entire directory structure.");
switchArg.setDefault("false"); switchArg.setDefault("false");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// TypeScript output directory // TypeScript output directory
optionArg = new FlaggedOption("tsout"); optionArg = new FlaggedOption(JSweetOptions.tsout);
optionArg.setLongFlag("tsout"); optionArg.setLongFlag(JSweetOptions.tsout);
optionArg.setDefault(".ts"); optionArg.setDefault(".ts");
optionArg.setHelp("Specify where to place generated TypeScript files."); optionArg.setHelp("Specify where to place generated TypeScript files.");
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
@ -417,9 +417,9 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// JavaScript output directory // JavaScript output directory
optionArg = new FlaggedOption("jsout"); optionArg = new FlaggedOption(JSweetOptions.jsout);
optionArg.setShortFlag('o'); optionArg.setShortFlag('o');
optionArg.setLongFlag("jsout"); optionArg.setLongFlag(JSweetOptions.jsout);
optionArg.setDefault("js"); optionArg.setDefault("js");
optionArg.setHelp("Specify where to place generated JavaScript files (ignored if jsFile is specified)."); optionArg.setHelp("Specify where to place generated JavaScript files (ignored if jsFile is specified).");
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
@ -427,41 +427,48 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Disable single precision floats // Disable single precision floats
switchArg = new Switch("disableSinglePrecisionFloats"); switchArg = new Switch(JSweetOptions.disableSinglePrecisionFloats);
switchArg.setLongFlag("disableSinglePrecisionFloats"); switchArg.setLongFlag(JSweetOptions.disableSinglePrecisionFloats);
switchArg.setHelp( switchArg.setHelp(
"By default, for a target version >=ES5, JSweet will force Java floats to be mapped to JavaScript numbers that will be constrained with ES5 Math.fround function. If this option is true, then the calls to Math.fround are erased and the generated program will use the JavaScript default precision (double precision)."); "By default, for a target version >=ES5, JSweet will force Java floats to be mapped to JavaScript numbers that will be constrained with ES5 Math.fround function. If this option is true, then the calls to Math.fround are erased and the generated program will use the JavaScript default precision (double precision).");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Transients as non-enumerable properties
switchArg = new Switch(JSweetOptions.nonEnumerableTransients);
switchArg.setLongFlag(JSweetOptions.nonEnumerableTransients);
switchArg.setHelp(
"Generate Java transient fields as non-enumerable JavaScript properties..");
jsap.registerParameter(switchArg);
// Do not generate JavaScript // Do not generate JavaScript
switchArg = new Switch("tsOnly"); switchArg = new Switch(JSweetOptions.tsOnly);
switchArg.setLongFlag("tsOnly"); switchArg.setLongFlag(JSweetOptions.tsOnly);
switchArg.setHelp("Do not compile the TypeScript output (let an external TypeScript compiler do so)."); switchArg.setHelp("Do not compile the TypeScript output (let an external TypeScript compiler do so).");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Do not generate d.ts files that correspond to def.* packages // Do not generate d.ts files that correspond to def.* packages
switchArg = new Switch("ignoreDefinitions"); switchArg = new Switch(JSweetOptions.ignoreDefinitions);
switchArg.setLongFlag("ignoreDefinitions"); switchArg.setLongFlag(JSweetOptions.ignoreDefinitions);
switchArg.setHelp( switchArg.setHelp(
"Ignore definitions from def.* packages, so that they are not generated in d.ts definition files. If this option is not set, the transpiler generates d.ts definition files in the directory given by the tsout option."); "Ignore definitions from def.* packages, so that they are not generated in d.ts definition files. If this option is not set, the transpiler generates d.ts definition files in the directory given by the tsout option.");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
switchArg = new Switch("ignoreJavaErrors"); switchArg = new Switch(JSweetOptions.ignoreJavaErrors);
switchArg.setLongFlag("ignoreJavaErrors"); switchArg.setLongFlag(JSweetOptions.ignoreJavaErrors);
switchArg.setHelp( switchArg.setHelp(
"Ignore Java compilation errors. Do not use unless you know what you are doing."); "Ignore Java compilation errors. Do not use unless you know what you are doing.");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Generates declarations // Generates declarations
switchArg = new Switch("declaration"); switchArg = new Switch(JSweetOptions.declaration);
switchArg.setLongFlag("declaration"); switchArg.setLongFlag(JSweetOptions.declaration);
switchArg.setHelp( switchArg.setHelp(
"Generate the d.ts files along with the js files, so that other programs can use them to compile."); "Generate the d.ts files along with the js files, so that other programs can use them to compile.");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Declarations output directory // Declarations output directory
optionArg = new FlaggedOption("dtsout"); optionArg = new FlaggedOption(JSweetOptions.dtsout);
optionArg.setLongFlag("dtsout"); optionArg.setLongFlag(JSweetOptions.dtsout);
optionArg.setHelp( optionArg.setHelp(
"Specify where to place generated d.ts files when the declaration option is set (by default, d.ts files are generated in the JavaScript output directory - next to the corresponding js files)."); "Specify where to place generated d.ts files when the declaration option is set (by default, d.ts files are generated in the JavaScript output directory - next to the corresponding js files).");
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
@ -469,8 +476,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Candies javascript output directory // Candies javascript output directory
optionArg = new FlaggedOption("candiesJsOut"); optionArg = new FlaggedOption(JSweetOptions.candiesJsOut);
optionArg.setLongFlag("candiesJsOut"); optionArg.setLongFlag(JSweetOptions.candiesJsOut);
optionArg.setDefault("js/candies"); optionArg.setDefault("js/candies");
optionArg.setHelp("Specify where to place extracted JavaScript files from candies."); optionArg.setHelp("Specify where to place extracted JavaScript files from candies.");
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
@ -478,8 +485,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Source root directory for source maps // Source root directory for source maps
optionArg = new FlaggedOption("sourceRoot"); optionArg = new FlaggedOption(JSweetOptions.sourceRoot);
optionArg.setLongFlag("sourceRoot"); optionArg.setLongFlag(JSweetOptions.sourceRoot);
optionArg.setHelp( optionArg.setHelp(
"Specify the location where debugger should locate Java files instead of source locations. Use this flag if the sources will be located at run-time in a different location than that at design-time. The location specified will be embedded in the sourceMap to direct the debugger where the source files will be located."); "Specify the location where debugger should locate Java files instead of source locations. Use this flag if the sources will be located at run-time in a different location than that at design-time. The location specified will be embedded in the sourceMap to direct the debugger where the source files will be located.");
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
@ -487,8 +494,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Classpath // Classpath
optionArg = new FlaggedOption("classpath"); optionArg = new FlaggedOption(JSweetOptions.classpath);
optionArg.setLongFlag("classpath"); optionArg.setLongFlag(JSweetOptions.classpath);
optionArg.setHelp( optionArg.setHelp(
"The JSweet transpilation classpath (candy jars). This classpath should at least contain the core candy."); "The JSweet transpilation classpath (candy jars). This classpath should at least contain the core candy.");
optionArg.setStringParser(JSAP.STRING_PARSER); optionArg.setStringParser(JSAP.STRING_PARSER);
@ -496,8 +503,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Module // Module
optionArg = new FlaggedOption("module"); optionArg = new FlaggedOption(JSweetOptions.module);
optionArg.setLongFlag("module"); optionArg.setLongFlag(JSweetOptions.module);
optionArg.setShortFlag('m'); optionArg.setShortFlag('m');
optionArg.setDefault("none"); optionArg.setDefault("none");
optionArg.setHelp("The module kind (none, commonjs, amd, system, umd, es2015)."); optionArg.setHelp("The module kind (none, commonjs, amd, system, umd, es2015).");
@ -515,8 +522,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Bundle // Bundle
switchArg = new Switch("bundle"); switchArg = new Switch(JSweetOptions.bundle);
switchArg.setLongFlag("bundle"); switchArg.setLongFlag(JSweetOptions.bundle);
switchArg.setShortFlag('b'); switchArg.setShortFlag('b');
switchArg.setHelp( switchArg.setHelp(
"Bundle up all the generated code in a single file, which can be used in the browser. The bundle files are called 'bundle.ts', 'bundle.d.ts', or 'bundle.js' depending on the kind of generated code. NOTE: bundles are not compatible with any module kind other than 'none'."); "Bundle up all the generated code in a single file, which can be used in the browser. The bundle files are called 'bundle.ts', 'bundle.d.ts', or 'bundle.js' depending on the kind of generated code. NOTE: bundles are not compatible with any module kind other than 'none'.");
@ -551,23 +558,23 @@ public class JSweetCommandLineLauncher {
// jsap.registerParameter(optionArg); // jsap.registerParameter(optionArg);
// Debug // Debug
switchArg = new Switch("sourceMap"); switchArg = new Switch(JSweetOptions.sourceMap);
switchArg.setLongFlag("sourceMap"); switchArg.setLongFlag(JSweetOptions.sourceMap);
switchArg.setHelp( switchArg.setHelp(
"Generate source map files for the Java files, so that it is possible to debug Java files directly with a debugger that supports source maps (most JavaScript debuggers)."); "Generate source map files for the Java files, so that it is possible to debug Java files directly with a debugger that supports source maps (most JavaScript debuggers).");
switchArg.setDefault("false"); switchArg.setDefault("false");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Enable assertions // Enable assertions
switchArg = new Switch("enableAssertions"); switchArg = new Switch(JSweetOptions.enableAssertions);
switchArg.setLongFlag("enableAssertions"); switchArg.setLongFlag(JSweetOptions.enableAssertions);
switchArg.setHelp("Java 'assert' statements are transpiled as runtime JavaScript checks."); switchArg.setHelp("Java 'assert' statements are transpiled as runtime JavaScript checks.");
switchArg.setDefault("false"); switchArg.setDefault("false");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Header file // Header file
optionArg = new FlaggedOption("header"); optionArg = new FlaggedOption(JSweetOptions.header);
optionArg.setLongFlag("header"); optionArg.setLongFlag(JSweetOptions.header);
optionArg.setHelp( optionArg.setHelp(
"A file that contains a header to be written at the beginning of each generated file. If left unspecified, JSweet will generate a default header."); "A file that contains a header to be written at the beginning of each generated file. If left unspecified, JSweet will generate a default header.");
optionArg.setStringParser(FileStringParser.getParser()); optionArg.setStringParser(FileStringParser.getParser());
@ -583,8 +590,8 @@ public class JSweetCommandLineLauncher {
optionArg.setRequired(false); optionArg.setRequired(false);
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
optionArg = new FlaggedOption("targetVersion"); optionArg = new FlaggedOption(JSweetOptions.targetVersion);
optionArg.setLongFlag("targetVersion"); optionArg.setLongFlag(JSweetOptions.targetVersion);
optionArg.setHelp("The EcmaScript target (JavaScript) version. Possible values: " optionArg.setHelp("The EcmaScript target (JavaScript) version. Possible values: "
+ Arrays.asList(EcmaScriptComplianceLevel.values())); + Arrays.asList(EcmaScriptComplianceLevel.values()));
optionArg.setDefault("ES3"); optionArg.setDefault("ES3");
@ -600,8 +607,8 @@ public class JSweetCommandLineLauncher {
jsap.registerParameter(optionArg); jsap.registerParameter(optionArg);
// Disable statics lazy initialization // Disable statics lazy initialization
switchArg = new Switch("disableStaticsLazyInitialization"); switchArg = new Switch(JSweetOptions.disableStaticsLazyInitialization);
switchArg.setLongFlag("disableStaticsLazyInitialization"); switchArg.setLongFlag(JSweetOptions.disableStaticsLazyInitialization);
switchArg.setHelp( switchArg.setHelp(
"Do not generate lazy initialization code of static fields that is meant " + "Do not generate lazy initialization code of static fields that is meant " +
"to emulate the Java behavior. When disables, the code is more readable " + "to emulate the Java behavior. When disables, the code is more readable " +
@ -609,6 +616,15 @@ public class JSweetCommandLineLauncher {
"static dependencies)."); "static dependencies).");
jsap.registerParameter(switchArg); jsap.registerParameter(switchArg);
// Sort class members
switchArg = new Switch(JSweetOptions.sortClassMembers);
switchArg.setLongFlag(JSweetOptions.sortClassMembers);
switchArg.setHelp(
"If enabled, class members are sorted using " +
"PrinterAdapter#getClassMemberComparator(), to be overloaded by the user to "+
"implement the desired order.");
jsap.registerParameter(switchArg);
return jsap; return jsap;
} }
@ -662,7 +678,7 @@ public class JSweetCommandLineLauncher {
@Override @Override
public void run() throws Exception { public void run() throws Exception {
String classPath = jsapArgs.getString("classpath"); String classPath = jsapArgs.getString(JSweetOptions.classpath);
logger.info("classpath: " + classPath); logger.info("classpath: " + classPath);
ErrorCountTranspilationHandler transpilationHandler = new ErrorCountTranspilationHandler( ErrorCountTranspilationHandler transpilationHandler = new ErrorCountTranspilationHandler(
@ -724,32 +740,32 @@ public class JSweetCommandLineLauncher {
javaInputFiles.addAll(extraJavaInputFiles); javaInputFiles.addAll(extraJavaInputFiles);
File tsOutputDir = null; File tsOutputDir = null;
if (jsapArgs.userSpecified("tsout") && jsapArgs.getFile("tsout") != null) { if (jsapArgs.userSpecified(JSweetOptions.tsout) && jsapArgs.getFile(JSweetOptions.tsout) != null) {
tsOutputDir = jsapArgs.getFile("tsout"); tsOutputDir = jsapArgs.getFile(JSweetOptions.tsout);
tsOutputDir.mkdirs(); tsOutputDir.mkdirs();
} }
logger.info("ts output dir: " + tsOutputDir); logger.info("ts output dir: " + tsOutputDir);
File jsOutputDir = null; File jsOutputDir = null;
if (jsapArgs.userSpecified("jsout") && jsapArgs.getFile("jsout") != null) { if (jsapArgs.userSpecified(JSweetOptions.jsout) && jsapArgs.getFile(JSweetOptions.jsout) != null) {
jsOutputDir = jsapArgs.getFile("jsout"); jsOutputDir = jsapArgs.getFile(JSweetOptions.jsout);
jsOutputDir.mkdirs(); jsOutputDir.mkdirs();
} }
logger.info("js output dir: " + jsOutputDir); logger.info("js output dir: " + jsOutputDir);
File dtsOutputDir = null; File dtsOutputDir = null;
if (jsapArgs.userSpecified("dtsout") && jsapArgs.getFile("dtsout") != null) { if (jsapArgs.userSpecified(JSweetOptions.dtsout) && jsapArgs.getFile(JSweetOptions.dtsout) != null) {
dtsOutputDir = jsapArgs.getFile("dtsout"); dtsOutputDir = jsapArgs.getFile(JSweetOptions.dtsout);
} }
File candiesJsOutputDir = null; File candiesJsOutputDir = null;
if (jsapArgs.userSpecified("candiesJsOut") && jsapArgs.getFile("candiesJsOut") != null) { if (jsapArgs.userSpecified(JSweetOptions.candiesJsOut) && jsapArgs.getFile(JSweetOptions.candiesJsOut) != null) {
candiesJsOutputDir = jsapArgs.getFile("candiesJsOut"); candiesJsOutputDir = jsapArgs.getFile(JSweetOptions.candiesJsOut);
} }
File sourceRootDir = null; File sourceRootDir = null;
if (jsapArgs.userSpecified("sourceRoot") && jsapArgs.getFile("sourceRoot") != null) { if (jsapArgs.userSpecified(JSweetOptions.sourceRoot) && jsapArgs.getFile(JSweetOptions.sourceRoot) != null) {
sourceRootDir = jsapArgs.getFile("sourceRoot"); sourceRootDir = jsapArgs.getFile(JSweetOptions.sourceRoot);
} }
JSweetFactory factory = null; JSweetFactory factory = null;
@ -779,64 +795,70 @@ public class JSweetCommandLineLauncher {
JSweetTranspiler transpiler = new JSweetTranspiler(factory, jsapArgs.getFile("workingDir"), tsOutputDir, JSweetTranspiler transpiler = new JSweetTranspiler(factory, jsapArgs.getFile("workingDir"), tsOutputDir,
jsOutputDir, candiesJsOutputDir, classPath); jsOutputDir, candiesJsOutputDir, classPath);
if (jsapArgs.userSpecified("bundle")) { if (jsapArgs.userSpecified(JSweetOptions.bundle)) {
transpiler.setBundle(jsapArgs.getBoolean("bundle")); transpiler.setBundle(jsapArgs.getBoolean(JSweetOptions.bundle));
} }
if (jsapArgs.userSpecified("noRootDirectories")) { if (jsapArgs.userSpecified(JSweetOptions.noRootDirectories)) {
transpiler.setNoRootDirectories(jsapArgs.getBoolean("noRootDirectories")); transpiler.setNoRootDirectories(jsapArgs.getBoolean(JSweetOptions.noRootDirectories));
} }
if (jsapArgs.userSpecified("sourceMap")) { if (jsapArgs.userSpecified(JSweetOptions.sourceMap)) {
transpiler.setGenerateSourceMaps(jsapArgs.getBoolean("sourceMap")); transpiler.setGenerateSourceMaps(jsapArgs.getBoolean(JSweetOptions.sourceMap));
} }
if (sourceRootDir != null) { if (sourceRootDir != null) {
transpiler.setSourceRoot(sourceRootDir); transpiler.setSourceRoot(sourceRootDir);
} }
if (jsapArgs.userSpecified("module")) { if (jsapArgs.userSpecified(JSweetOptions.module)) {
transpiler.setModuleKind(ModuleKind.valueOf(jsapArgs.getString("module"))); transpiler.setModuleKind(ModuleKind.valueOf(jsapArgs.getString(JSweetOptions.module)));
} }
if (jsapArgs.userSpecified(JSweetOptions.moduleResolution)) { if (jsapArgs.userSpecified(JSweetOptions.moduleResolution)) {
transpiler.setModuleResolution( transpiler.setModuleResolution(
ModuleResolution.valueOf(jsapArgs.getString(JSweetOptions.moduleResolution))); ModuleResolution.valueOf(jsapArgs.getString(JSweetOptions.moduleResolution)));
} }
if (jsapArgs.userSpecified("encoding")) { if (jsapArgs.userSpecified(JSweetOptions.encoding)) {
transpiler.setEncoding(jsapArgs.getString("encoding")); transpiler.setEncoding(jsapArgs.getString(JSweetOptions.encoding));
} }
if (jsapArgs.userSpecified("outEncoding")) { if (jsapArgs.userSpecified(JSweetOptions.outEncoding)) {
transpiler.setOutEncoding(jsapArgs.getString("outEncoding")); transpiler.setOutEncoding(jsapArgs.getString(JSweetOptions.outEncoding));
} }
if (jsapArgs.userSpecified("enableAssertions")) { if (jsapArgs.userSpecified(JSweetOptions.nonEnumerableTransients)) {
transpiler.setIgnoreAssertions(!jsapArgs.getBoolean("enableAssertions")); transpiler.setNonEnumerableTransients(jsapArgs.getBoolean(JSweetOptions.nonEnumerableTransients));
} }
if (jsapArgs.userSpecified("declaration")) { if (jsapArgs.userSpecified(JSweetOptions.enableAssertions)) {
transpiler.setGenerateDeclarations(jsapArgs.getBoolean("declaration")); transpiler.setIgnoreAssertions(!jsapArgs.getBoolean(JSweetOptions.enableAssertions));
} }
if (jsapArgs.userSpecified("tsOnly")) { if (jsapArgs.userSpecified(JSweetOptions.declaration)) {
transpiler.setGenerateJsFiles(!jsapArgs.getBoolean("tsOnly")); transpiler.setGenerateDeclarations(jsapArgs.getBoolean(JSweetOptions.declaration));
} }
if (jsapArgs.userSpecified("ignoreDefinitions")) { if (jsapArgs.userSpecified(JSweetOptions.tsOnly)) {
transpiler.setGenerateDefinitions(!jsapArgs.getBoolean("ignoreDefinitions")); transpiler.setGenerateJsFiles(!jsapArgs.getBoolean(JSweetOptions.tsOnly));
} }
if (jsapArgs.userSpecified("ignoreJavaErrors")) { if (jsapArgs.userSpecified(JSweetOptions.ignoreDefinitions)) {
transpiler.setIgnoreJavaErrors(jsapArgs.getBoolean("ignoreJavaErrors")); transpiler.setGenerateDefinitions(!jsapArgs.getBoolean(JSweetOptions.ignoreDefinitions));
} }
if (jsapArgs.userSpecified("dtsout")) { if (jsapArgs.userSpecified(JSweetOptions.ignoreJavaErrors)) {
transpiler.setIgnoreJavaErrors(jsapArgs.getBoolean(JSweetOptions.ignoreJavaErrors));
}
if (jsapArgs.userSpecified(JSweetOptions.dtsout)) {
transpiler.setDeclarationsOutputDir(dtsOutputDir); transpiler.setDeclarationsOutputDir(dtsOutputDir);
} }
if (jsapArgs.userSpecified("header")) { if (jsapArgs.userSpecified(JSweetOptions.header)) {
transpiler.setHeaderFile(jsapArgs.getFile("header")); transpiler.setHeaderFile(jsapArgs.getFile(JSweetOptions.header));
} }
if (jsapArgs.userSpecified("targetVersion")) { if (jsapArgs.userSpecified(JSweetOptions.targetVersion)) {
transpiler.setEcmaTargetVersion( transpiler.setEcmaTargetVersion(
JSweetTranspiler.getEcmaTargetVersion(jsapArgs.getString("targetVersion"))); JSweetTranspiler.getEcmaTargetVersion(jsapArgs.getString(JSweetOptions.targetVersion)));
} }
if (jsapArgs.userSpecified("disableSinglePrecisionFloats")) { if (jsapArgs.userSpecified(JSweetOptions.disableSinglePrecisionFloats)) {
transpiler.setDisableSinglePrecisionFloats(jsapArgs.getBoolean("disableSinglePrecisionFloats")); transpiler.setDisableSinglePrecisionFloats(jsapArgs.getBoolean(JSweetOptions.disableSinglePrecisionFloats));
} }
if (jsapArgs.userSpecified(JSweetOptions.extraSystemPath)) { if (jsapArgs.userSpecified(JSweetOptions.extraSystemPath)) {
ProcessUtil.addExtraPath(jsapArgs.getString(JSweetOptions.extraSystemPath)); ProcessUtil.addExtraPath(jsapArgs.getString(JSweetOptions.extraSystemPath));
} }
if (jsapArgs.userSpecified("disableStaticsLazyInitialization")) { if (jsapArgs.userSpecified(JSweetOptions.disableStaticsLazyInitialization)) {
transpiler.setLazyInitializedStatics(!jsapArgs.getBoolean("disableStaticsLazyInitialization")); transpiler.setLazyInitializedStatics(!jsapArgs.getBoolean(JSweetOptions.disableStaticsLazyInitialization));
}
if (jsapArgs.userSpecified(JSweetOptions.sortClassMembers)) {
transpiler.setSortClassMembers(jsapArgs.getBoolean(JSweetOptions.sortClassMembers));
} }
if (tsOutputDir != null) { if (tsOutputDir != null) {
@ -848,7 +870,7 @@ public class JSweetCommandLineLauncher {
// transpiler.setAdapters(Arrays.asList(jsapArgs.getStringArray("adapters"))); // transpiler.setAdapters(Arrays.asList(jsapArgs.getStringArray("adapters")));
List<File> files = Arrays.asList(jsapArgs.getFileArray("defInput")); List<File> files = Arrays.asList(jsapArgs.getFileArray(JSweetOptions.defInput));
logger.info("definition input dirs: " + files); logger.info("definition input dirs: " + files);
for (File f : files) { for (File f : files) {

View File

@ -0,0 +1,124 @@
/*
* JSweet transpiler - http://www.jsweet.org
* Copyright (C) 2015 CINCHEO SAS <renaud.pawlak@cincheo.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jsweet.transpiler;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.ElementKind;
import org.jsweet.transpiler.util.Util;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCAssign;
import com.sun.tools.javac.tree.JCTree.JCAssignOp;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.TreeScanner;
/**
* This AST scanner analyzes local variables to determine if they are locally
* assigned and can be assumed constant or not.
*
* @see JSweetContext
* @author Renaud Pawlak
*/
public class ConstAnalyzer extends TreeScanner {
private Set<VarSymbol> modifiedVariables = new HashSet<>();
private ElementKind variableKind = ElementKind.LOCAL_VARIABLE;
private boolean initializationOnly = false;
/**
* Create a constant variable analyzer on local variables only (default).
*/
public ConstAnalyzer() {
}
/**
* Create a constant variable analyzer on the given kind of variable.
*
* @param variableKind the variable kind to analyze (if null, analyzes all kinds
* of variables)
* @param initializationOnly only takes into account direct assignments and not self-dependent modifications
*/
public ConstAnalyzer(ElementKind variableKind, boolean initializationOnly) {
this.variableKind = variableKind;
this.initializationOnly = initializationOnly;
}
/**
* Gets all the local variables that are modified within the program. All other
* local variables can be assumed as constant.
*/
public Set<VarSymbol> getModifiedVariables() {
return modifiedVariables;
}
private void registerModification(JCTree tree) {
Symbol symbol = Util.getAccessedSymbol(tree);
if (symbol != null && (variableKind == null || symbol.getKind() == variableKind)) {
modifiedVariables.add((VarSymbol) symbol);
}
}
@Override
public void visitAssign(JCAssign assign) {
// TODO: should check if rhs contains self reference for initialization only
registerModification(assign.lhs);
super.visitAssign(assign);
}
@Override
public void visitAssignop(JCAssignOp assignOp) {
if (!this.initializationOnly) {
registerModification(assignOp.lhs);
}
super.visitAssignop(assignOp);
}
@Override
public void visitUnary(JCUnary unary) {
switch (unary.getTag()) {
case PREINC:
case POSTINC:
case PREDEC:
case POSTDEC:
if (!this.initializationOnly) {
registerModification(unary.arg);
}
default:
}
super.visitUnary(unary);
}
/**
* Scans a given compilation unit list.
*/
public void process(List<JCCompilationUnit> cuList) {
for (JCCompilationUnit cu : cuList) {
scan(cu);
}
}
}

View File

@ -116,6 +116,17 @@ public class JSweetContext extends Context {
} }
} }
/**
* The constant variables (variables assigned only at initialization) scanner
* and accessor.
*
* <p>TODO: This scanner is run globally (for all compilation units) before
* translation. It could be run locally to each compilation unit, except for
* default methods that are injected in the target classes.
*/
public ConstAnalyzer constAnalyzer = null;
private Map<String, TypeMirror> jdkSubclasses = new HashMap<>(); private Map<String, TypeMirror> jdkSubclasses = new HashMap<>();
public StaticInitilializerAnalyzer referenceAnalyzer; public StaticInitilializerAnalyzer referenceAnalyzer;

View File

@ -71,6 +71,10 @@ public interface JSweetOptions {
* Constant string for the 'ignoreDefinitions' option. * Constant string for the 'ignoreDefinitions' option.
*/ */
String ignoreDefinitions = "ignoreDefinitions"; String ignoreDefinitions = "ignoreDefinitions";
/**
* Constant string for the 'ignoreJavaErrors' option.
*/
String ignoreJavaErrors = "ignoreJavaErrors";
/** /**
* Constant string for the 'header' option. * Constant string for the 'header' option.
*/ */
@ -99,6 +103,14 @@ public interface JSweetOptions {
* Constant string for the 'jsout' option. * Constant string for the 'jsout' option.
*/ */
String jsout = "jsout"; String jsout = "jsout";
/**
* Constant string for the 'sourceRoot' option.
*/
String sourceRoot = "sourceRoot";
/**
* Constant string for the 'defInput' option.
*/
String defInput = "defInput";
/** /**
* Constant string for the 'candiesJsOut' option. * Constant string for the 'candiesJsOut' option.
*/ */
@ -117,13 +129,28 @@ public interface JSweetOptions {
*/ */
String useSingleQuotesForStringLiterals = "useSingleQuotesForStringLiterals"; String useSingleQuotesForStringLiterals = "useSingleQuotesForStringLiterals";
/**
* Constant string for the 'nonEnumerableTransients' option.
*/
String nonEnumerableTransients = "nonEnumerableTransients";
/**
* Constant string for the 'classpath' option.
*/
String classpath = "classpath";
/**
* Constant string for the 'sortClassMembers' option.
*/
String sortClassMembers = "sortClassMembers";
/** /**
* All the supported options (used to report non-blocking errors when options do not exist). * All the supported options (used to report non-blocking errors when options do not exist).
*/ */
String[] options = { bundle, noRootDirectories, sourceMap, module, encoding, outEncoding, enableAssertions, String[] options = { bundle, noRootDirectories, sourceMap, module, encoding, outEncoding, enableAssertions,
declaration, tsOnly, ignoreDefinitions, header, disableSinglePrecisionFloats, declaration, tsOnly, ignoreDefinitions, ignoreJavaErrors, header, disableSinglePrecisionFloats,
disableStaticsLazyInitialization, targetVersion, tsout, dtsout, jsout, candiesJsOut, moduleResolution, disableStaticsLazyInitialization, targetVersion, tsout, dtsout, jsout, candiesJsOut, moduleResolution,
extraSystemPath, useSingleQuotesForStringLiterals }; extraSystemPath, useSingleQuotesForStringLiterals, nonEnumerableTransients, classpath, sortClassMembers };
/** /**
* Returns the configuration from the configuration file. * Returns the configuration from the configuration file.
@ -337,4 +364,15 @@ public interface JSweetOptions {
*/ */
boolean isUseSingleQuotesForStringLiterals(); boolean isUseSingleQuotesForStringLiterals();
/**
* If true, the transpiler generates Java transient fields as non-enumerable
* JavaScript properties.
*/
boolean isNonEnumerableTransients();
/**
* If true, class members are sorted using
* {@link PrinterAdapter#getClassMemberComparator()}.
*/
boolean isSortClassMembers();
} }

View File

@ -241,6 +241,8 @@ public class JSweetTranspiler implements JSweetOptions {
private boolean ignoreCandiesTypeScriptDefinitions = false; private boolean ignoreCandiesTypeScriptDefinitions = false;
private boolean lazyInitializedStatics = true; private boolean lazyInitializedStatics = true;
private boolean useSingleQuotesForStringLiterals = false; private boolean useSingleQuotesForStringLiterals = false;
private boolean nonEnumerableTransients = false;
private boolean sortClassMembers = false;
private ArrayList<String> adapters = new ArrayList<>(); private ArrayList<String> adapters = new ArrayList<>();
private File configurationFile; private File configurationFile;
@ -394,6 +396,12 @@ public class JSweetTranspiler implements JSweetOptions {
} }
if (options.containsKey(JSweetOptions.useSingleQuotesForStringLiterals)) { if (options.containsKey(JSweetOptions.useSingleQuotesForStringLiterals)) {
setUseSingleQuotesForStringLiterals((Boolean) getMapValue(options, JSweetOptions.useSingleQuotesForStringLiterals)); setUseSingleQuotesForStringLiterals((Boolean) getMapValue(options, JSweetOptions.useSingleQuotesForStringLiterals));
}
if (options.containsKey(JSweetOptions.ignoreJavaErrors)) {
setIgnoreJavaErrors((Boolean) getMapValue(options, JSweetOptions.ignoreJavaErrors));
}
if (options.containsKey(JSweetOptions.nonEnumerableTransients)) {
setNonEnumerableTransients((Boolean) getMapValue(options, JSweetOptions.nonEnumerableTransients));
} }
} }
@ -712,11 +720,9 @@ public class JSweetTranspiler implements JSweetOptions {
SourceFile... sourceFiles) throws Exception { SourceFile... sourceFiles) throws Exception {
logger.info("[" + engineName + " engine] eval files: " + Arrays.asList(sourceFiles)); logger.info("[" + engineName + " engine] eval files: " + Arrays.asList(sourceFiles));
EvalOptions options = new EvalOptions(isUsingModules(), workingDir);
if ("Java".equals(engineName)) { if ("Java".equals(engineName)) {
JavaEval evaluator = new JavaEval(this, options); JavaEval evaluator = new JavaEval(this, new EvalOptions(isUsingModules(), workingDir, false));
return evaluator.performEval(sourceFiles); return evaluator.performEval(sourceFiles);
} else { } else {
if (!areAllTranspiled(sourceFiles)) { if (!areAllTranspiled(sourceFiles)) {
@ -747,7 +753,9 @@ public class JSweetTranspiler implements JSweetOptions {
jsFiles = Stream.of(sourceFiles).map(sourceFile -> sourceFile.getJsFile()).collect(toList()); jsFiles = Stream.of(sourceFiles).map(sourceFile -> sourceFile.getJsFile()).collect(toList());
} }
JavaScriptEval evaluator = new JavaScriptEval(options, JavaScriptRuntime.NodeJs); JavaScriptEval evaluator = new JavaScriptEval(
new EvalOptions(isUsingModules(), workingDir, context.isUsingJavaRuntime()),
JavaScriptRuntime.NodeJs);
return evaluator.performEval(jsFiles); return evaluator.performEval(jsFiles);
} }
} }
@ -983,6 +991,8 @@ public class JSweetTranspiler implements JSweetOptions {
List<JCCompilationUnit> compilationUnits) throws IOException { List<JCCompilationUnit> compilationUnits) throws IOException {
// regular file-to-file generation // regular file-to-file generation
new OverloadScanner(transpilationHandler, context).process(compilationUnits); new OverloadScanner(transpilationHandler, context).process(compilationUnits);
context.constAnalyzer = new ConstAnalyzer();
context.constAnalyzer.scan(compilationUnits);
if (isVerbose()) { if (isVerbose()) {
context.dumpOverloads(System.out); context.dumpOverloads(System.out);
@ -1115,6 +1125,8 @@ public class JSweetTranspiler implements JSweetOptions {
} }
new OverloadScanner(transpilationHandler, context).process(orderedCompilationUnits); new OverloadScanner(transpilationHandler, context).process(orderedCompilationUnits);
context.constAnalyzer = new ConstAnalyzer();
context.constAnalyzer.process(orderedCompilationUnits);
adapter.onTranspilationStarted(); adapter.onTranspilationStarted();
@ -1929,4 +1941,22 @@ public class JSweetTranspiler implements JSweetOptions {
this.useSingleQuotesForStringLiterals = useSingleQuotesForStringLiterals; this.useSingleQuotesForStringLiterals = useSingleQuotesForStringLiterals;
} }
@Override
public boolean isNonEnumerableTransients() {
return this.nonEnumerableTransients;
}
public void setNonEnumerableTransients(boolean nonEnumerableTransients) {
this.nonEnumerableTransients = nonEnumerableTransients;
}
@Override
public boolean isSortClassMembers() {
return this.sortClassMembers;
}
public void setSortClassMembers(boolean sortClassMembers) {
this.sortClassMembers = sortClassMembers;
}
} }

View File

@ -66,6 +66,7 @@ import org.jsweet.transpiler.extension.PrinterAdapter;
import org.jsweet.transpiler.model.ExtendedElement; import org.jsweet.transpiler.model.ExtendedElement;
import org.jsweet.transpiler.model.ExtendedElementFactory; import org.jsweet.transpiler.model.ExtendedElementFactory;
import org.jsweet.transpiler.model.MethodInvocationElement; import org.jsweet.transpiler.model.MethodInvocationElement;
import org.jsweet.transpiler.model.TypeCastElement;
import org.jsweet.transpiler.model.support.ArrayAccessElementSupport; import org.jsweet.transpiler.model.support.ArrayAccessElementSupport;
import org.jsweet.transpiler.model.support.AssignmentElementSupport; import org.jsweet.transpiler.model.support.AssignmentElementSupport;
import org.jsweet.transpiler.model.support.AssignmentWithOperatorElementSupport; import org.jsweet.transpiler.model.support.AssignmentWithOperatorElementSupport;
@ -1633,8 +1634,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
printIndent().print("public " + PARENT_CLASS_FIELD_NAME + ": any;").println(); printIndent().print("public " + PARENT_CLASS_FIELD_NAME + ": any;").println();
} }
Set<JCMethodDecl> injectedDefaultMethods = new HashSet<>();
Map<JCMethodDecl, MethodSymbol> injectedDefaultMethodMap = new HashMap<>();
if (defaultMethods != null && !defaultMethods.isEmpty()) { if (defaultMethods != null && !defaultMethods.isEmpty()) {
getScope().defaultMethodScope = true;
for (Entry<JCClassDecl, JCMethodDecl> entry : defaultMethods) { for (Entry<JCClassDecl, JCMethodDecl> entry : defaultMethods) {
if (!(entry.getValue().type instanceof MethodType)) { if (!(entry.getValue().type instanceof MethodType)) {
continue; continue;
@ -1642,37 +1645,11 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
MethodSymbol s = Util.findMethodDeclarationInType2(context.types, classdecl.sym, MethodSymbol s = Util.findMethodDeclarationInType2(context.types, classdecl.sym,
entry.getValue().getName().toString(), (MethodType) entry.getValue().type); entry.getValue().getName().toString(), (MethodType) entry.getValue().type);
if (s == null || s == entry.getValue().sym) { if (s == null || s == entry.getValue().sym) {
getAdapter().typeVariablesToErase injectedDefaultMethods.add(entry.getValue());
.addAll(((ClassSymbol) s.getEnclosingElement()).getTypeParameters()); injectedDefaultMethodMap.put(entry.getValue(), s);
// scan for used types to generate imports
if (context.useModules) {
UsedTypesScanner scanner = new UsedTypesScanner();
JCMethodDecl method = entry.getValue();
if (!context.hasAnnotationType(method.sym, JSweetConfig.ANNOTATION_ERASED)) {
if (context.hasAnnotationType(method.sym, JSweetConfig.ANNOTATION_REPLACE)) {
// do not scan the method body
scanner.scan(method.params);
scanner.scan(method.restype);
scanner.scan(method.thrown);
scanner.scan(method.typarams);
scanner.scan(method.recvparam);
} else {
scanner.scan(method);
} }
} }
} }
if (!context.hasAnnotationType(entry.getValue().sym, JSweetConfig.ANNOTATION_ERASED)) {
printIndent().print(
"/* Default method injected from " + entry.getKey().sym.getQualifiedName() + " */")
.println();
}
printIndent().print(entry.getValue()).println();
getAdapter().typeVariablesToErase
.removeAll(((ClassSymbol) s.getEnclosingElement()).getTypeParameters());
}
}
getScope().defaultMethodScope = false;
}
if (getScope().enumScope) { if (getScope().enumScope) {
printIndent(); printIndent();
@ -1700,7 +1677,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
String prefix = getClassName(classdecl.sym) + "."; String prefix = getClassName(classdecl.sym) + ".";
printIndent().print("static __static_initialize() { "); printIndent().print("static __static_initialize() { ");
print("if(!" + prefix + "__static_initialized) { "); print("if (!" + prefix + "__static_initialized) { ");
print(prefix + "__static_initialized = true; "); print(prefix + "__static_initialized = true; ");
for (int i = 0; i < liCount; i++) { for (int i = 0; i < liCount; i++) {
print(prefix + "__static_initializer_" + i + "(); "); print(prefix + "__static_initializer_" + i + "(); ");
@ -1713,7 +1690,57 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
boolean hasUninitializedFields = false; boolean hasUninitializedFields = false;
List<JCTree> defs = new ArrayList<>();
defs.addAll(injectedDefaultMethods);
defs.addAll(classdecl.defs);
if (context.options.isSortClassMembers()) {
List<JCTree> memberDefs = defs.stream()
.filter(t -> (t instanceof JCMethodDecl || t instanceof JCVariableDecl))
.sorted((t1, t2) -> getAdapter().getClassMemberComparator().compare(
ExtendedElementFactory.INSTANCE.create(t1), ExtendedElementFactory.INSTANCE.create(t2)))
.collect(Collectors.toList());
defs = new ArrayList<>();
defs.addAll(memberDefs);
for (JCTree def : classdecl.defs) { for (JCTree def : classdecl.defs) {
if (!defs.contains(def)) {
defs.add(def);
}
}
}
for (JCTree def : defs) {
if (injectedDefaultMethods.contains(def)) {
JCMethodDecl defaultMethod = (JCMethodDecl) def;
MethodSymbol s = injectedDefaultMethodMap.get(defaultMethod);
getScope().defaultMethodScope = true;
getAdapter().typeVariablesToErase.addAll(((ClassSymbol) s.getEnclosingElement()).getTypeParameters());
// scan for used types to generate imports
if (context.useModules) {
UsedTypesScanner scanner = new UsedTypesScanner();
if (!context.hasAnnotationType(defaultMethod.sym, JSweetConfig.ANNOTATION_ERASED)) {
if (context.hasAnnotationType(defaultMethod.sym, JSweetConfig.ANNOTATION_REPLACE)) {
// do not scan the method body
scanner.scan(defaultMethod.params);
scanner.scan(defaultMethod.restype);
scanner.scan(defaultMethod.thrown);
scanner.scan(defaultMethod.typarams);
scanner.scan(defaultMethod.recvparam);
} else {
scanner.scan(defaultMethod);
}
}
}
if (!context.hasAnnotationType(defaultMethod.sym, JSweetConfig.ANNOTATION_ERASED)) {
printIndent()
.print("/* Default method injected from " + defaultMethod.sym.getEnclosingElement() + " */")
.println();
}
printIndent().print(defaultMethod).println();
getAdapter().typeVariablesToErase.removeAll(((ClassSymbol) s.getEnclosingElement()).getTypeParameters());
getScope().defaultMethodScope = false;
continue;
}
if (getScope().interfaceScope && ((def instanceof JCMethodDecl && ((JCMethodDecl) def).sym.isStatic()) if (getScope().interfaceScope && ((def instanceof JCMethodDecl && ((JCMethodDecl) def).sym.isStatic())
|| (def instanceof JCVariableDecl && ((JCVariableDecl) def).sym.isStatic()))) { || (def instanceof JCVariableDecl && ((JCVariableDecl) def).sym.isStatic()))) {
// static interface members are printed in a namespace // static interface members are printed in a namespace
@ -2568,7 +2595,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
print(" else "); print(" else ");
} }
wasPrinted = true; wasPrinted = true;
print("if("); print("if (");
printMethodParamsTest(overload, method); printMethodParamsTest(overload, method);
print(") "); print(") ");
if (method.sym.isConstructor() if (method.sym.isConstructor()
@ -2615,7 +2642,9 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
} }
print(getOverloadMethodName(method.sym)).print("("); print(getOverloadMethodName(method.sym)).print("(");
for (int j = 0; j < method.getParameters().size(); j++) { for (int j = 0; j < method.getParameters().size(); j++) {
if (j == method.getParameters().size() - 1 && Util.hasVarargs(overload.coreMethod.sym)) { if (j == method.getParameters().size() - 1 && Util.hasVarargs(method.sym)) {
print("...");
} else if (j == method.getParameters().size() - 1 && Util.hasVarargs(overload.coreMethod.sym)) {
print("<any>"); print("<any>");
} }
print(avoidJSKeyword(overload.coreMethod.getParameters().get(j).name.toString())).print(", "); print(avoidJSKeyword(overload.coreMethod.getParameters().get(j).name.toString())).print(", ");
@ -2810,12 +2839,25 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
print(";").println(); print(";").println();
} else if (var.init == null) { } else if (var.init == null) {
if (doesMemberNameRequireQuotes(name)) { if (doesMemberNameRequireQuotes(name)) {
printIndent().print("if(").print("this['").print(name).print("']").print("===undefined) ") printIndent().print("if (").print("this['").print(name).print("']").print(" === undefined) { ");
.print("this['").print(name).print("'] = ").print(getAdapter().getVariableInitialValue(var.sym)) if (context.options.isNonEnumerableTransients() && var.sym.getModifiers().contains(Modifier.TRANSIENT)) {
.print(";").println(); print("Object.defineProperty(this, " + getStringLiteralQuote() + name + getStringLiteralQuote()
+ ", { value: ").print(getAdapter().getVariableInitialValue(var.sym))
.print(", enumerable: false }); }").println();
} else { } else {
printIndent().print("if(").print("this.").print(name).print("===undefined) this.").print(name) print("this['").print(name).print("'] = ").print(getAdapter().getVariableInitialValue(var.sym))
.print(" = ").print(getAdapter().getVariableInitialValue(var.sym)).print(";").println(); .print("; }").println();
}
} else {
printIndent().print("if (").print("this.").print(name).print(" === undefined) { ");
if (context.options.isNonEnumerableTransients() && var.sym.getModifiers().contains(Modifier.TRANSIENT)) {
print("Object.defineProperty(this, " + getStringLiteralQuote() + name + getStringLiteralQuote()
+ ", { value: ").print(getAdapter().getVariableInitialValue(var.sym))
.print(", enumerable: false }); }").println();
} else {
print("this.").print(name).print(" = ").print(getAdapter().getVariableInitialValue(var.sym))
.print("; }").println();
}
} }
} }
} }
@ -2887,7 +2929,6 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
} }
if (method.getBody() != null) { if (method.getBody() != null) {
boolean skipFirst = false; boolean skipFirst = false;
boolean initialized = false;
if (!method.getBody().stats.isEmpty() && method.getBody().stats.get(0).toString().startsWith("this(")) { if (!method.getBody().stats.isEmpty() && method.getBody().stats.get(0).toString().startsWith("this(")) {
skipFirst = true; skipFirst = true;
JCMethodInvocation inv = (JCMethodInvocation) ((JCExpressionStatement) method.getBody().stats JCMethodInvocation inv = (JCMethodInvocation) ((JCExpressionStatement) method.getBody().stats
@ -2897,7 +2938,6 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
for (JCMethodDecl md : overload.methods) { for (JCMethodDecl md : overload.methods) {
if (md.sym.equals(ms)) { if (md.sym.equals(ms)) {
printIndent(); printIndent();
initialized = true;
printInlinedMethod(overload, md, inv.args); printInlinedMethod(overload, md, inv.args);
println(); println();
} }
@ -2914,21 +2954,17 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
enter(method.getBody()); enter(method.getBody());
com.sun.tools.javac.util.List<JCStatement> stats = skipFirst ? method.getBody().stats.tail com.sun.tools.javac.util.List<JCStatement> stats = skipFirst ? method.getBody().stats.tail
: method.getBody().stats; : method.getBody().stats;
if (method.sym.isConstructor()) {
getScope().hasDeclaredConstructor = true;
}
if (!stats.isEmpty() && stats.head.toString().startsWith("super(")) { if (!stats.isEmpty() && stats.head.toString().startsWith("super(")) {
printBlockStatement(stats.head); printBlockStatement(stats.head);
printFieldInitializations(); printFieldInitializations(stats);
if (!initialized) {
printInstanceInitialization(getParent(JCClassDecl.class), method.sym);
}
if (!stats.tail.isEmpty()) { if (!stats.tail.isEmpty()) {
printIndent().print("((").print(") => {").startIndent().println();
printBlockStatements(stats.tail); printBlockStatements(stats.tail);
endIndent().printIndent().print("})(").print(");").println();
} }
} else { } else {
if (!initialized) { printFieldInitializations(stats);
printInstanceInitialization(getParent(JCClassDecl.class), method.sym);
}
if (!stats.isEmpty() || !method.sym.isConstructor()) { if (!stats.isEmpty() || !method.sym.isConstructor()) {
printIndent(); printIndent();
} }
@ -2970,7 +3006,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
endIndent().printIndent().print("}"); endIndent().printIndent().print("}");
} }
private void printFieldInitializations() { private void printFieldInitializations(List<JCStatement> potentialInitializationStatements) {
JCClassDecl clazz = getParent(JCClassDecl.class); JCClassDecl clazz = getParent(JCClassDecl.class);
for (JCTree t : clazz.getMembers()) { for (JCTree t : clazz.getMembers()) {
if (t instanceof JCVariableDecl && !getScope().fieldsWithInitializers.contains(t)) { if (t instanceof JCVariableDecl && !getScope().fieldsWithInitializers.contains(t)) {
@ -2980,9 +3016,15 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
if (context.getFieldNameMapping(field.sym) != null) { if (context.getFieldNameMapping(field.sym) != null) {
name = context.getFieldNameMapping(field.sym); name = context.getFieldNameMapping(field.sym);
} }
printIndent().print("if(").print("this.").print(name).print("===undefined) ").print("this.") printIndent().print("if (").print("this.").print(name).print(" === undefined) { ");
.print(name).print(" = ").print(getAdapter().getVariableInitialValue(field.sym)).print(";") if (context.options.isNonEnumerableTransients() && field.sym.getModifiers().contains(Modifier.TRANSIENT)) {
.println(); print("Object.defineProperty(this, " + getStringLiteralQuote() + name + getStringLiteralQuote()
+ ", { value: ").print(getAdapter().getVariableInitialValue(field.sym))
.print(", enumerable: false }); }").println();
} else {
print("this.").print(name).print(" = ").print(getAdapter().getVariableInitialValue(field.sym))
.print("; }").println();
}
} }
} }
} }
@ -3114,6 +3156,14 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
int i = 0; int i = 0;
for (; i < m.getParameters().size(); i++) { for (; i < m.getParameters().size(); i++) {
print("("); print("(");
if (Class.class.getName().equals(context.types.erasure(m.getParameters().get(i).type).toString())
&& m.getParameters().get(i).type.getTypeArguments().head != null
&& m.getParameters().get(i).type.getTypeArguments().head.isInterface()) {
print(avoidJSKeyword(overload.coreMethod.getParameters().get(i).name.toString())).print(" === ");
print(getStringLiteralQuote()).print(m.getParameters().get(i).type.getTypeArguments().head.toString())
.print(getStringLiteralQuote());
print(" || ");
}
printInstanceOf(avoidJSKeyword(overload.coreMethod.getParameters().get(i).name.toString()), null, printInstanceOf(avoidJSKeyword(overload.coreMethod.getParameters().get(i).name.toString()), null,
m.getParameters().get(i).type); m.getParameters().get(i).type);
checkType(m.getParameters().get(i).type.tsym); checkType(m.getParameters().get(i).type.tsym);
@ -3124,6 +3174,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
} }
for (; i < overload.coreMethod.getParameters().size(); i++) { for (; i < overload.coreMethod.getParameters().size(); i++) {
print(avoidJSKeyword(overload.coreMethod.getParameters().get(i).name.toString())).print(" === undefined"); print(avoidJSKeyword(overload.coreMethod.getParameters().get(i).name.toString())).print(" === undefined");
if (i == overload.coreMethod.getParameters().size() - 1 && overload.coreMethod.sym.isVarArgs()) {
print(" || ");
print(avoidJSKeyword(overload.coreMethod.getParameters().get(i).name.toString())).print(".length === 0");
}
print(" && "); print(" && ");
} }
removeLastChars(4); removeLastChars(4);
@ -3382,12 +3436,21 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
} }
} }
if (!(inArgListTail && (parent instanceof JCForLoop))) { if (!(inArgListTail && (parent instanceof JCForLoop))) {
if (!getAdapter().substituteVariableDeclarationKeyword(varDecl.sym)) {
if (isDefinitionScope) { if (isDefinitionScope) {
print("var "); print("var ");
} else {
if (!isLazyInitialized(varDecl.sym) && ((!globals && context.constAnalyzer != null
&& !context.constAnalyzer.getModifiedVariables().contains(varDecl.sym))
|| (globals && varDecl.sym.getModifiers().contains(Modifier.FINAL)
&& varDecl.init != null))) {
print("const ");
} else { } else {
print(VAR_DECL_KEYWORD + " "); print(VAR_DECL_KEYWORD + " ");
} }
} }
}
}
} else { } else {
if (ambient) { if (ambient) {
report(varDecl, varDecl.name, JSweetProblem.WRONG_USE_OF_AMBIENT, varDecl.name); report(varDecl, varDecl.name, JSweetProblem.WRONG_USE_OF_AMBIENT, varDecl.name);
@ -3460,7 +3523,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
} }
} }
if (varDecl.init != null && !isDefinitionScope) { if (varDecl.init != null && !isDefinitionScope) {
print("if(" + prefix).print(name).print(" == null) ").print(prefix).print(name).print(" = "); print("if (" + prefix).print(name).print(" == null) { ").print(prefix).print(name).print(" = ");
/* /*
* if (getScope().enumWrapperClassScope) { JCNewClass newClass = (JCNewClass) * if (getScope().enumWrapperClassScope) { JCNewClass newClass = (JCNewClass)
* varDecl.init; print("new " * varDecl.init; print("new "
@ -3471,7 +3534,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
print(varDecl.init); print(varDecl.init);
} }
// } // }
print("; "); print("; }");
} }
print("return ").print(prefix).print(name).print("; }"); print("return ").print(prefix).print(name).print("; }");
if (!globals && context.bundleMode) { if (!globals && context.bundleMode) {
@ -4519,13 +4582,13 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
println().endIndent().printIndent().print("}"); println().endIndent().printIndent().print("}");
if (!interfaces.isEmpty()) { if (!interfaces.isEmpty()) {
print(", '" + INTERFACES_FIELD_NAME + "', { configurable: true, value: "); print(", 'constructor', { configurable: true, value: { " + INTERFACES_FIELD_NAME +": ");
print("["); print("[");
for (String i : interfaces) { for (String i : interfaces) {
print(getStringLiteralQuote()).print(i).print(getStringLiteralQuote() + ","); print(getStringLiteralQuote()).print(i).print(getStringLiteralQuote() + ",");
} }
removeLastChar(); removeLastChar();
print("]"); print("] }");
print(" })"); print(" })");
} }
} else { } else {
@ -4969,7 +5032,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
*/ */
@Override @Override
public void visitIf(JCIf ifStatement) { public void visitIf(JCIf ifStatement) {
print("if").print(ifStatement.cond).print(" "); print("if ").print(ifStatement.cond).print(" ");
print(ifStatement.thenpart); print(ifStatement.thenpart);
if (!(ifStatement.thenpart instanceof JCBlock)) { if (!(ifStatement.thenpart instanceof JCBlock)) {
if (!statementsWithNoSemis.contains(ifStatement.thenpart.getClass())) { if (!statementsWithNoSemis.contains(ifStatement.thenpart.getClass())) {
@ -5242,7 +5305,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
} }
} else { } else {
print("<any> (function(dims) { " + VAR_DECL_KEYWORD print("<any> (function(dims) { " + VAR_DECL_KEYWORD
+ " allocate = function(dims) { if(dims.length==0) { return " + " allocate = function(dims) { if (dims.length === 0) { return "
+ Util.getTypeInitialValue(newArray.elemtype.type) + "; } else { " + VAR_DECL_KEYWORD + Util.getTypeInitialValue(newArray.elemtype.type) + "; } else { " + VAR_DECL_KEYWORD
+ " array = []; for(" + VAR_DECL_KEYWORD + " array = []; for(" + VAR_DECL_KEYWORD
+ " i = 0; i < dims[0]; i++) { array.push(allocate(dims.slice(1))); } return array; }}; return allocate(dims);})"); + " i = 0; i < dims[0]; i++) { array.push(allocate(dims.slice(1))); } return array; }}; return allocate(dims);})");
@ -5335,11 +5398,14 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
@Override @Override
public void visitSwitch(JCSwitch switchStatement) { public void visitSwitch(JCSwitch switchStatement) {
print("switch("); print("switch(");
if (!getAdapter()
.substituteSwitchStatementSelector(ExtendedElementFactory.INSTANCE.create(switchStatement.selector))) {
print(switchStatement.selector); print(switchStatement.selector);
if (context.types.isSameType(context.symtab.charType, if (context.types.isSameType(context.symtab.charType,
context.types.unboxedTypeOrType(switchStatement.selector.type))) { context.types.unboxedTypeOrType(switchStatement.selector.type))) {
print(".charCodeAt(0)"); print(".charCodeAt(0)");
} }
}
print(") {").println(); print(") {").println();
for (JCCase caseStatement : switchStatement.cases) { for (JCCase caseStatement : switchStatement.cases) {
printIndent(); printIndent();
@ -5416,6 +5482,9 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
if (substituteAssignedExpression(cast.type, cast.expr)) { if (substituteAssignedExpression(cast.type, cast.expr)) {
return; return;
} }
if (getAdapter().substituteTypeCast((TypeCastElement)ExtendedElementFactory.INSTANCE.create(cast))) {
return;
}
if (Util.isIntegral(cast.type)) { if (Util.isIntegral(cast.type)) {
if (cast.type.getKind() == TypeKind.LONG) { if (cast.type.getKind() == TypeKind.LONG) {
print("(n => n<0?Math.ceil(n):Math.floor(n))("); print("(n => n<0?Math.ceil(n):Math.floor(n))(");
@ -5801,7 +5870,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
if (context.isInterface(type.tsym)) { if (context.isInterface(type.tsym)) {
print(" != null && "); print(" != null && ");
print("("); print("(");
print(exprStr, expr); /*print(exprStr, expr);
if (checkFirstArrayElement) if (checkFirstArrayElement)
print("[0]"); print("[0]");
print("[" + getStringLiteralQuote() + INTERFACES_FIELD_NAME + getStringLiteralQuote() + "]") print("[" + getStringLiteralQuote() + INTERFACES_FIELD_NAME + getStringLiteralQuote() + "]")
@ -5809,9 +5878,10 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
print(exprStr, expr); print(exprStr, expr);
if (checkFirstArrayElement) if (checkFirstArrayElement)
print("[0]"); print("[0]");
print("[" + getStringLiteralQuote() + INTERFACES_FIELD_NAME + getStringLiteralQuote() print("[" + getStringLiteralQuote() + INTERFACES_FIELD_NAME
+ "].indexOf(\"").print(type.tsym.getQualifiedName().toString()).print("\") >= 0"); + getStringLiteralQuote() + "].indexOf(\"")
print(" || "); .print(type.tsym.getQualifiedName().toString()).print("\") >= 0");
print(" || ");*/
print(exprStr, expr); print(exprStr, expr);
if (checkFirstArrayElement) if (checkFirstArrayElement)
print("[0]"); print("[0]");
@ -5833,6 +5903,20 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
print("[0]"); print("[0]");
print(" === " + getStringLiteralQuote() + "string" + getStringLiteralQuote()); print(" === " + getStringLiteralQuote() + "string" + getStringLiteralQuote());
} }
print(")");
} else if (Class.class.getName().equals(type.tsym.getQualifiedName().toString())) {
print(" != null && ");
print("(");
print(exprStr, expr);
if (checkFirstArrayElement)
print("[0]");
print("[" + getStringLiteralQuote() + CLASS_NAME_IN_CONSTRUCTOR
+ getStringLiteralQuote() + "]").print(" != null");
print(" || ((t) => { try { new t; return true; } catch { return false; } })(");
print(exprStr, expr);
if (checkFirstArrayElement)
print("[0]");
print(")");
print(")"); print(")");
} else { } else {
if (type.tsym instanceof TypeVariableSymbol if (type.tsym instanceof TypeVariableSymbol
@ -5860,7 +5944,7 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
print(exprStr, expr); print(exprStr, expr);
if (checkFirstArrayElement) if (checkFirstArrayElement)
print("[0]"); print("[0]");
print(".length==0 || "); print(".length == 0 || ");
print(exprStr, expr); print(exprStr, expr);
print("[0] == null ||"); print("[0] == null ||");
if (t.elemtype instanceof ArrayType) { if (t.elemtype instanceof ArrayType) {
@ -5904,8 +5988,8 @@ public class Java2TypeScriptTranslator extends AbstractTreePrinter {
public void visitAssert(JCAssert assertion) { public void visitAssert(JCAssert assertion) {
if (!context.options.isIgnoreAssertions()) { if (!context.options.isIgnoreAssertions()) {
String assertCode = assertion.toString().replace("\"", "'"); String assertCode = assertion.toString().replace("\"", "'");
print("if(!(").print(assertion.cond).print( print("if (!(").print(assertion.cond).print(
")) throw new Error(\"Assertion error line " + getCurrentLine() + ": " + assertCode + "\");"); ")) { throw new Error(\"Assertion error line " + getCurrentLine() + ": " + assertCode + "\"); }");
} }
} }

View File

@ -5,10 +5,12 @@ import java.io.File;
public class EvalOptions { public class EvalOptions {
public final boolean useModules; public final boolean useModules;
public final File workingDir; public final File workingDir;
public final boolean useJavaRuntime;
public EvalOptions(boolean useModules, File workingDir) { public EvalOptions(boolean useModules, File workingDir, boolean useJavaRuntime) {
this.useModules = useModules; this.useModules = useModules;
this.workingDir = workingDir; this.workingDir = workingDir;
this.useJavaRuntime = useJavaRuntime;
} }
} }

View File

@ -3,8 +3,10 @@ package org.jsweet.transpiler.eval;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
@ -52,6 +54,12 @@ public class JavaScriptEval extends RuntimeEval {
File tmpFile = new File(options.workingDir, "eval.tmp_" + System.currentTimeMillis() + ".js"); File tmpFile = new File(options.workingDir, "eval.tmp_" + System.currentTimeMillis() + ".js");
FileUtils.deleteQuietly(tmpFile); FileUtils.deleteQuietly(tmpFile);
if (options.useJavaRuntime) {
List<File> newFiles = new ArrayList<>(jsFiles);
newFiles.add(0, new File("src/test/resources/j4ts.js"));
jsFiles = newFiles;
}
Set<File> alreadyWrittenScripts = new HashSet<>(); Set<File> alreadyWrittenScripts = new HashSet<>();
for (File jsFile : jsFiles) { for (File jsFile : jsFiles) {
if (!alreadyWrittenScripts.contains(jsFile)) { if (!alreadyWrittenScripts.contains(jsFile)) {
@ -61,7 +69,7 @@ public class JavaScriptEval extends RuntimeEval {
} }
} }
logger.info("[no modules] eval file: " + tmpFile + " jsFiles=" + jsFiles); logger.info("[no modules] eval file: " + tmpFile + " jsFiles=" + jsFiles + ", useJavaRuntime=" + options.useJavaRuntime);
runProcess = runScript(trace, tmpFile); runProcess = runScript(trace, tmpFile);
} }

View File

@ -72,6 +72,7 @@ import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.type.PrimitiveType;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeMirror;
@ -1249,14 +1250,14 @@ public class Java2TypeScriptAdapter extends PrinterAdapter {
switch (targetMethodName) { switch (targetMethodName) {
case "getName": case "getName":
printMacroName(targetMethodName); printMacroName(targetMethodName);
getPrinter().print("(c => c[\"" + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"]?c[\"" getPrinter().print("(c => typeof c === 'string'?c:c[\"" + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"]?c[\""
+ Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"]:c[\"name\"])("); + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"]:c[\"name\"])(");
printTarget(invocationElement.getTargetExpression()); printTarget(invocationElement.getTargetExpression());
print(")"); print(")");
return true; return true;
case "getSimpleName": case "getSimpleName":
printMacroName(targetMethodName); printMacroName(targetMethodName);
print("(c => c[\"" + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"]?c[\"" print("(c => typeof c === 'string'?(<any>c).substring((<any>c).lastIndexOf('.')+1):c[\"" + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"]?c[\""
+ Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"].substring(c[\"" + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + "\"].substring(c[\""
+ Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR + Java2TypeScriptTranslator.CLASS_NAME_IN_CONSTRUCTOR
+ "\"].lastIndexOf('.')+1):c[\"name\"].substring(c[\"name\"].lastIndexOf('.')+1))("); + "\"].lastIndexOf('.')+1):c[\"name\"].substring(c[\"name\"].lastIndexOf('.')+1))(");
@ -1285,15 +1286,25 @@ public class Java2TypeScriptAdapter extends PrinterAdapter {
} else { } else {
switch (targetMethodName) { switch (targetMethodName) {
case "equals": case "equals":
if (types().isSameType(invocationElement.getTargetExpression().getType(), TypeMirror t1 = util().toPrimitiveTypeOrType(invocationElement.getTargetExpression().getType());
util().getType(String.class)) TypeMirror t2 = util().toPrimitiveTypeOrType(invocationElement.getArgument(0).getType());
|| util().isNumber(invocationElement.getTargetExpression().getType())) { if (types().isSameType(t1, t2) && util().isCoreType(t1)) {
if(isInlinedExpression(invocationElement)) { if (isInlinedExpression(invocationElement)) {
print("("); print("(");
} }
print(invocationElement.getTargetExpression()).print(" === ") print(invocationElement.getTargetExpression()).print(" === ");
.print(invocationElement.getArgument(0)); ExtendedElement arg = invocationElement.getArgument(0);
if(isInlinedExpression(invocationElement)) { boolean inlinable = arg instanceof VariableAccessElement
|| (arg instanceof MethodInvocationElement
&& !"equals".equals(((MethodInvocationElement) arg).getMethodName()));
if (!inlinable) {
print("(");
}
print(invocationElement.getArgument(0));
if (!inlinable) {
print(")");
}
if (isInlinedExpression(invocationElement)) {
print(")"); print(")");
} }
} else { } else {

View File

@ -19,6 +19,7 @@
package org.jsweet.transpiler.extension; package org.jsweet.transpiler.extension;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.Comparator;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -49,6 +50,7 @@ import org.jsweet.transpiler.model.AssignmentElement;
import org.jsweet.transpiler.model.AssignmentWithOperatorElement; import org.jsweet.transpiler.model.AssignmentWithOperatorElement;
import org.jsweet.transpiler.model.BinaryOperatorElement; import org.jsweet.transpiler.model.BinaryOperatorElement;
import org.jsweet.transpiler.model.CaseElement; import org.jsweet.transpiler.model.CaseElement;
import org.jsweet.transpiler.model.TypeCastElement;
import org.jsweet.transpiler.model.CompilationUnitElement; import org.jsweet.transpiler.model.CompilationUnitElement;
import org.jsweet.transpiler.model.ExtendedElement; import org.jsweet.transpiler.model.ExtendedElement;
import org.jsweet.transpiler.model.ForeachLoopElement; import org.jsweet.transpiler.model.ForeachLoopElement;
@ -1053,6 +1055,13 @@ public class PrinterAdapter {
return parentAdapter == null ? false : parentAdapter.substituteInstanceof(exprStr, expr, type); return parentAdapter == null ? false : parentAdapter.substituteInstanceof(exprStr, expr, type);
} }
/**
* Substitutes if necessary a type cast expression.
*/
public boolean substituteTypeCast(TypeCastElement castExpression) {
return parentAdapter == null ? false : parentAdapter.substituteTypeCast(castExpression);
}
/** /**
* Substitutes if necessary the pattern of a case statement. * Substitutes if necessary the pattern of a case statement.
*/ */
@ -1060,6 +1069,13 @@ public class PrinterAdapter {
return parentAdapter == null ? false : parentAdapter.substituteCaseStatementPattern(caseStatement, pattern); return parentAdapter == null ? false : parentAdapter.substituteCaseStatementPattern(caseStatement, pattern);
} }
/**
* Substitutes if necessary the selector expression of a switch statement.
*/
public boolean substituteSwitchStatementSelector(ExtendedElement selector) {
return parentAdapter == null ? false : parentAdapter.substituteSwitchStatementSelector(selector);
}
/** /**
* This method is called after a type was printed. * This method is called after a type was printed.
*/ */
@ -1204,4 +1220,36 @@ public class PrinterAdapter {
return printer.isInlinedExpression(((ExtendedElementSupport<?>) element).getTree()); return printer.isInlinedExpression(((ExtendedElementSupport<?>) element).getTree());
} }
/**
* Returns a comparator that will control the order of class members for output
* (default will keep order of appearance in the source code).
*/
public Comparator<ExtendedElement> getClassMemberComparator() {
if (parentAdapter == null) {
return new Comparator<ExtendedElement>() {
@Override
public int compare(ExtendedElement e1, ExtendedElement e2) {
return e1.getStartSourcePosition() - e2.getStartSourcePosition();
}
};
} else {
return parentAdapter.getClassMemberComparator();
}
}
/**
* Optionally substitutes the default variable declaration keyword
* (<code>var</code>, <code>let</code>, <code>const</code>) for the given
* variable. By default, regular variables are declared with the
* <code>let</code> keyword, except for unmodified variables, which are declared
* with the <code>const</code> keyword.
*
* @param variable the target variable
* @return true if the default keyword has been substituted, false otherwise
* (default is false)
*/
public boolean substituteVariableDeclarationKeyword(VariableElement variable) {
return parentAdapter == null ? false : parentAdapter.substituteVariableDeclarationKeyword(variable);
}
} }

View File

@ -0,0 +1,7 @@
package org.jsweet.transpiler.model;
public interface ExecutableElement extends ExtendedElement, javax.lang.model.element.ExecutableElement {
javax.lang.model.element.ExecutableElement getStandardElement();
}

View File

@ -69,4 +69,9 @@ public interface ExtendedElement {
*/ */
boolean isStringLiteral(); boolean isStringLiteral();
/**
* Gets the start position of the element in the source code.
*/
int getStartSourcePosition();
} }

View File

@ -25,6 +25,7 @@ import org.jsweet.transpiler.model.support.AssignmentElementSupport;
import org.jsweet.transpiler.model.support.BinaryOperatorElementSupport; import org.jsweet.transpiler.model.support.BinaryOperatorElementSupport;
import org.jsweet.transpiler.model.support.CaseElementSupport; import org.jsweet.transpiler.model.support.CaseElementSupport;
import org.jsweet.transpiler.model.support.CompilationUnitElementSupport; import org.jsweet.transpiler.model.support.CompilationUnitElementSupport;
import org.jsweet.transpiler.model.support.ExecutableElementSupport;
import org.jsweet.transpiler.model.support.ExtendedElementSupport; import org.jsweet.transpiler.model.support.ExtendedElementSupport;
import org.jsweet.transpiler.model.support.ForeachLoopElementSupport; import org.jsweet.transpiler.model.support.ForeachLoopElementSupport;
import org.jsweet.transpiler.model.support.IdentifierElementSupport; import org.jsweet.transpiler.model.support.IdentifierElementSupport;
@ -33,8 +34,10 @@ import org.jsweet.transpiler.model.support.LiteralElementSupport;
import org.jsweet.transpiler.model.support.MethodInvocationElementSupport; import org.jsweet.transpiler.model.support.MethodInvocationElementSupport;
import org.jsweet.transpiler.model.support.NewArrayElementSupport; import org.jsweet.transpiler.model.support.NewArrayElementSupport;
import org.jsweet.transpiler.model.support.NewClassElementSupport; import org.jsweet.transpiler.model.support.NewClassElementSupport;
import org.jsweet.transpiler.model.support.TypeCastElementSupport;
import org.jsweet.transpiler.model.support.UnaryOperatorElementSupport; import org.jsweet.transpiler.model.support.UnaryOperatorElementSupport;
import org.jsweet.transpiler.model.support.VariableAccessElementSupport; import org.jsweet.transpiler.model.support.VariableAccessElementSupport;
import org.jsweet.transpiler.model.support.VariableElementSupport;
import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCArrayAccess; import com.sun.tools.javac.tree.JCTree.JCArrayAccess;
@ -47,10 +50,13 @@ import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent; import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCImport; import com.sun.tools.javac.tree.JCTree.JCImport;
import com.sun.tools.javac.tree.JCTree.JCLiteral; import com.sun.tools.javac.tree.JCTree.JCLiteral;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCNewArray; import com.sun.tools.javac.tree.JCTree.JCNewArray;
import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCUnary; import com.sun.tools.javac.tree.JCTree.JCUnary;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
/** /**
* A factory to create extended elements. It defines an overloaded create method * A factory to create extended elements. It defines an overloaded create method
@ -91,6 +97,10 @@ public class ExtendedElementFactory {
return null; return null;
} }
switch (tree.getTag()) { switch (tree.getTag()) {
case METHODDEF:
return new ExecutableElementSupport((JCMethodDecl) tree);
case VARDEF:
return new VariableElementSupport((JCVariableDecl) tree);
case APPLY: case APPLY:
return new MethodInvocationElementSupport((JCMethodInvocation) tree); return new MethodInvocationElementSupport((JCMethodInvocation) tree);
case SELECT: case SELECT:
@ -147,6 +157,8 @@ public class ExtendedElementFactory {
case POSTDEC: case POSTDEC:
case POSTINC: case POSTINC:
return new UnaryOperatorElementSupport((JCUnary) tree); return new UnaryOperatorElementSupport((JCUnary) tree);
case TYPECAST:
return new TypeCastElementSupport((JCTypeCast) tree);
default: default:
return new ExtendedElementSupport<>(tree); return new ExtendedElementSupport<>(tree);
} }

View File

@ -43,4 +43,15 @@ public interface ForeachLoopElement extends ExtendedElement {
*/ */
ExtendedElement getBody(); ExtendedElement getBody();
/**
* Returns true if the loop contains a control flow statement
* (<code>break</code>, <code>continue</code>, <code>return</code>).
*/
boolean hasControlFlowStatement();
/**
* Returns true if the iteration variable is modified within the loop body.
*/
boolean isIterationVariableModified();
} }

View File

@ -0,0 +1,38 @@
/*
* JSweet transpiler - http://www.jsweet.org
* Copyright (C) 2015 CINCHEO SAS <renaud.pawlak@cincheo.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jsweet.transpiler.model;
/**
* An AST node for a Java cast expression.
*
* @author Renaud Pawlak
*/
public interface TypeCastElement extends ExtendedElement {
/**
* Gets the target type expression.
*/
public ExtendedElement getTargetTypeExpression();
/**
* Gets the expression being cast.
*/
public ExtendedElement getExpression();
}

View File

@ -56,6 +56,11 @@ public interface Util {
*/ */
boolean isNumber(TypeMirror type); boolean isNumber(TypeMirror type);
/**
* Tells if the given type is a boolean.
*/
boolean isBoolean(TypeMirror type);
/** /**
* Tells if the given element is deprecated. * Tells if the given element is deprecated.
*/ */
@ -117,4 +122,21 @@ public interface Util {
*/ */
String getTypeInitialValue(TypeMirror type); String getTypeInitialValue(TypeMirror type);
/**
* Gets all the members of the given type, including members within the super
* classes.
*
* @param typeElement the typeElement
* @return a list of all the members
*/
List<Element> getAllMembers(TypeElement typeElement);
/**
* Gets the type as a primitive type (by unboxing it) when possible.
*
* @param type the origin type
* @return the origin type or the corresponding primitive type if possible
*/
TypeMirror toPrimitiveTypeOrType(TypeMirror type);
} }

View File

@ -0,0 +1,7 @@
package org.jsweet.transpiler.model;
public interface VariableElement extends ExtendedElement, javax.lang.model.element.VariableElement {
javax.lang.model.element.VariableElement getStandardElement();
}

View File

@ -0,0 +1,123 @@
package org.jsweet.transpiler.model.support;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.element.TypeParameterElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import org.jsweet.transpiler.model.ExecutableElement;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
public class ExecutableElementSupport extends ExtendedElementSupport<JCMethodDecl> implements ExecutableElement {
public ExecutableElementSupport(JCMethodDecl tree) {
super(tree);
}
@Override
public javax.lang.model.element.ExecutableElement getStandardElement() {
return tree.sym;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return tree.sym.accept(v, p);
}
@Override
public TypeMirror asType() {
return tree.sym.asType();
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return tree.sym.getAnnotation(annotationType);
}
@Override
public List<? extends AnnotationMirror> getAnnotationMirrors() {
return tree.sym.getAnnotationMirrors();
}
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
return tree.sym.getAnnotationsByType(annotationType);
}
@Override
public AnnotationValue getDefaultValue() {
return tree.sym.getDefaultValue();
}
@Override
public List<? extends Element> getEnclosedElements() {
return tree.sym.getEnclosedElements();
}
@Override
public Element getEnclosingElement() {
return tree.sym.getEnclosingElement();
}
@Override
public ElementKind getKind() {
return tree.sym.getKind();
}
@Override
public Set<Modifier> getModifiers() {
return tree.sym.getModifiers();
}
@Override
public List<? extends VariableElement> getParameters() {
return tree.sym.getParameters();
}
@Override
public TypeMirror getReceiverType() {
return tree.sym.getReceiverType();
}
@Override
public TypeMirror getReturnType() {
return tree.sym.getReturnType();
}
@Override
public Name getSimpleName() {
return tree.sym.getSimpleName();
}
@Override
public List<? extends TypeMirror> getThrownTypes() {
return tree.sym.getThrownTypes();
}
@Override
public List<? extends TypeParameterElement> getTypeParameters() {
return tree.sym.getTypeParameters();
}
@Override
public boolean isVarArgs() {
return tree.sym.isVarArgs();
}
@Override
public boolean isDefault() {
return tree.sym.isDefault();
}
}

View File

@ -92,4 +92,10 @@ public class ExtendedElementSupport<T extends JCTree> implements ExtendedElement
public boolean isStringLiteral() { public boolean isStringLiteral() {
return getTree().getKind() == Kind.STRING_LITERAL; return getTree().getKind() == Kind.STRING_LITERAL;
} }
@Override
public int getStartSourcePosition() {
return getTree().getStartPosition();
}
} }

View File

@ -20,11 +20,19 @@ package org.jsweet.transpiler.model.support;
import javax.lang.model.element.VariableElement; import javax.lang.model.element.VariableElement;
import org.jsweet.transpiler.ConstAnalyzer;
import org.jsweet.transpiler.model.ExtendedElement; import org.jsweet.transpiler.model.ExtendedElement;
import org.jsweet.transpiler.model.ExtendedElementFactory; import org.jsweet.transpiler.model.ExtendedElementFactory;
import org.jsweet.transpiler.model.ForeachLoopElement; import org.jsweet.transpiler.model.ForeachLoopElement;
import com.sun.tools.javac.tree.JCTree.JCBreak;
import com.sun.tools.javac.tree.JCTree.JCContinue;
import com.sun.tools.javac.tree.JCTree.JCDoWhileLoop;
import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop; import com.sun.tools.javac.tree.JCTree.JCEnhancedForLoop;
import com.sun.tools.javac.tree.JCTree.JCForLoop;
import com.sun.tools.javac.tree.JCTree.JCReturn;
import com.sun.tools.javac.tree.JCTree.JCWhileLoop;
import com.sun.tools.javac.tree.TreeScanner;
/** /**
* See {@link ForeachLoopElement}. * See {@link ForeachLoopElement}.
@ -52,4 +60,47 @@ public class ForeachLoopElementSupport extends ExtendedElementSupport<JCEnhanced
return ExtendedElementFactory.INSTANCE.create(getTree().expr); return ExtendedElementFactory.INSTANCE.create(getTree().expr);
} }
@Override
public boolean hasControlFlowStatement() {
boolean[] hasControlFlowStatement = { false };
new TreeScanner() {
@Override
public void visitBreak(JCBreak tree) {
hasControlFlowStatement[0] = true;
}
@Override
public void visitContinue(JCContinue tree) {
hasControlFlowStatement[0] = true;
}
@Override
public void visitReturn(JCReturn tree) {
hasControlFlowStatement[0] = true;
}
@Override
public void visitForeachLoop(JCEnhancedForLoop tree) {
// do not scan inner loops
}
@Override
public void visitDoLoop(JCDoWhileLoop tree) {
// do not scan inner loops
}
@Override
public void visitWhileLoop(JCWhileLoop tree) {
// do not scan inner loops
}
@Override
public void visitForLoop(JCForLoop tree) {
// do not scan inner loops
}
}.scan(getTree().body);
return hasControlFlowStatement[0];
}
@Override
public boolean isIterationVariableModified() {
ConstAnalyzer a = new ConstAnalyzer();
a.scan(getTree().body);
return a.getModifiedVariables().contains(getIterationVariable());
}
} }

View File

@ -0,0 +1,48 @@
/*
* JSweet transpiler - http://www.jsweet.org
* Copyright (C) 2015 CINCHEO SAS <renaud.pawlak@cincheo.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jsweet.transpiler.model.support;
import org.jsweet.transpiler.model.TypeCastElement;
import org.jsweet.transpiler.model.ExtendedElement;
import org.jsweet.transpiler.model.ExtendedElementFactory;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
/**
* See {@link TypeCastElement}.
*
* @author Renaud Pawlak
*/
public class TypeCastElementSupport extends ExtendedElementSupport<JCTypeCast> implements TypeCastElement {
public TypeCastElementSupport(JCTypeCast tree) {
super(tree);
}
@Override
public ExtendedElement getTargetTypeExpression() {
return (ExtendedElement) ExtendedElementFactory.INSTANCE.create(getTree().getType());
}
@Override
public ExtendedElement getExpression() {
return ExtendedElementFactory.INSTANCE.create(getTree().getExpression());
}
}

View File

@ -18,6 +18,8 @@
*/ */
package org.jsweet.transpiler.model.support; package org.jsweet.transpiler.model.support;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
@ -80,6 +82,8 @@ public class UtilSupport implements Util {
@Override @Override
public TypeMirror getType(Class<?> clazz) { public TypeMirror getType(Class<?> clazz) {
switch (clazz.getName()) { switch (clazz.getName()) {
case "java.lang.Object":
return context.symtab.objectType;
case "java.lang.annotation.Annotation": case "java.lang.annotation.Annotation":
return context.symtab.annotationType; return context.symtab.annotationType;
case "java.lang.AssertionError": case "java.lang.AssertionError":
@ -153,6 +157,11 @@ public class UtilSupport implements Util {
return org.jsweet.transpiler.util.Util.isNumber(type); return org.jsweet.transpiler.util.Util.isNumber(type);
} }
@Override
public boolean isBoolean(TypeMirror type) {
return org.jsweet.transpiler.util.Util.isBoolean(type);
}
@Override @Override
public boolean isDeprecated(Element element) { public boolean isDeprecated(Element element) {
return org.jsweet.transpiler.util.Util.isDeprecated(element); return org.jsweet.transpiler.util.Util.isDeprecated(element);
@ -207,4 +216,32 @@ public class UtilSupport implements Util {
return false; return false;
} }
@Override
public List<Element> getAllMembers(TypeElement typeElement) {
if(typeElement == null) {
return Collections.emptyList();
}
List<Element> elements = new ArrayList<Element>();
for(Element e : typeElement.getEnclosedElements()) {
elements.add(e);
}
elements.addAll(getAllMembers(typeElement.getSuperclass()));
return elements;
}
private List<Element> getAllMembers(TypeMirror type) {
if(type == null) {
return Collections.emptyList();
}
return getAllMembers((TypeElement)context.modelTypes.asElement(type));
}
@Override
public TypeMirror toPrimitiveTypeOrType(TypeMirror type) {
try {
return context.types.unboxedTypeOrType((Type)type);
} catch (Exception e) {
return type;
}
}
} }

View File

@ -0,0 +1,85 @@
package org.jsweet.transpiler.model.support;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Set;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ElementVisitor;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.Name;
import javax.lang.model.type.TypeMirror;
import org.jsweet.transpiler.model.VariableElement;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
public class VariableElementSupport extends ExtendedElementSupport<JCVariableDecl> implements VariableElement {
public VariableElementSupport(JCVariableDecl tree) {
super(tree);
}
@Override
public javax.lang.model.element.VariableElement getStandardElement() {
return tree.sym;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return tree.sym.accept(v, p);
}
@Override
public TypeMirror asType() {
return tree.sym.asType();
}
@Override
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return tree.sym.getAnnotation(annotationType);
}
@Override
public List<? extends AnnotationMirror> getAnnotationMirrors() {
return tree.sym.getAnnotationMirrors();
}
@Override
public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationType) {
return tree.sym.getAnnotationsByType(annotationType);
}
@Override
public List<? extends Element> getEnclosedElements() {
return tree.sym.getEnclosedElements();
}
@Override
public Element getEnclosingElement() {
return tree.sym.getEnclosingElement();
}
@Override
public ElementKind getKind() {
return tree.sym.getKind();
}
@Override
public Set<Modifier> getModifiers() {
return tree.sym.getModifiers();
}
@Override
public Name getSimpleName() {
return tree.sym.getSimpleName();
}
@Override
public Object getConstantValue() {
return tree.sym.getConstantValue();
}
}

View File

@ -468,4 +468,11 @@ public abstract class AbstractTreeScanner extends TreeScanner {
return null; return null;
} }
/**
* Gets the transpilation handler for this scanner.
*/
public TranspilationHandler getLogHandler() {
return logHandler;
}
} }

View File

@ -1059,6 +1059,21 @@ public class Util {
} }
} }
/**
* Returns true is the type is a boolean.
*/
public static boolean isBoolean(TypeMirror type) {
if (type == null) {
return false;
}
switch (type.getKind()) {
case BOOLEAN:
return true;
default:
return false;
}
}
/** /**
* Returns true is the type is a core. * Returns true is the type is a core.
*/ */

View File

@ -78,14 +78,21 @@ public class ApiTests extends AbstractTest {
@Test @Test
public void testJ4TSInvocations() { public void testJ4TSInvocations() {
transpile(ModuleKind.none, logHandler -> { // with J4TS
transpilerTest().getTranspiler().setUsingJavaRuntime(true);
eval(ModuleKind.none, (logHandler, result) -> {
logHandler.assertNoProblems();
}, getSourceFile(J4TSInvocations.class));
// without J4TS
transpilerTest().getTranspiler().setUsingJavaRuntime(false);
eval(ModuleKind.none, (logHandler, result) -> {
logHandler.assertNoProblems(); logHandler.assertNoProblems();
}, getSourceFile(J4TSInvocations.class)); }, getSourceFile(J4TSInvocations.class));
} }
@Test @Test
public void testJdkInvocations() { public void testJdkInvocations() {
eval((logHandler, result) -> { eval(ModuleKind.none, (logHandler, result) -> {
Assert.assertEquals("There should be no errors", 0, logHandler.reportedProblems.size()); Assert.assertEquals("There should be no errors", 0, logHandler.reportedProblems.size());
assertEquals("test", result.<String>get("s1")); assertEquals("test", result.<String>get("s1"));
assertEquals("m1", result.<String>get("s2")); assertEquals("m1", result.<String>get("s2"));
@ -273,6 +280,7 @@ public class ApiTests extends AbstractTest {
public void testDates() { public void testDates() {
eval(ModuleKind.none, (logHandler, r) -> { eval(ModuleKind.none, (logHandler, r) -> {
logHandler.assertNoProblems(); logHandler.assertNoProblems();
System.out.println("result = " + r.get("localeString"));
assertTrue(asList( assertTrue(asList(
"1/1/2020, 1:00:00 AM", "1/1/2020, 1:00:00 AM",
"2020-1-1 1:00:00 AM").contains( "2020-1-1 1:00:00 AM").contains(

View File

@ -2,10 +2,12 @@ package org.jsweet.test.transpiler;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Comparator;
import java.util.EventObject; import java.util.EventObject;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement; import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement; import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeKind;
@ -29,6 +31,7 @@ import org.jsweet.transpiler.extension.Java2TypeScriptAdapter;
import org.jsweet.transpiler.extension.MapAdapter; import org.jsweet.transpiler.extension.MapAdapter;
import org.jsweet.transpiler.extension.PrinterAdapter; import org.jsweet.transpiler.extension.PrinterAdapter;
import org.jsweet.transpiler.extension.RemoveJavaDependenciesAdapter; import org.jsweet.transpiler.extension.RemoveJavaDependenciesAdapter;
import org.jsweet.transpiler.model.ExtendedElement;
import org.jsweet.transpiler.model.ImportElement; import org.jsweet.transpiler.model.ImportElement;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
@ -41,6 +44,7 @@ import source.extension.HelloWorldDto;
import source.extension.HelloWorldService; import source.extension.HelloWorldService;
import source.extension.IAddNumber; import source.extension.IAddNumber;
import source.extension.Maps; import source.extension.Maps;
import source.extension.ToBeSorted;
import source.extension.UseOfGlobalVariable; import source.extension.UseOfGlobalVariable;
class TestFactory extends JSweetFactory { class TestFactory extends JSweetFactory {
@ -106,6 +110,37 @@ class HelloWorldAdapter extends PrinterAdapter {
} }
} }
class SortAdapter extends PrinterAdapter {
public SortAdapter(PrinterAdapter parentAdapter) {
super(parentAdapter);
}
@Override
public Comparator<ExtendedElement> getClassMemberComparator() {
Comparator<ExtendedElement> defaultComparator = super.getClassMemberComparator();
return new Comparator<ExtendedElement>() {
@Override
public int compare(ExtendedElement e1, ExtendedElement e2) {
if(e1 instanceof org.jsweet.transpiler.model.ExecutableElement &&
e2 instanceof org.jsweet.transpiler.model.ExecutableElement) {
ExecutableElement se1 = ((org.jsweet.transpiler.model.ExecutableElement)e1).getStandardElement();
ExecutableElement se2 = ((org.jsweet.transpiler.model.ExecutableElement)e2).getStandardElement();
if (se1.getModifiers().contains(Modifier.STATIC) && !se2.getModifiers().contains(Modifier.STATIC)) {
return -1;
} else if (se2.getModifiers().contains(Modifier.STATIC) && !se1.getModifiers().contains(Modifier.STATIC)) {
return 1;
}
}
return defaultComparator.compare(e1, e2);
}
};
}
}
class JaxRSStubAdapter extends PrinterAdapter { class JaxRSStubAdapter extends PrinterAdapter {
public JaxRSStubAdapter(PrinterAdapter parent) { public JaxRSStubAdapter(PrinterAdapter parent) {
@ -245,6 +280,31 @@ public class ExtensionTests extends AbstractTest {
Assert.assertFalse(generatedCode.contains("date : Date")); Assert.assertFalse(generatedCode.contains("date : Date"));
} }
@Test
public void testSortAdapter() throws IOException {
TranspilerTestRunner transpilerTest = new TranspilerTestRunner(getCurrentTestOutDir(), new JSweetFactory());
SourceFile f = getSourceFile(ToBeSorted.class);
transpilerTest.transpile(logHandler -> {
logHandler.assertNoProblems();
}, f);
String generatedCode = FileUtils.readFileToString(f.getTsFile());
Assert.assertTrue(generatedCode.indexOf("myStaticMethod") > generatedCode.indexOf("myMethod"));
transpilerTest = new TranspilerTestRunner(getCurrentTestOutDir(), new JSweetFactory() {
@Override
public PrinterAdapter createAdapter(JSweetContext context) {
return new SortAdapter(super.createAdapter(context));
}
});
transpilerTest.getTranspiler().setSortClassMembers(true);
f = getSourceFile(ToBeSorted.class);
transpilerTest.transpile(logHandler -> {
logHandler.assertNoProblems();
}, f);
generatedCode = FileUtils.readFileToString(f.getTsFile());
Assert.assertTrue(generatedCode.indexOf("myStaticMethod") < generatedCode.indexOf("myMethod"));
}
@Test @Test
public void testDisallowGlobalVariablesAdapter() { public void testDisallowGlobalVariablesAdapter() {
TranspilerTestRunner transpilerTest = new TranspilerTestRunner(getCurrentTestOutDir(), new JSweetFactory() { TranspilerTestRunner transpilerTest = new TranspilerTestRunner(getCurrentTestOutDir(), new JSweetFactory() {

View File

@ -62,6 +62,8 @@ import source.overload.ConstructorOverloadWithFieldInitializer;
import source.overload.InterfaceInheritance; import source.overload.InterfaceInheritance;
import source.overload.LocalVariablesNameCollision; import source.overload.LocalVariablesNameCollision;
import source.overload.NonPublicRootMethod; import source.overload.NonPublicRootMethod;
import source.overload.OverLoadClassAndObject;
import source.overload.OverLoadVarags;
import source.overload.OverLoadWithClassParam; import source.overload.OverLoadWithClassParam;
import source.overload.Overload; import source.overload.Overload;
import source.overload.OverloadInInnerClass; import source.overload.OverloadInInnerClass;
@ -262,6 +264,31 @@ public class OverloadTests extends AbstractTest {
}, getSourceFile(ConstructorOverloadWithFieldInitializer.class)); }, getSourceFile(ConstructorOverloadWithFieldInitializer.class));
} }
@Test
public void testOverloadClassAndObjectWithJ4TS() {
transpilerTest().getTranspiler().setUsingJavaRuntime(true);
eval(ModuleKind.none, (logHandler, r) -> {
logHandler.assertNoProblems();
}, getSourceFile(OverLoadClassAndObject.class));
transpilerTest().getTranspiler().setUsingJavaRuntime(false);
}
@Test
public void testOverloadClassAndObject() {
eval(ModuleKind.none, (logHandler, r) -> {
logHandler.assertNoProblems();
}, getSourceFile(OverLoadClassAndObject.class));
}
@Test
public void testOverloadVarargs() {
transpilerTest().getTranspiler().setUsingJavaRuntime(true);
eval(ModuleKind.none, (logHandler, r) -> {
logHandler.assertNoProblems();
}, getSourceFile(OverLoadVarags.class));
transpilerTest().getTranspiler().setUsingJavaRuntime(false);
}
@Test @Test
public void testConstructorOverloadWithArray() { public void testConstructorOverloadWithArray() {
eval(ModuleKind.none, (logHandler, r) -> { eval(ModuleKind.none, (logHandler, r) -> {

View File

@ -68,6 +68,7 @@ import source.structural.PrivateMethodNameClashes;
import source.structural.ReplaceAnnotation; import source.structural.ReplaceAnnotation;
import source.structural.StaticMembersInInterfaces; import source.structural.StaticMembersInInterfaces;
import source.structural.SubAbstract; import source.structural.SubAbstract;
import source.structural.Transients;
import source.structural.TwoClassesInSameFile; import source.structural.TwoClassesInSameFile;
import source.structural.WrappedParametersOwner; import source.structural.WrappedParametersOwner;
import source.structural.WrongConstructsInInterfaces; import source.structural.WrongConstructsInInterfaces;
@ -544,6 +545,20 @@ public class StructuralTests extends AbstractTest {
}, getSourceFile(FieldInitialization.class)); }, getSourceFile(FieldInitialization.class));
} }
@Test
public void testTransients() {
eval(ModuleKind.none, (logHandler, r) -> {
logHandler.assertNoProblems();
assertEquals("a,b,c,d", r.get("keys"));
}, getSourceFile(Transients.class));
this.transpilerTest().getTranspiler().setNonEnumerableTransients(true);
eval(ModuleKind.none, (logHandler, r) -> {
logHandler.assertNoProblems();
assertEquals("a,c", r.get("keys"));
}, getSourceFile(Transients.class));
this.transpilerTest().getTranspiler().setNonEnumerableTransients(false);
}
@Test @Test
public void testInheritanceWithGenerics() { public void testInheritanceWithGenerics() {
transpile(logHandler -> { transpile(logHandler -> {

View File

@ -22,16 +22,22 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.jsweet.test.transpiler.util.TranspilerTestRunner;
import org.jsweet.transpiler.JSweetContext;
import org.jsweet.transpiler.JSweetFactory;
import org.jsweet.transpiler.JSweetProblem; import org.jsweet.transpiler.JSweetProblem;
import org.jsweet.transpiler.ModuleKind; import org.jsweet.transpiler.ModuleKind;
import org.jsweet.transpiler.SourceFile; import org.jsweet.transpiler.SourceFile;
import org.jsweet.transpiler.extension.PrinterAdapter;
import org.jsweet.transpiler.util.EvaluationResult; import org.jsweet.transpiler.util.EvaluationResult;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import source.extension.ToBeSorted;
import source.syntax.AnnotationQualifiedNames; import source.syntax.AnnotationQualifiedNames;
import source.syntax.Casts; import source.syntax.Casts;
import source.syntax.DocComments; import source.syntax.DocComments;
@ -146,6 +152,25 @@ public class SyntaxTests extends AbstractTest {
}, getSourceFile(FinalVariables.class)); }, getSourceFile(FinalVariables.class));
} }
@Test
public void testConstVariables() throws IOException {
SourceFile f1 = getSourceFile(FinalVariables.class);
SourceFile f2 = getSourceFile(GlobalsInvocation.class);
transpilerTest().transpile(logHandler -> {
logHandler.assertNoProblems();
}, f1, f2);
String generatedCode = FileUtils.readFileToString(f1.getTsFile());
Assert.assertTrue(generatedCode.contains("const explicitFinalString"));
Assert.assertTrue(generatedCode.contains("let explicitFinalStringWithDeferredAssignment"));
Assert.assertFalse(generatedCode.contains("const explicitFinalStringWithDeferredAssignment"));
Assert.assertTrue(generatedCode.contains("const implicitFinalString"));
Assert.assertTrue(generatedCode.contains("let notFinalString"));
generatedCode = FileUtils.readFileToString(f2.getTsFile());
Assert.assertTrue(generatedCode.contains("const explicitFinalGlobal"));
Assert.assertTrue(generatedCode.contains("let implicitFinalGlobal"));
Assert.assertTrue(generatedCode.contains("let notFinalGlobal"));
}
@Test @Test
public void testFinalVariablesRuntime() { public void testFinalVariablesRuntime() {
try { try {

View File

@ -96,6 +96,7 @@ public class TranspilerTestRunner {
transpiler.setGenerateSourceMaps(false); transpiler.setGenerateSourceMaps(false);
transpiler.setUseTsserver(true); transpiler.setUseTsserver(true);
transpiler.setVerbose(verbose); transpiler.setVerbose(verbose);
transpiler.setUsingJavaRuntime(false);
FileUtils.deleteQuietly(transpiler.getWorkingDirectory()); FileUtils.deleteQuietly(transpiler.getWorkingDirectory());
} }

View File

@ -11,7 +11,7 @@ public class Dates {
double JANUARY = 0; double JANUARY = 0;
Date d = new Date(Date.UTC(2020, JANUARY, 01, 1, 0, 0)); Date d = new Date(Date.UTC(2020, JANUARY, 01, 1, 0, 0));
String localeString = d.toLocaleString("fr", new DateTimeFormatOptions() { String localeString = d.toLocaleString("en", new DateTimeFormatOptions() {
{ {
$set("timeZone", "UTC"); $set("timeZone", "UTC");
} }

View File

@ -8,6 +8,12 @@ public class Equals {
static Array<String> trace = new Array<String>(); static Array<String> trace = new Array<String>();
static Integer int1 = 0;
static Integer int2 = 0;
static Integer int3 = 0;
static Integer int4 = 0;
static Integer int5 = 0;
public static void main(String[] args) { public static void main(String[] args) {
trace.push("" + equals("a", "b")); trace.push("" + equals("a", "b"));
trace.push("" + equals("a", "a")); trace.push("" + equals("a", "a"));
@ -20,6 +26,11 @@ public class Equals {
MyObject2 o = new MyObject2("a"); MyObject2 o = new MyObject2("a");
trace.push("" + equals(o, o)); trace.push("" + equals(o, o));
$export("trace", trace.join(",")); $export("trace", trace.join(","));
// ensures that this kind of test works fine
if (!int1.equals(int2 == int3
? int4
: int5)) {
}
} }
public static boolean equals(Object a, Object b) { public static boolean equals(Object a, Object b) {

View File

@ -0,0 +1,11 @@
package source.extension;
public class ToBeSorted {
public void myMethod() {
}
static void myStaticMethod() {
}
}

View File

@ -0,0 +1,62 @@
package source.overload;
import static jsweet.util.Lang.$apply;
import static jsweet.util.Lang.object;
public class OverLoadClassAndObject {
public static void main(String[] args) {
OverLoadClassAndObject overload = new OverLoadClassAndObject();
System.out.println(overload.m(AnInterface.class));
System.out.println(overload.m(new AClass()));
System.out.println((String)$apply(object(overload).$get("m"), new AClass()));
System.out.println((String)$apply(object(overload).$get("m"), AClass.class));
// Overload with strings cannot work because AnInterface.class is transpiled as a string
System.out.println((String)$apply(object(overload).$get("m"), AnInterface.class));
System.out.println(overload.m2(AClass.class));
System.out.println(overload.m2(new AClass()));
System.out.println((String)$apply(object(overload).$get("m2"), new AClass()));
System.out.println((String)$apply(object(overload).$get("m2"), AClass.class));
assert overload.m(AnInterface.class) == "2:source.overload.AnInterface";
assert overload.m(new AClass()) == "1:object";
assert $apply(object(overload).$get("m"), new AClass()) == "1:object";
assert $apply(object(overload).$get("m"), AClass.class) == "2:source.overload.AClass";
assert $apply(object(overload).$get("m"), AnInterface.class) == "2:source.overload.AnInterface";
assert overload.m2(AClass.class) == "2:source.overload.AClass";
assert overload.m2(new AClass()) == "1:object";
assert $apply(object(overload).$get("m2"), new AClass()) == "1:object";
assert $apply(object(overload).$get("m2"), AClass.class) == "2:source.overload.AClass";
}
String m(AnInterface o) {
return "1:" + o.getName();
}
String m(Class<AnInterface> clazz) {
return "2:" + clazz.getName();
}
String m2(AClass o) {
return "1:" + o.getName();
}
String m2(Class<AClass> clazz) {
return "2:" + clazz.getName();
}
}
interface AnInterface {
String getName();
}
class AClass implements AnInterface {
public String getName() {
return "object";
}
}

View File

@ -0,0 +1,50 @@
package source.overload;
import static jsweet.util.Lang.$insert;
public class OverLoadVarags {
public static void main(String[] args) {
OverLoadVarags ov = new OverLoadVarags();
System.out.println(ov.m(new AClass2()));
System.out.println(ov.m(new AClass2(), true, "a", "b", "c"));
System.out.println((String)$insert("ov.m(new AClass2())"));
System.out.println((String)$insert("ov.m(new AClass2(), true, 'a', 'b', 'c')"));
assert ov.m(new AClass2()) == "1:object";
assert ov.m(new AClass2(), true, "a", "b", "c") == "objecta,b,c/3";
assert $insert("ov.m(new AClass2())") == "1:object";
assert $insert("ov.m(new AClass2(), true, 'a', 'b', 'c')") == "objecta,b,c/3";
// passing an array does not work
// TODO: when invoking org method, test if passed expression type is an array and use call
//assert $insert("ov.m(new AClass2(), true, ['a', 'b', 'c'])") == "objecta,b,c/3";
assert ov.mref(new AClass2(), "a", "b", "c") == "objecta,b,c/3";
assert ov.mref(new AClass2(), new String[] {"a", "b", "c"}) == "objecta,b,c/3";
}
String m(AnInterface2 dto, boolean b, String... options) {
return dto.getName() + varM(options);
}
String m(AnInterface2 dto) {
return "1:" + dto.getName();
}
String mref(AnInterface2 dto, String... options) {
return dto.getName() + varM(options);
}
String varM(String... options) {
return "" + options + "/" + $insert("arguments.length");
}
}
interface AnInterface2 {
String getName();
}
class AClass2 implements AnInterface2 {
public String getName() {
return "object";
}
}

View File

@ -0,0 +1,27 @@
package source.structural;
import static jsweet.util.Lang.$export;
import def.js.Array;
import jsweet.util.Lang;
public class Transients {
public static void main(String[] args) {
Array<String> keys = Lang.$insert("Object.keys(new ChildWithTransients())");
System.out.println("keys = "+keys);
$export("keys", keys.join(","));
}
}
class ParentWithTransients {
int a;
transient int b;
}
class ChildWithTransients extends ParentWithTransients {
int c;
transient int d;
}

View File

@ -33,7 +33,11 @@ import def.js.Math;
public class FinalVariables { public class FinalVariables {
int finalField;
int modifiedField;
void m1(HTMLElement e) { void m1(HTMLElement e) {
modifiedField++;
NodeList nodes = document.querySelectorAll("form .form-control"); NodeList nodes = document.querySelectorAll("form .form-control");
for (int i = 0; i < nodes.length; i++) { for (int i = 0; i < nodes.length; i++) {
HTMLElement element = (HTMLElement) nodes.$get(i); HTMLElement element = (HTMLElement) nodes.$get(i);
@ -98,25 +102,46 @@ public class FinalVariables {
} }
void explicitFinal() { void explicitFinal() {
final String s = "abc"; final String explicitFinalString = "abc";
handler(new ANonFunctionalInterface() { handler(new ANonFunctionalInterface() {
@Override @Override
public void m() { public void m() {
System.out.println(s); System.out.println(explicitFinalString);
}
});
}
public void explicitFinalWithDeferredAssignment(boolean condition) {
final String explicitFinalStringWithDeferredAssignment;
if(condition) {
explicitFinalStringWithDeferredAssignment = "1";
} else {
explicitFinalStringWithDeferredAssignment = "2";
}
handler(new ANonFunctionalInterface() {
@Override
public void m() {
System.out.println(explicitFinalStringWithDeferredAssignment);
} }
}); });
} }
void implicitFinal() { void implicitFinal() {
String s = "abc"; String implicitFinalString = "abc";
handler(new ANonFunctionalInterface() { handler(new ANonFunctionalInterface() {
@Override @Override
public void m() { public void m() {
System.out.println(s); System.out.println(implicitFinalString);
} }
}); });
} }
String notFinal() {
String notFinalString = "abc";
notFinalString = "bcd";
return notFinalString;
}
} }
// subset of promises API // subset of promises API
@ -133,3 +158,4 @@ interface Callback<T1, T2> {
interface ANonFunctionalInterface { interface ANonFunctionalInterface {
void m(); void m();
} }

View File

@ -50,4 +50,14 @@ class Globals {
}); });
} }
public static void m() {}; public static void m() {};
public final static int explicitFinalGlobal = 1;
public static int implicitFinalGlobal = 1;
public static int notFinalGlobal = 1;
public static void init() {
notFinalGlobal = 1;
}
} }

File diff suppressed because it is too large Load Diff