Merge tag 'apache-royale-0.9.6'
diff --git a/.gitignore b/.gitignore
index 7c415e6..d777804 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,6 +13,10 @@
*.iws
*.eml
+# VSCode conf files
+**/.vscode/**
+*.code-workspace
+
#OS junk files
[Tt]humbs.db
*.DS_Store
@@ -42,4 +46,7 @@
debugger/generated/
# Asciidoctor related temp files
-ditaa-diagram.*
\ No newline at end of file
+ditaa-diagram.*
+
+# JUnit temp files
+junittestcases*.properties
\ No newline at end of file
diff --git a/ApproveFalcon.xml b/ApproveFalcon.xml
index 9c1e3fc..ba95ad6 100644
--- a/ApproveFalcon.xml
+++ b/ApproveFalcon.xml
@@ -56,8 +56,8 @@
<property name="bin.rat.report" value="${basedir}/rat-report-bin.txt"/>
<property name="apache.rat.jar" value="apache-rat-0.11.jar" />
<property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.11.jar" />
- <property name="apache.rat.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" />
- <property name="apache.rat.tasks.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11" />
+ <property name="apache.rat.url" value="https://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" />
+ <property name="apache.rat.tasks.url" value="https://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11" />
<property file="${basedir}/approveroyale.properties"/>
diff --git a/Jenkinsfile b/Jenkinsfile
index d5d533a..3490bb5 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -23,7 +23,7 @@
// Run only on the windows-2012-1 agent as this is the only one setup to fully
// support Royale builds.
-node('windows-2012-1') {
+node('jenkins-win-he-de-1') {
currentBuild.result = "SUCCESS"
diff --git a/LICENSE b/LICENSE
index d645695..77de039 100644
--- a/LICENSE
+++ b/LICENSE
@@ -200,3 +200,21 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+
+--------------------------------------------------------------------------------
+
+APACHE ROYALE SUBCOMPONENTS:
+
+The Apache Royale SDK includes a number of subcomponents with
+separate copyright notices and license terms. Your use of the source
+code for the these subcomponents is subject to the terms and
+conditions of the following licenses. Paths are relative to the royale-compiler
+folder.
+
+The following .java files in
+compiler-jx/src/main/java/com/google/javascript/jscomp
+are derived from the files in the Google Closure Compiler which are available
+under Apache License 2.0.
+
+RoyaleClosurePassConfig.java
+Files with names ending with WithModuleSupport.java
diff --git a/NOTICE b/NOTICE
index ee01330..6f9f984 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,13 +1,16 @@
Apache Royale Compiler
-Copyright 2018 The Apache Software Foundation
+Copyright 2019 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
The Initial Developer of the Original Code, known as Adobe Flex
-and Adobe ASC 2.0, is Adobe Systems Incorporated (http://www.adobe.com/).
+and Adobe ASC 2.0 and JBurgGenerator.java, is Adobe Systems Incorporated
+(http://www.adobe.com/).
Copyright 2003 - 2012 Adobe Systems Incorporated. All Rights Reserved.
The flex-compiler-oem compiler contains code written by Jeff Dyer at:
Copyright Mountain View Compiler Company (1998-2003).
+Portions of JBurgGenerator.java contains code written by Tom Harwood
+ Copyright Tom Harwood (2003-2008).
diff --git a/NOTICE.base b/NOTICE.base
index 1a99147..69caa49 100644
--- a/NOTICE.base
+++ b/NOTICE.base
@@ -1,5 +1,5 @@
Apache Royale Compiler
-Copyright 2018 The Apache Software Foundation
+Copyright 2019 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/NOTICE.fdb b/NOTICE.fdb
index e8dea8a..fd988a9 100644
--- a/NOTICE.fdb
+++ b/NOTICE.fdb
@@ -1,5 +1,5 @@
Apache Royale Debugger
-Copyright 2018 The Apache Software Foundation
+Copyright 2019 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/NOTICE.oem b/NOTICE.oem
index 1dc6435..e5c6bf7 100644
--- a/NOTICE.oem
+++ b/NOTICE.oem
@@ -1,5 +1,5 @@
Apache Royale Compiler
-Copyright 2018 The Apache Software Foundation
+Copyright 2019 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).
diff --git a/README b/README
index 4a807a6..a1376d4 100644
--- a/README
+++ b/README
@@ -268,7 +268,7 @@
commons-compress - https://repo1.maven.org/maven2/org/apache/commons/commons-compress/1.10/commons-compress-1.10.jar
guava - https://repo1.maven.org/maven2/com/google/guava/guava/17.0/guava-17.0.jar
jburg - https://repo1.maven.org/maven2/net/sourceforge/jburg/jburg/1.10.2/jburg-1.10.2.jar
- jflex - http://jflex.de/jflex-1.6.0.tar.gz
+ jflex - https://jflex.de/jflex-1.6.0.tar.gz
lzma - http://www.java2s.com/Code/JarDownload/lzma/lzma-9.20.jar.zip
Google Closure Compiler - http://github.com/google/closure-compiler/archive/v 20151015.zip
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 7cd179f..b59e3bb 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,18 @@
+Apache Royale Compiler 0.9.6
+=================
+
+ - Added -allow-abstract-classes compiler option to enable abstract keyword for classes and methods.
+ - Added -allow-private-constructors compiler option to enable classes with private constructors.
+ - Added -allow-import-aliases compiler option to enable import renaming syntax.
+ - Added -verbose compiler option to reduce console output by default.
+ - Added RoyaleUnit tasks for Apache Ant.
+ - Fix incorrect compiler error when unicodeRange value is specified for Embed metadata.
+ - Fix missing compiler error when adding type parameters to classes other the Vector.
+ - Fix missing compiler error for intantiation of a variable with new that is not typed as Class or Function.
+ - Fix missing compiler warning for missing types on function parameter.
+ - Fix internal cache that broke IDEs that use compiler to provide code intelligence.
+ - Fix automatic type coercion in generated JS so that it better matches SWF behavior.
+
Apache Royale Compiler 0.9.4
=================
diff --git a/build.properties b/build.properties
index d06260b..cd6baca 100644
--- a/build.properties
+++ b/build.properties
@@ -17,7 +17,11 @@
##
################################################################################
-release.version = 0.9.4
+##used by Ant scripts
+release.version=0.9.6
+##used by release jobs on Jenkins
+releaseversion=0.9.6
+developbranchname=release_practice
generated.by.match=/\\*\\*. \\* Generated by Apache Royale Compiler
generated.by.comment=/**\n\
diff --git a/build.xml b/build.xml
index aa4a673..ac25291 100644
--- a/build.xml
+++ b/build.xml
@@ -70,7 +70,7 @@
<target name="swf" depends="sdk, javadoc, tests" description="Builds SWF compiler, builds Royale Javadoc, and runs SWF compiler tests."/>
- <target name="main" depends="swf, jx, oem, debugger, anttasks" description="Builds Royale SWF compiler, then Royale JS Transpiler"/>
+ <target name="main" depends="swf, jx, oem, debugger, anttasks, royaleunit.anttasks" description="Builds Royale SWF compiler, then Royale JS Transpiler"/>
<target name="jx" depends="compiler.jx, compiler.jx.tests" description="Builds Royale JS Transpiler" />
@@ -92,6 +92,10 @@
<ant dir="royale-ant-tasks" target="jar"/>
</target>
+ <target name="royaleunit.anttasks" description="Builds RoyaleUnit ant tasks JAR">
+ <ant dir="royaleunit-ant-tasks" target="jar"/>
+ </target>
+
<target name="debugger" depends="swfutils" description="Builds FDB JAR">
<ant dir="debugger" target="jar"/>
</target>
@@ -108,6 +112,10 @@
<ant dir="royale-ant-tasks" target="test"/>
</target>
+ <target name="royaleunit.ant.tests" description="Runs the tests." unless="skip.compiler.jx.tests">
+ <ant dir="royaleunit-ant-tasks" target="test"/>
+ </target>
+
<target name="copyLastSuccessfulBuild" description="Copies last royale-asjs build.">
<ant dir="compiler-jx/src/test" target="copyLastSuccessfulBuild"/>
</target>
@@ -130,6 +138,7 @@
<ant dir="flex-compiler-oem" target="clean"/>
<ant dir="swfutils" target="clean"/>
<ant dir="royale-ant-tasks" target="clean"/>
+ <ant dir="royaleunit-ant-tasks" target="clean"/>
<ant dir="debugger" target="clean"/>
</target>
@@ -156,6 +165,7 @@
<ant dir="flex-compiler-oem" target="wipe"/>
<ant dir="swfutils" target="wipe"/>
<ant dir="royale-ant-tasks" target="wipe"/>
+ <ant dir="royaleunit-ant-tasks" target="wipe"/>
<ant dir="debugger" target="clean"/>
<delete dir="${basedir}/out" failonerror="false" includeEmptyDirs="true"/>
<delete dir="${basedir}/temp" failonerror="false" includeEmptyDirs="true"/>
@@ -248,6 +258,7 @@
<copy todir="${staging-dir}" includeEmptyDirs="false">
<fileset dir="${basedir}">
+ <include name=".mvn/extensions.xml"/>
<include name="build.xml"/>
<include name="build.properties"/>
<include name="env-template.properties"/>
@@ -459,6 +470,19 @@
<exclude name="target/META-INF/**"/>
</fileset>
</copy>
+ <copy todir="${staging-dir}/royaleunit-ant-tasks" includeEmptyDirs="false">
+ <fileset dir="${basedir}/royaleunit-ant-tasks">
+ <include name="**"/>
+ <exclude name=".classpath" />
+ <exclude name=".project" />
+ <exclude name=".settings/**" />
+ <exclude name="target/classes/**"/>
+ <exclude name="target/flex/**"/>
+ <exclude name="target/flash/**"/>
+ <exclude name="target/generated-sources/**"/>
+ <exclude name="target/META-INF/**"/>
+ </fileset>
+ </copy>
</target>
<target name="stage-source-jx"
diff --git a/compiler-build-tools/pom.xml b/compiler-build-tools/pom.xml
index 734ab70..235eca6 100644
--- a/compiler-build-tools/pom.xml
+++ b/compiler-build-tools/pom.xml
@@ -29,7 +29,7 @@
<groupId>org.apache.royale.compiler</groupId>
<artifactId>compiler-build-tools</artifactId>
- <version>1.0.0</version>
+ <version>1.1.0</version>
<packaging>maven-plugin</packaging>
<name>Apache Royale: Build Tools</name>
@@ -37,6 +37,11 @@
<build>
<plugins>
<plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<version>3.5</version>
@@ -68,6 +73,18 @@
<pluginManagement>
<plugins>
<plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>strip-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.4</version>
@@ -127,6 +144,11 @@
<dependencies>
<dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>25.1-jre</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.5.4</version>
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClass.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClass.java
index 9d0e9e5..a80b33b 100644
--- a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClass.java
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClass.java
@@ -38,11 +38,24 @@
}
}
- public static void processFile(File file, String annotation) throws AnnotateClassDeleteException, AnnotateClassRenameException {
+ public static void processFile(File file, String annotation, String dateStart, String dateEnd) throws AnnotateClassDeleteException, AnnotateClassRenameException {
if(!file.exists()) {
System.out.println("Missing file: " + file.getPath());
return;
}
+ String comment = "";
+ if (dateStart.length() > 0)
+ {
+ int c = dateStart.indexOf("***");
+ if (c > -1)
+ {
+ comment = dateStart.substring(0, c);
+ dateStart = dateStart.substring(c + 3);
+ }
+ System.out.println("searching for generated date line starting with: '" + dateStart + "'");
+ if (comment.length() > 0)
+ System.out.println("and comment starting with: '" + comment + "'");
+ }
try
{
// Prepare to read the file.
@@ -60,6 +73,26 @@
boolean alreadyAnnotated = false;
while ((line = bufferedReader.readLine()) != null)
{
+ if (dateStart.length() > 0)
+ {
+ if ((comment.length() > 0 && line.startsWith(comment)) || comment.length() == 0)
+ {
+ int c = line.indexOf(dateStart);
+ if (c > -1)
+ {
+ if (dateEnd.length() > 0)
+ {
+ int c1 = line.lastIndexOf(dateEnd);
+ if (c1 > 0)
+ {
+ line = comment + dateStart + line.substring(c1);
+ }
+ }
+ else
+ line = comment + dateStart;
+ }
+ }
+ }
// If the class is already annotated, prevent us from doing it again.
if (line.contains(annotation)) {
alreadyAnnotated = true;
@@ -91,11 +124,33 @@
} catch(Exception e) {
// Ignore.
}
+ try {
+ inputStreamReader.close();
+ } catch(Exception e) {
+ // Ignore.
+ }
+ try {
+ fileInputStream.close();
+ } catch(Exception e) {
+ // Ignore.
+ }
}
// Remove the original file.
if(!file.delete()) {
- throw new AnnotateClassDeleteException("Error deleting original file at: " + file.getPath());
+ // wait a bit then retry on Windows
+ if (file.exists())
+ {
+ for (int i = 0; i < 6; i++)
+ {
+ Thread.sleep(500);
+ System.gc();
+ if (file.delete())
+ break;
+ }
+ if (file.exists())
+ throw new AnnotateClassDeleteException("Error deleting original file at: " + file.getPath());
+ }
}
// Rename the temp file to the name of the original file.
@@ -114,8 +169,10 @@
{
File f = new File(args[0]);
String annotation = args[1];
+ String dateStart = args[2];
+ String dateEnd = args[3];
try {
- processFile(f, annotation);
+ processFile(f, annotation, dateStart, dateEnd);
} catch (Exception e) {
e.printStackTrace();
}
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClassesMojo.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClassesMojo.java
index 3999688..92223ca 100644
--- a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClassesMojo.java
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/AnnotateClassesMojo.java
@@ -47,6 +47,12 @@
@Parameter(property="annotation", required=true)
private String annotation;
+ @Parameter(property="dateStart", required=false)
+ private String dateStart = "";
+
+ @Parameter(property="dateEnd", required=false)
+ private String dateEnd = "";
+
public void execute()
throws MojoExecutionException
{
@@ -58,7 +64,7 @@
Set<File> candidates = scan.getIncludedSources(directory, null);
for(File candidate : candidates) {
try {
- AnnotateClass.processFile(candidate, annotation);
+ AnnotateClass.processFile(candidate, annotation, dateStart, dateEnd);
} catch(AnnotateClass.AnnotateClassDeleteException e) {
throw new MojoExecutionException(e.getMessage());
} catch(AnnotateClass.AnnotateClassRenameException e) {
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/BaseProblemGeneratorMojo.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/BaseProblemGeneratorMojo.java
index 3af7b1c..6aa695e 100644
--- a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/BaseProblemGeneratorMojo.java
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/BaseProblemGeneratorMojo.java
@@ -113,6 +113,11 @@
{
return isProblemClass(input);
}
+ @Override
+ public boolean test(File input)
+ {
+ return apply(input);
+ }
});
}
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/ProblemResourceBundleGeneratorMojo.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/ProblemResourceBundleGeneratorMojo.java
index b8a3193..0183982 100644
--- a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/ProblemResourceBundleGeneratorMojo.java
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/problems/ProblemResourceBundleGeneratorMojo.java
@@ -61,7 +61,9 @@
@Override
protected void printEntry(PrintWriter writer, File source, boolean last) {
- writer.println(getProblemName(source) + "=" + getProblemDescription(source));
+ // don't use println otherwise file has windows line-endings on windows and
+ // won't compare to osx version
+ writer.print(getProblemName(source) + "=" + getProblemDescription(source) + "\n");
}
private String getProblemName(File sourceFile) {
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/unknowntreehandler/UnknownTreePatternInputOutput.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/unknowntreehandler/UnknownTreePatternInputOutput.java
index 2ad0d36..955e820 100644
--- a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/unknowntreehandler/UnknownTreePatternInputOutput.java
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/unknowntreehandler/UnknownTreePatternInputOutput.java
@@ -230,7 +230,10 @@
output.println("public class " + this.className);
output.println("{");
output.println();
- output.println(" // Patterns generated " + new java.util.Date().toString() + " from " + src_file_name.replaceAll("\\\\", "/"));
+ String src = src_file_name.replaceAll("\\\\", "/");
+ int c = src.indexOf("compiler/src");
+ src = src.substring(c);
+ output.println(" // Patterns generated from " + src);
output.println(" public static Map<ASTNodeID, ArrayList<UnknownTreeFinding.Template> > allTemplates = new HashMap<ASTNodeID, ArrayList<UnknownTreeFinding.Template>>();");
output.println(" static");
diff --git a/compiler-common/pom.xml b/compiler-common/pom.xml
index 2370a7b..581b97d 100644
--- a/compiler-common/pom.xml
+++ b/compiler-common/pom.xml
@@ -1,73 +1,83 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>compiler-common</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: Compiler-Common</name>
- <description>The Apache Royale Compiler Common classes</description>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.flex</groupId>
- <artifactId>flex-tool-api</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.6</version>
- </dependency>
- <dependency>
- <groupId>commons-cli</groupId>
- <artifactId>commons-cli</artifactId>
- <version>1.4</version>
- </dependency>
- <dependency>
- <groupId>org.antlr</groupId>
- <artifactId>antlr</artifactId>
- <version>3.3</version>
- </dependency>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- <version>20.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-scm-plugin</artifactId>
- <version>1.10.0</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>3.1.0</version>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>compiler-common</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: Compiler-Common</name>
+ <description>The Apache Royale Compiler Common classes</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.flex</groupId>
+ <artifactId>flex-tool-api</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.6</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>3.3</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>25.1-jre</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-plugin</artifactId>
+ <version>1.10.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/clients/problems/ProblemSettingsFilter.java b/compiler-common/src/main/java/org/apache/royale/compiler/clients/problems/ProblemSettingsFilter.java
index 8f857c6..2930c7f 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/clients/problems/ProblemSettingsFilter.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/clients/problems/ProblemSettingsFilter.java
@@ -41,6 +41,7 @@
import org.apache.royale.compiler.problems.ScopedToDefaultNamespaceProblem;
import org.apache.royale.compiler.problems.SemanticWarningProblem;
import org.apache.royale.compiler.problems.StrictSemanticsProblem;
+import org.apache.royale.compiler.problems.ThisUsedInClosureProblem;
import org.apache.royale.compiler.problems.VariableHasNoTypeDeclarationProblem;
/**
@@ -65,6 +66,7 @@
* -warn-instanceof-changes
* -warn-missing-namespace-decl
* -warn-no-type-decl
+ * -warn-this-within-closure
*
*/
public class ProblemSettingsFilter implements IProblemFilter
@@ -186,6 +188,8 @@
ICompilerSettings.WARN_MISSING_NAMESPACE_DECL);
setShowActionScriptWarning(VariableHasNoTypeDeclarationProblem.class,
ICompilerSettings.WARN_NO_TYPE_DECL);
+ setShowActionScriptWarning(ThisUsedInClosureProblem.class,
+ ICompilerSettings.WARN_THIS_WITHIN_CLOSURE);
}
/**
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java b/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
index bb686ea..a601f80 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/common/ASModifier.java
@@ -60,6 +60,11 @@
* Represents the <code>virtual</code> modifier.
*/
public static final ASModifier VIRTUAL = new ASModifier(IASKeywordConstants.VIRTUAL, 1 << 6);
+
+ /**
+ * Represents the <code>abstract</code> modifier.
+ */
+ public static final ASModifier ABSTRACT = new ASModifier(IASKeywordConstants.ABSTRACT, 1 << 7);
/**
* A list of all the modifiers that exist within AS3
@@ -71,7 +76,8 @@
NATIVE,
OVERRIDE,
STATIC,
- VIRTUAL
+ VIRTUAL,
+ ABSTRACT
};
/**
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/config/CompilerDiagnosticsConstants.java b/compiler-common/src/main/java/org/apache/royale/compiler/config/CompilerDiagnosticsConstants.java
index 9b6ce58..76eb483 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/config/CompilerDiagnosticsConstants.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/config/CompilerDiagnosticsConstants.java
@@ -40,5 +40,6 @@
public static final int FILE_UTILS = 4096;
public static final int ROYALEJSPROJECT = 8192;
public static final int COMPC_PHASES = 16384;
+ public static final int GOOG_DEPS = 32768;
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
index 85f779f..3817b3e 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configuration.java
@@ -1485,6 +1485,73 @@
}
//
+ // 'compiler.allow-import-aliases' option
+ //
+
+ private boolean allowImportAliases = false;
+
+ public boolean getCompilerAllowImportAliases()
+ {
+ return allowImportAliases;
+ }
+
+ /**
+ * Whether the compiler will allow imports to include an optional alias for
+ * the definition name.
+ */
+ @Config
+ @Mapping({ "compiler", "allow-import-aliases" })
+ @RoyaleOnly
+ public void setCompilerAllowImportAliases(ConfigurationValue cv, boolean allow)
+ {
+ this.allowImportAliases = allow;
+ }
+
+ //
+ // 'compiler.allow-abstract-classes' option
+ //
+
+ private boolean allowAbstractClasses = false;
+
+ public boolean getCompilerAllowAbstractClasses()
+ {
+ return allowAbstractClasses;
+ }
+
+ /**
+ * Whether the compiler will allow classes to be abstract.
+ */
+ @Config
+ @Mapping({ "compiler", "allow-abstract-classes" })
+ @RoyaleOnly
+ public void setCompilerAllowAbstractClasses(ConfigurationValue cv, boolean allow)
+ {
+ this.allowAbstractClasses = allow;
+ }
+
+ //
+ // 'compiler.allow-private-constructors' option
+ //
+
+ private boolean allowPrivateConstructors = false;
+
+ public boolean getCompilerAllowPrivateConstructors()
+ {
+ return allowPrivateConstructors;
+ }
+
+ /**
+ * Whether the compiler will allow constructors to be private.
+ */
+ @Config
+ @Mapping({ "compiler", "allow-private-constructors" })
+ @RoyaleOnly
+ public void setCompilerAllowPrivateConstructors(ConfigurationValue cv, boolean allow)
+ {
+ this.allowPrivateConstructors = allow;
+ }
+
+ //
// 'compiler.actionscript-file-encoding' option
//
@@ -3241,11 +3308,11 @@
public boolean debug()
{
// the debug() in as3 and mxml configuration maps to stacktraceLineNumbers
- return verboseStacktraces;
+ return generateDebugTags;
}
public boolean release() {
- return !verboseStacktraces;
+ return !generateDebugTags;
}
@Config
@@ -3986,6 +4053,24 @@
}
//
+ // 'compiler.warn-this-within-closure' option
+ //
+
+ private boolean warn_this_within_closure = true;
+
+ public boolean warn_this_within_closure()
+ {
+ return warn_this_within_closure;
+ }
+
+ @Config(advanced = true)
+ @Mapping({ "compiler", "warn-this-within-closure" })
+ public void setCompilerWarnThisWithinClosure(ConfigurationValue cv, boolean b)
+ {
+ warn_this_within_closure = b;
+ }
+
+ //
// compiler.generate-abstract-syntax-tree
//
@@ -4569,6 +4654,11 @@
//
public String date = null;
+
+ public String getMetadataDate()
+ {
+ return date;
+ }
@Config
@Mapping({ "metadata", "date" })
@@ -4579,6 +4669,25 @@
}
//
+ // 'metadata.dateFormat' option
+ //
+
+ public String dateFormat = null;
+
+ public String getMetadataDateFormat()
+ {
+ return dateFormat;
+ }
+
+ @Config
+ @Mapping({ "metadata", "dateFormat" })
+ @Arguments("text")
+ public void setMetadataDateFormat(ConfigurationValue cv, String text)
+ {
+ dateFormat = text;
+ }
+
+ //
// 'metadata.description' option
//
@@ -5503,6 +5612,24 @@
}
//
+ // 'swf-debugfile-alias' option
+ //
+
+ private String swfDebugfileAlias;
+
+ public String getSwfDebugfileAlias()
+ {
+ return swfDebugfileAlias;
+ }
+
+ @Config
+ @Arguments("filename")
+ public void setSwfDebugfileAlias(ConfigurationValue val, String output) throws ConfigurationException
+ {
+ this.swfDebugfileAlias = output;
+ }
+
+ //
// 'dump-config-file' option from ToolsConfiguration
//
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configurator.java b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configurator.java
index 065f7b1..bb90ae6 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/config/Configurator.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/config/Configurator.java
@@ -2300,6 +2300,7 @@
* --compiler.warn-slow-text-field-addition
* --compiler.warn-unlikely-function-value
* --compiler.warn-xml-class-has-changed
+ * --compiler.warn-this-within-closure
* </pre>
*
* @param warningCode warning code
@@ -2340,6 +2341,7 @@
* @see #WARN_SLOW_TEXTFIELD_ADDITION
* @see #WARN_UNLIKELY_FUNCTION_VALUE
* @see #WARN_XML_CLASS_HAS_CHANGED
+ * @see #WARN_THIS_WITHIN_CLOSURE
*/
@Override
public void checkActionScriptWarning(int warningCode, boolean b)
@@ -2456,6 +2458,9 @@
case WARN_XML_CLASS_HAS_CHANGED:
key = COMPILER_WARN_XML_CLASS_HAS_CHANGED;
break;
+ case WARN_THIS_WITHIN_CLOSURE:
+ key = COMPILER_WARN_THIS_WITHIN_CLOSURE;
+ break;
}
if (key != null)
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerProblemSettings.java b/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerProblemSettings.java
index 355987e..9e0ed7c 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerProblemSettings.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerProblemSettings.java
@@ -157,6 +157,7 @@
* --compiler.warn-slow-text-field-addition
* --compiler.warn-unlikely-function-value
* --compiler.warn-xml-class-has-changed
+ * --compiler.warn-this-within-closure
* </pre>
*
* @param warningCode warning code, one of:
@@ -198,6 +199,7 @@
* <li> WARN_SLOW_TEXTFIELD_ADDITION
* <li> WARN_UNLIKELY_FUNCTION_VALUE
* <li> WARN_XML_CLASS_HAS_CHANGED
+ * <li> WARN_THIS_WITHIN_CLOSURE
* </ul>
* </p>
*/
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerSettingsConstants.java b/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerSettingsConstants.java
index 71a39ec..3dd99ce 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerSettingsConstants.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/config/ICompilerSettingsConstants.java
@@ -51,6 +51,7 @@
static final String DEFAULT_BACKGROUND_COLOR = "--default-background-color";
static final String DEBUG_PASSWORD = "--debug-password";
static final String SWF_VERSION = "--swf-version";
+ static final String COMPILER_WARN_THIS_WITHIN_CLOSURE = "--compiler.warn-this-within-closure";
static final String COMPILER_WARN_XML_CLASS_HAS_CHANGED = "--compiler.warn-xml-class-has-changed";
static final String COMPILER_WARN_UNLIKELY_FUNCTION_VALUE = "--compiler.warn-unlikely-function-value";
static final String COMPILER_WARN_SLOW_TEXT_FIELD_ADDITION = "--compiler.warn-slow-text-field-addition";
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java b/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
index b45cea2..54e17ac 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASKeywordConstants.java
@@ -26,6 +26,7 @@
*/
public interface IASKeywordConstants
{
+ static final String ABSTRACT = "abstract";
static final String AS = "as";
static final String BREAK = "break";
static final String CASE = "case";
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASWarningConstants.java b/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASWarningConstants.java
index 99db8ef..2b6b337 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASWarningConstants.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/constants/IASWarningConstants.java
@@ -209,4 +209,9 @@
* Possible usage of the ActionScript 2.0 <code>XML</code> class.
*/
static final int XML_CLASS_HAS_CHANGED = 3573;
+
+ /**
+ * Keyword this within closure.
+ */
+ static final int THIS_WITHIN_CLOSURE = 20000;
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java b/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
index 21f225b..89bfd78 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/definitions/IDefinition.java
@@ -268,6 +268,13 @@
boolean isStatic();
/**
+ * Is this definition marked as <code>abstract</code>?
+ *
+ * @return <code>true</code> if the definition is <code>abstract</code>.
+ */
+ boolean isAbstract();
+
+ /**
* Determines whether the specified modifier is present on this definition.
* See {@link ASModifier} for the list of modifiers.
*
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/embedding/EmbedAttribute.java b/compiler-common/src/main/java/org/apache/royale/compiler/embedding/EmbedAttribute.java
index a1563fa..87f623e 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/embedding/EmbedAttribute.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/embedding/EmbedAttribute.java
@@ -44,6 +44,7 @@
// report one problem that font embeddeding is not supported.
ADV_ANTI_ALIASING("advancedAntiAliasing"),
EMBED_AS_CFF("embedAsCFF"),
+ UNICODE_RANGE("unicodeRange"),
FONT_FAMILY("fontFamily"),
FONT_NAME("fontName"),
FONT_STYLE("fontStyle"),
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/CombinedFile.java b/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/CombinedFile.java
index bcf48b5..6025ae6 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/CombinedFile.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/CombinedFile.java
@@ -242,4 +242,10 @@
// No BOM tag.
return BOM.NONE;
}
+
+ @Override
+ public void setLastModified(long fileDate) {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/FileSpecification.java b/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/FileSpecification.java
index 67e1fc8..91dd053 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/FileSpecification.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/FileSpecification.java
@@ -26,6 +26,7 @@
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -47,6 +48,8 @@
super(path);
}
+ public static boolean useCRLFFilter = false;
+
@Override
public int hashCode() {
final int prime = 31;
@@ -116,9 +119,12 @@
final BufferedInputStream strm = new BufferedInputStream(new FileInputStream(file));
final BOM bom = getBOM(strm);
strm.skip(bom.pattern.length);
-
- final Reader reader = new BufferedReader(
- new InputStreamReader(strm, bom.charset));
+
+ final InputStreamReader inputSR = useCRLFFilter ?
+ new InputStreamReader(new NoCRLFInputStream(strm), bom.charset) :
+ new InputStreamReader(strm, bom.charset);
+
+ final Reader reader = new BufferedReader(inputSR);
return reader;
}
@@ -127,4 +133,106 @@
{
return new BufferedInputStream(new FileInputStream(getFileHandle()));
}
+
+ @Override
+ public void setLastModified(long fileDate) {
+ File fileHandle = getFileHandle();
+ fileHandle.setLastModified(fileDate);
+ }
+
+ public static class NoCRLFInputStream extends FilterInputStream
+ {
+ public NoCRLFInputStream(InputStream fileInputStream)
+ {
+ super(fileInputStream);
+ }
+
+ /**
+ * if we read a CR, just skip it, assuming it will
+ * be followed by an LF
+ */
+ @Override
+ public int read() throws IOException
+ {
+ int retval = super.read();
+ if (retval == '\r')
+ retval = super.read();
+ return retval;
+ }
+
+ /**
+ * if we read a CR, just skip it, assuming it will
+ * be followed by an LF
+ * @throws IOException
+ */
+ @Override
+ public int read(byte[] b) throws IOException
+ {
+ int n = b.length;
+ byte[] temp = new byte[b.length];
+ int retval = super.read(temp);
+ if (retval == -1)
+ return -1;
+
+ int j = 0;
+ for (int i = 0; i < retval; i++)
+ {
+ byte c = temp[i];
+ if (c == '\r')
+ continue;
+ else
+ b[j++] = c;
+ }
+ while (j < retval)
+ {
+ int extra = super.read(b, j, 1);
+ if (extra == -1)
+ break;
+ byte c = b[j];
+ if (c == '\r')
+ continue;
+ else
+ j++;
+ }
+ return j;
+ }
+
+ /**
+ * if we read a CR, just skip it, assuming it will
+ * be followed by an LF
+ * @throws IOException
+ */
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException
+ {
+ byte[] temp = new byte[len];
+ int retval = super.read(temp, off, len);
+ if (retval == -1)
+ return -1;
+ if (retval == 0)
+ return 0;
+
+ int j = 0;
+ for (int i = off; i < retval; i++)
+ {
+ byte c = temp[i];
+ if (c == '\r')
+ continue;
+ else
+ b[off + j++] = c;
+ }
+// System.out.println(new String(b));
+ while (j < retval)
+ {
+ int extra = super.read(b, off + j, 1);
+ if (extra == -1)
+ break;
+ byte c = b[off + j];
+ if (c == '\r')
+ continue;
+ j++;
+ }
+ return j;
+ }
+ }
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/IFileSpecification.java b/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/IFileSpecification.java
index bb40f3e..246ff8d 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/IFileSpecification.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/filespecs/IFileSpecification.java
@@ -49,6 +49,13 @@
*/
long getLastModified();
+
+ /**
+ * Set the last modified timestamp of the file
+ * @param fileDate the last modified timestamp
+ */
+ void setLastModified(long fileDate);
+
/**
* @return true if this file specification refers to an open document and
* the {@link #createReader()} method returns a reader that reads the live
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/CompilerProblemSettings.java b/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/CompilerProblemSettings.java
index 868293f..3bdc442 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/CompilerProblemSettings.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/CompilerProblemSettings.java
@@ -213,6 +213,9 @@
case ICompilerSettings.WARN_XML_CLASS_HAS_CHANGED:
warning = configuration.warn_xml_class_has_changed();
break;
+ case ICompilerSettings.WARN_THIS_WITHIN_CLOSURE:
+ warning = configuration.warn_this_within_closure();
+ break;
}
return warning;
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/ICompilerSettings.java b/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/ICompilerSettings.java
index 4bc7e75..054de47 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/ICompilerSettings.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/ICompilerSettings.java
@@ -547,6 +547,11 @@
* Possible usage of the ActionScript 2.0 <code>XML</code> class.
*/
int WARN_XML_CLASS_HAS_CHANGED = IASWarningConstants.XML_CLASS_HAS_CHANGED;
+
+ /**
+ * Keyword this within closure.
+ */
+ int WARN_THIS_WITHIN_CLOSURE = IASWarningConstants.THIS_WITHIN_CLOSURE;
/**
* Enables checking of the following ActionScript warnings:
@@ -588,6 +593,7 @@
* --compiler.warn-slow-text-field-addition
* --compiler.warn-unlikely-function-value
* --compiler.warn-xml-class-has-changed
+ * --compiler.warn-this-within-closure
* </pre>
*
* @param warningCode Warning code.
@@ -629,6 +635,7 @@
* @see #WARN_SLOW_TEXTFIELD_ADDITION
* @see #WARN_UNLIKELY_FUNCTION_VALUE
* @see #WARN_XML_CLASS_HAS_CHANGED
+ * @see #WARN_THIS_WITHIN_CLOSURE
*/
void checkActionScriptWarning(int warningCode, boolean b);
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/TargetSettings.java b/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/TargetSettings.java
index bc2ab9f..919b4fb 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/TargetSettings.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/internal/config/TargetSettings.java
@@ -594,4 +594,15 @@
{
return configuration.getRemoveDeadCode();
}
+
+ @Override
+ public String getSWFMetadataDate() {
+ return configuration.getMetadataDate();
+ }
+
+ @Override
+ public String getSWFMetadataDateFormat() {
+ return configuration.getMetadataDateFormat();
+ }
+
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/internal/parsing/as/OffsetLookup.java b/compiler-common/src/main/java/org/apache/royale/compiler/internal/parsing/as/OffsetLookup.java
index 376fb47..26b7699 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/internal/parsing/as/OffsetLookup.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/internal/parsing/as/OffsetLookup.java
@@ -88,7 +88,8 @@
* @param absoluteOffset absolute offset
* @return The {@code OffsetCue} that applies to the given absolute offset.
*/
- private OffsetCue findOffsetCue(int absoluteOffset)
+ @SuppressWarnings("deprecation")
+ private OffsetCue findOffsetCue(int absoluteOffset)
{
if (offsetCueList.isEmpty() || absoluteOffset < 0)
return null;
@@ -169,6 +170,12 @@
{
return cue.filename.equals(filename);
}
+
+ @Override
+ public boolean test(OffsetCue input)
+ {
+ return apply(input);
+ }
});
// Find a list of OffsetCues before the local offset.
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/problems/FilePrivateItemsWithMainVarWarningProblem.java b/compiler-common/src/main/java/org/apache/royale/compiler/problems/FilePrivateItemsWithMainVarWarningProblem.java
new file mode 100644
index 0000000..10e8db7
--- /dev/null
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/problems/FilePrivateItemsWithMainVarWarningProblem.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.common.ISourceLocation;
+import org.apache.royale.compiler.problems.annotations.DefaultSeverity;
+
+/**
+ * When a variable is the externally accessible package scoped definition, there is a
+ * namespace implementation issue in javascript for other file-private members.
+ * This use case seems limited, as it is likely that the externally visible variable
+ * definition would need to depend on the file-private definitions, otherwise it is
+ * questionable why they would even exist. Given the likelihood that this is very limited,
+ * it is currently not recommended.
+ */
+@DefaultSeverity(CompilerProblemSeverity.WARNING)
+public class FilePrivateItemsWithMainVarWarningProblem extends CompilerProblem
+{
+ public static final String DESCRIPTION =
+ "Using file-private definitions outside a package level variable is not recommended and may not work (javascript).";
+
+ public static final int warningCode = 5045;
+
+ public FilePrivateItemsWithMainVarWarningProblem(ISourceLocation site)
+ {
+ super(site);
+ }
+
+ public FilePrivateItemsWithMainVarWarningProblem(String sourcePath, int start, int end, int line, int column, int endLine, int endColumn)
+ {
+ super(sourcePath, start, end, line, column, endLine, endColumn);
+ }
+
+}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/problems/ParameterHasNoTypeDeclarationProblem.java b/compiler-common/src/main/java/org/apache/royale/compiler/problems/ParameterHasNoTypeDeclarationProblem.java
new file mode 100644
index 0000000..d64d973
--- /dev/null
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/problems/ParameterHasNoTypeDeclarationProblem.java
@@ -0,0 +1,46 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * <pre>
+ * Example:
+ * function foo(baz) : void {
+ * }
+ * </pre>
+ *
+ */
+public final class ParameterHasNoTypeDeclarationProblem extends SemanticWarningProblem
+{
+ public static final String DESCRIPTION = "parameter '${paramName}' for function '${functionName}' has no type declaration.";
+
+ public static final int warningCode = 1008;
+ public ParameterHasNoTypeDeclarationProblem(IASNode site, String paramName, String functionName)
+ {
+ super(site);
+ this.paramName = paramName;
+ this.functionName = functionName;
+ }
+
+ public final String paramName;
+ public final String functionName;
+}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/problems/PublicVarWarningProblem.java b/compiler-common/src/main/java/org/apache/royale/compiler/problems/PublicVarWarningProblem.java
index 02fddc8..6a4ce55 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/problems/PublicVarWarningProblem.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/problems/PublicVarWarningProblem.java
@@ -41,4 +41,10 @@
{
super(site);
}
+
+ public PublicVarWarningProblem(String sourcePath, int start, int end, int line, int column, int endLine, int endColumn)
+ {
+ super(sourcePath, start, end, line, column, endLine, endColumn);
+ }
+
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/problems/ThisUsedInClosureProblem.java b/compiler-common/src/main/java/org/apache/royale/compiler/problems/ThisUsedInClosureProblem.java
new file mode 100644
index 0000000..28ef5df
--- /dev/null
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/problems/ThisUsedInClosureProblem.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Diagnostic emitted when the method body semantic checker detects
+ * a reference to "this" in a closure
+ */
+public final class ThisUsedInClosureProblem extends SemanticWarningProblem
+{
+ public static final String DESCRIPTION =
+ "Encountered ${THIS} keyword within closure. Value of ${THIS} will not be the same as enclosing scope.";
+
+ public static final int warningCode = 20000;
+
+ public ThisUsedInClosureProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String THIS = "this";
+}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java b/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
index 332576a..00042f9 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/projects/ICompilerProject.java
@@ -265,6 +265,21 @@
/**
* @return True if a subclass can have a private API with the same name as a private API in its base classes.
*/
- boolean getAllowPrivateNameConflicts();
+ boolean getAllowPrivateNameConflicts();
+
+ /**
+ * @return True if import aliases are allowed.
+ */
+ boolean getAllowImportAliases();
+
+ /**
+ * @return True if abstract classes are allowed.
+ */
+ boolean getAllowAbstractClasses();
+
+ /**
+ * @return True if private constructors are allowed.
+ */
+ boolean getAllowPrivateConstructors();
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/targets/ITargetSettings.java b/compiler-common/src/main/java/org/apache/royale/compiler/targets/ITargetSettings.java
index 946e670..f1b6672 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/targets/ITargetSettings.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/targets/ITargetSettings.java
@@ -500,5 +500,19 @@
* @return An array of strings specifying the import targets.
*/
String[] getMxmlImplicitImports();
+
+ /**
+ * Gets Date string used in RDF metadata.
+ *
+ * @return null or RDF date.
+ */
+ String getSWFMetadataDate();
+
+ /**
+ * Gets DateFormat string used in RDF metadata date.
+ *
+ * @return null or Java SimpleDateFormat pattern.
+ */
+ String getSWFMetadataDateFormat();
}
diff --git a/compiler-common/src/main/java/org/apache/royale/compiler/tree/as/IFunctionNode.java b/compiler-common/src/main/java/org/apache/royale/compiler/tree/as/IFunctionNode.java
index e85cb07..64755fd 100644
--- a/compiler-common/src/main/java/org/apache/royale/compiler/tree/as/IFunctionNode.java
+++ b/compiler-common/src/main/java/org/apache/royale/compiler/tree/as/IFunctionNode.java
@@ -172,16 +172,4 @@
* JS codegen needs to know about them.
*/
void rememberLocalFunction(IFunctionNode localFunction);
-
- /**
- * flag to determine whether to emit the local function
- * or a reference to it
- */
- boolean getEmittingLocalFunctions();
-
- /**
- * flag to determine whether to emit the local function
- * or a reference to it
- */
- void setEmittingLocalFunctions(boolean emit);
}
diff --git a/compiler-externc/.classpath b/compiler-externc/.classpath
index 2274c0b..1c61f77 100644
--- a/compiler-externc/.classpath
+++ b/compiler-externc/.classpath
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src/test/java"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java">
+ <attributes>
+ <attribute name="test" value="true"/>
+ </attributes>
+ </classpathentry>
<classpathentry kind="src" path="src/main/java"/>
<classpathentry kind="lib" path="../compiler/lib/external/commons-cli.jar"/>
<classpathentry kind="lib" path="../compiler/lib/external/commons-io.jar"/>
diff --git a/compiler-externc/build.xml b/compiler-externc/build.xml
index 773a0ee..57b349f 100644
--- a/compiler-externc/build.xml
+++ b/compiler-externc/build.xml
@@ -161,6 +161,7 @@
<target name="clean" description="clean">
<delete dir="${compiler-externc}/target/classes"/>
+ <delete file="${compiler-externc}/target/js.swc"/>
</target>
<target name="wipe" depends="clean" description="Wipes everything that didn't come from Git.">
diff --git a/compiler-externc/pom.xml b/compiler-externc/pom.xml
index 249ed9d..a9ff8b1 100644
--- a/compiler-externc/pom.xml
+++ b/compiler-externc/pom.xml
@@ -1,153 +1,158 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>compiler-externc</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: Externc</name>
- <description>The Apache Royale Compiler Externs Compiler</description>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-build-tools</artifactId>
- <version>${compiler-build-tools.version}</version>
- <executions>
- <execution>
- <id>unpack-closure-externs</id>
- <phase>validate</phase>
- <goals>
- <goal>unpack-resources</goal>
- </goals>
- <configuration>
- <resource>externs.zip</resource>
- </configuration>
- </execution>
- </executions>
- <!--
- Dependency to the closure compiler externs artifact so
- the "unpack-resources" goal can find the externs.zip
- -->
- <dependencies>
- <dependency>
- <groupId>com.google.javascript</groupId>
- <artifactId>closure-compiler-externs</artifactId>
- <version>v20170626</version>
- </dependency>
- </dependencies>
- </plugin>
- <!-- Make the surefire execute all unit-tests -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>2.19</version>
- <configuration>
- <includes>
- <include>org/**/TestExternES3.java</include>
- <include>org/**/TestExternChrome.java</include>
- <include>org/**/TestExternJSMissing.java</include>
- <include>org/**/TestAnnotationEnum.java</include>
- <include>org/**/TestCollectImports.java</include>
- <include>org/**/TestConstructor.java</include>
- <include>org/**/TestPackageNamespace.java</include>
- <include>org/**/TestReferenceModel.java</include>
- <include>org/**/TestTypeTypedefs.java</include>
- <include>org/**/TestTypeInheritance.java</include>
- </includes>
- <excludes>
- </excludes>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-failsafe-plugin</artifactId>
- <version>2.18.1</version>
- <configuration>
- <includes>
- <include>org/**/TestExternES3.java</include>
- <include>org/**/TestExternChrome.java</include>
- <include>org/**/TestExternJSMissing.java</include>
- <include>org/**/TestAnnotationEnum.java</include>
- <include>org/**/TestCollectImports.java</include>
- <include>org/**/TestConstructor.java</include>
- <include>org/**/TestPackageNamespace.java</include>
- <include>org/**/TestReferenceModel.java</include>
- <include>org/**/TestTypeTypedefs.java</include>
- <include>org/**/TestTypeInheritance.java</include>
- </includes>
- <excludes>
- </excludes>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <version>2.2</version>
- <executions>
- <execution>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-
-
- <dependencies>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-common</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>com.google.javascript</groupId>
- <artifactId>closure-compiler</artifactId>
- <version>v20170626</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-test-utils</artifactId>
- <version>0.9.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>compiler-externc</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: Externc</name>
+ <description>The Apache Royale Compiler Externs Compiler</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-build-tools</artifactId>
+ <version>${compiler-build-tools.version}</version>
+ <executions>
+ <execution>
+ <id>unpack-closure-externs</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>unpack-resources</goal>
+ </goals>
+ <configuration>
+ <resource>externs.zip</resource>
+ </configuration>
+ </execution>
+ </executions>
+ <!--
+ Dependency to the closure compiler externs artifact so
+ the "unpack-resources" goal can find the externs.zip
+ -->
+ <dependencies>
+ <dependency>
+ <groupId>com.google.javascript</groupId>
+ <artifactId>closure-compiler-externs</artifactId>
+ <version>v20181210</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <!-- Make the surefire execute all unit-tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19</version>
+ <configuration>
+ <includes>
+ <include>org/**/TestExternES3.java</include>
+ <include>org/**/TestExternChrome.java</include>
+ <include>org/**/TestExternJSMissing.java</include>
+ <include>org/**/TestAnnotationEnum.java</include>
+ <include>org/**/TestCollectImports.java</include>
+ <include>org/**/TestConstructor.java</include>
+ <include>org/**/TestPackageNamespace.java</include>
+ <include>org/**/TestReferenceModel.java</include>
+ <include>org/**/TestTypeTypedefs.java</include>
+ <include>org/**/TestTypeInheritance.java</include>
+ </includes>
+ <excludes>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <includes>
+ <include>org/**/TestExternES3.java</include>
+ <include>org/**/TestExternChrome.java</include>
+ <include>org/**/TestExternJSMissing.java</include>
+ <include>org/**/TestAnnotationEnum.java</include>
+ <include>org/**/TestCollectImports.java</include>
+ <include>org/**/TestConstructor.java</include>
+ <include>org/**/TestPackageNamespace.java</include>
+ <include>org/**/TestReferenceModel.java</include>
+ <include>org/**/TestTypeTypedefs.java</include>
+ <include>org/**/TestTypeInheritance.java</include>
+ </includes>
+ <excludes>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.2</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-common</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.javascript</groupId>
+ <artifactId>closure-compiler</artifactId>
+ <version>v20181210</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-test-utils</artifactId>
+ <version>0.9.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/AbstractCompilerPass.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/AbstractCompilerPass.java
index 6d5387a..ed0c68e 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/AbstractCompilerPass.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/AbstractCompilerPass.java
@@ -52,7 +52,7 @@
public void process(Node externs, Node root)
{
//NodeTraversal.traverse(compiler, root, this);
- NodeTraversal.traverseRootsEs6(compiler, this, externs, root);
+ NodeTraversal.traverseRoots(compiler, this, externs, root);
}
protected void log(Node n)
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/ReferenceCompiler.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/ReferenceCompiler.java
index e58c228..8e217bd 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/ReferenceCompiler.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/pass/ReferenceCompiler.java
@@ -67,7 +67,7 @@
options.setPrettyPrint(true);
options.setLineLengthThreshold(80);
options.setPreferSingleQuotes(true);
- options.setIdeMode(true);
+ //options.setIdeMode(true);
options.setParseJsDocDocumentation(Config.JsDocParsing.INCLUDE_DESCRIPTIONS_NO_WHITESPACE);
options.setExternExports(false);
options.setExtraAnnotationNames(Arrays.asList(asdocTags));
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/BaseReference.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/BaseReference.java
index e2204b6..0be229f 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/BaseReference.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/BaseReference.java
@@ -32,6 +32,7 @@
import com.google.javascript.rhino.JSDocInfo.TypePosition;
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
+import com.google.javascript.rhino.jstype.JSType.Nullability;
public abstract class BaseReference
{
@@ -275,7 +276,7 @@
if (outputJS && parameterType != null)
{
sb.append("{");
- sb.append(mapBackToJS(getModel().evaluate(parameterType).toAnnotationString(), optional));
+ sb.append(mapBackToJS(getModel().evaluate(parameterType).toAnnotationString(Nullability.EXPLICIT), optional));
sb.append("}");
sb.append(" ");
}
@@ -292,7 +293,7 @@
if (!outputJS && parameterType != null)
{
sb.append("[");
- sb.append(getModel().evaluate(parameterType).toAnnotationString());
+ sb.append(getModel().evaluate(parameterType).toAnnotationString(Nullability.EXPLICIT));
sb.append("]");
sb.append(" ");
}
@@ -313,9 +314,9 @@
sb.append(" * @returns ");
sb.append("{");
if (outputJS)
- sb.append(mapBackToJS(getModel().evaluate(returnType).toAnnotationString(), false));
+ sb.append(mapBackToJS(getModel().evaluate(returnType).toAnnotationString(Nullability.EXPLICIT), false));
else
- sb.append(getModel().evaluate(returnType).toAnnotationString());
+ sb.append(getModel().evaluate(returnType).toAnnotationString(Nullability.EXPLICIT));
sb.append("} ");
String description = getComment().getReturnDescription();
if (description != null)
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
index 7817e7c..d32cde3 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ClassReference.java
@@ -40,6 +40,7 @@
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.ObjectType;
+import com.google.javascript.rhino.jstype.TemplatizedType;
public class ClassReference extends BaseReference
{
@@ -502,7 +503,7 @@
ArrayList<ClassReference> result = new ArrayList<ClassReference>();
for (JSTypeExpression jsTypeExpression : getComment().getImplementedInterfaces())
{
- String interfaceName = getModel().evaluate(jsTypeExpression).toAnnotationString();
+ String interfaceName = getModel().evaluate(jsTypeExpression).getDisplayName();
ClassReference reference = getModel().getClassReference(interfaceName);
if (reference != null)
result.add(reference);
@@ -515,7 +516,7 @@
ArrayList<ClassReference> result = new ArrayList<ClassReference>();
for (JSTypeExpression jsTypeExpression : getComment().getExtendedInterfaces())
{
- String interfaceName = getModel().evaluate(jsTypeExpression).toAnnotationString();
+ String interfaceName = getModel().evaluate(jsTypeExpression).getDisplayName();
ClassReference reference = getModel().getClassReference(interfaceName);
if (reference != null)
result.add(reference);
@@ -530,7 +531,11 @@
for (JSTypeExpression jsTypeExpression : implementedInterfaces)
{
JSType jsType = getModel().evaluate(jsTypeExpression);
- String interfaceName = jsType.toAnnotationString();
+ if (jsType.isTemplatizedType())
+ {
+ jsType = ((TemplatizedType)jsType).getReferencedType();
+ }
+ String interfaceName = jsType.getDisplayName();
ClassReference interfaceReference = getModel().getClassReference(interfaceName);
if (interfaceReference != null)
result.add(interfaceReference);
@@ -639,6 +644,11 @@
{
// skipping Object.prototype.toString() allows toString(opt_radix) for Number, int and uint
}
+ else if (getQualifiedName().equals("Object") && functionName.equals("toJSON"))
+ {
+ // skipping Object.prototype.toJSON(). Doesn't seem to be in the spec and excluding
+ // in the config seems to also block Date.toJSON
+ }
else
{
instanceMethods.put(functionName, method);
@@ -871,7 +881,7 @@
sb.append("extends ");
for (JSTypeExpression jsTypeExpression : extendedInterfaces)
{
- String value = getModel().evaluate(jsTypeExpression).toAnnotationString();
+ String value = getModel().evaluate(jsTypeExpression).toString();
sb.append(value);
if (--len > 0)
sb.append(", ");
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ConstantReference.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ConstantReference.java
index f4c8351..265a842 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ConstantReference.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ConstantReference.java
@@ -74,7 +74,17 @@
if (getQualifiedName().equals("undefined"))
{
sb.append(indent);
- sb.append("public const undefined:* = 0;\n");
+ sb.append("public const undefined:* = void 0;\n");
+ }
+ else if (getQualifiedName().equals("NaN"))
+ {
+ sb.append(indent);
+ sb.append("public const NaN:Number = 0/0;\n");
+ }
+ else if (getQualifiedName().equals("Infinity"))
+ {
+ sb.append(indent);
+ sb.append("public const Infinity:Number = 1/0;\n");
}
else
{
@@ -91,6 +101,7 @@
HashMap<String, String> map = new HashMap<String, String>();
map.put("Number", "0");
map.put("undefined", "0");
+ map.put("Boolean", "false");
if (map.containsKey(type))
return map.get(type);
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FieldReference.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FieldReference.java
index 3f95e37..95c35ad 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FieldReference.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FieldReference.java
@@ -32,6 +32,7 @@
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.JSType;
+import com.google.javascript.rhino.jstype.JSType.Nullability;
public class FieldReference extends MemberReference
{
@@ -79,7 +80,7 @@
{
jsType = getModel().evaluate(getComment().getType());
}
- return jsType != null ? jsType.toAnnotationString() : "Object";
+ return jsType != null ? jsType.toAnnotationString(Nullability.EXPLICIT) : "Object";
}
public FieldReference(ReferenceModel model, ClassReference classReference, Node node, String name,
@@ -87,7 +88,6 @@
{
super(model, classReference, node, name, comment);
Collection<Marker> markers = comment.getMarkers();
- Marker[] markerArray = new Marker[markers.size()];
for (Marker marker : markers)
{
if (marker.getAnnotation().getItem().equals("const"))
@@ -284,7 +284,7 @@
sb.append(indent);
sb.append(" * @type ");
sb.append("{");
- sb.append(mapBackToJS(getModel().evaluate(type).toAnnotationString(), false));
+ sb.append(mapBackToJS(getModel().evaluate(type).toAnnotationString(Nullability.EXPLICIT), false));
sb.append("} ");
sb.append("\n");
}
@@ -293,7 +293,7 @@
sb.append(indent);
sb.append(" * @see JSType - ");
sb.append("[");
- sb.append(getModel().evaluate(type).toAnnotationString());
+ sb.append(getModel().evaluate(type).toAnnotationString(Nullability.EXPLICIT));
sb.append("] ");
String description = getComment().getReturnDescription();
if (description != null)
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FunctionReference.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FunctionReference.java
index 6fd200a..8351dd1 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FunctionReference.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/FunctionReference.java
@@ -130,7 +130,7 @@
braces = " { " + returns + " }";
- sb.append(" ");
+ sb.append(indent);
sb.append(publicModifier);
sb.append(staticValue);
sb.append("function ");
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/MethodReference.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/MethodReference.java
index 218e910..df02449 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/MethodReference.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/MethodReference.java
@@ -31,6 +31,7 @@
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.JSType;
+import com.google.javascript.rhino.jstype.JSType.Nullability;
public class MethodReference extends MemberReference
{
@@ -69,7 +70,7 @@
public String toReturnTypeAnnotationString()
{
JSType jsType = getModel().evaluate(getComment().getReturnType());
- return jsType.toAnnotationString();
+ return jsType.toAnnotationString(Nullability.EXPLICIT);
}
public MethodReference(ReferenceModel model, ClassReference classReference, Node node, String name,
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
index f0fcd24..1fe4d5c 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/reference/ReferenceModel.java
@@ -37,6 +37,7 @@
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.JSType;
+import com.google.javascript.rhino.jstype.TemplatizedType;
public class ReferenceModel
{
@@ -328,6 +329,10 @@
try
{
jsType = expression.evaluate(null, jscompiler.getTypeRegistry());
+ if (jsType.isTemplatizedType())
+ {
+ jsType = ((TemplatizedType)jsType).getReferencedType();
+ }
}
catch (Exception e)
{
diff --git a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/utils/JSTypeUtils.java b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/utils/JSTypeUtils.java
index a2f85ee..2dd8ec5 100644
--- a/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/utils/JSTypeUtils.java
+++ b/compiler-externc/src/main/java/org/apache/royale/compiler/internal/codegen/typedefs/utils/JSTypeUtils.java
@@ -29,7 +29,9 @@
import com.google.javascript.rhino.JSTypeExpression;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.NamedType;
+import com.google.javascript.rhino.jstype.TemplatizedType;
import com.google.javascript.rhino.jstype.UnionType;
+import com.google.javascript.rhino.jstype.JSType.Nullability;
public class JSTypeUtils
{
@@ -92,7 +94,7 @@
public static String toEnumTypeString(BaseReference reference)
{
JSTypeExpression enumParameterType = reference.getComment().getEnumParameterType();
- String overrideStringType = transformType(reference.getModel().evaluate(enumParameterType).toAnnotationString());
+ String overrideStringType = transformType(reference.getModel().evaluate(enumParameterType).toAnnotationString(Nullability.EXPLICIT));
return overrideStringType;
}
@@ -167,6 +169,10 @@
{
return "* /* " + type + " */";
}
+ else if (jsType.isTemplatizedType())
+ {
+ return ((TemplatizedType)jsType).getReferencedType().toString();
+ }
else
{
if (type.indexOf("Array<") == 0)
diff --git a/compiler-externc/src/test/build.xml b/compiler-externc/src/test/build.xml
index 9e11013..8c79786 100644
--- a/compiler-externc/src/test/build.xml
+++ b/compiler-externc/src/test/build.xml
@@ -88,7 +88,6 @@
<fileset dir="${compiler.externc}/target/test-classes">
<!-- externs tests -->
<include name="**/TestExternES3.class"/>
- <include name="**/TestExternChrome.class"/>
<include name="**/TestExternJSMissing.class"/>
<include name="**/TestAnnotationEnum.class"/>
<include name="**/TestCollectImports.class"/>
diff --git a/compiler-externc/src/test/config/externc-config.xml b/compiler-externc/src/test/config/externc-config.xml
index 3171696..ee1ed35 100644
--- a/compiler-externc/src/test/config/externc-config.xml
+++ b/compiler-externc/src/test/config/externc-config.xml
@@ -67,7 +67,6 @@
<path-element>../../../target/downloads/browser/whatwg_encoding.js</path-element>
- <path-element>../../../target/downloads/browser/chrome.js</path-element>
<!-- path-element>../../../target/downloads/browser/fetchapi.js</path-element>-->
<path-element>../../../target/downloads/browser/fileapi.js</path-element>
<path-element>../../../target/downloads/browser/flash.js</path-element>
@@ -107,6 +106,7 @@
<class-exclude>
<class>controlRange</class>
<class>ITemplateArray</class>
+ <class>Symbol</class>
</class-exclude>
<!-- Object.toString() is excluded by the ExternC compiler. Otherwise
@@ -156,6 +156,14 @@
<class>Document</class>
<name>createTreeWalker</name>
</exclude>
+ <exclude>
+ <class>AsyncGenerator</class>
+ <name>next</name>
+ </exclude>
+ <exclude>
+ <class>Generator</class>
+ <name>next</name>
+ </exclude>
<!-- SVG -->
<exclude><class>SVGStylable</class><name>className</name></exclude>
<exclude><class>SVGStylable</class><name>style</name></exclude>
diff --git a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestConstructor.java b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestConstructor.java
index 099ec7d..6455ffa 100644
--- a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestConstructor.java
+++ b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestConstructor.java
@@ -30,6 +30,8 @@
import org.apache.royale.compiler.internal.codegen.typedefs.reference.ClassReference;
import org.junit.Test;
+import com.google.javascript.rhino.jstype.JSType.Nullability;
+
public class TestConstructor extends TypedefsTestBase
{
@@ -82,13 +84,13 @@
assertEquals(
"number",
- evaluateParam(FooOptVarArgs.getConstructor(), "arg1").toAnnotationString());
+ evaluateParam(FooOptVarArgs.getConstructor(), "arg1").toAnnotationString(Nullability.EXPLICIT));
assertEquals(
"*",
- evaluateParam(FooOptVarArgs.getConstructor(), "opt_arg2").toAnnotationString());
+ evaluateParam(FooOptVarArgs.getConstructor(), "opt_arg2").toAnnotationString(Nullability.EXPLICIT));
assertEquals(
"*",
- evaluateParam(FooOptVarArgs.getConstructor(), "var_args").toAnnotationString());
+ evaluateParam(FooOptVarArgs.getConstructor(), "var_args").toAnnotationString(Nullability.EXPLICIT));
}
@Test
diff --git a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternChrome.java b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternChrome.java
deleted file mode 100644
index f7bb0d3..0000000
--- a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternChrome.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.royale.compiler.internal.codegen.typedefs;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-
-import org.apache.royale.compiler.clients.ExternCConfiguration;
-import org.apache.royale.compiler.internal.codegen.typedefs.reference.ClassReference;
-import org.apache.royale.compiler.problems.ICompilerProblem;
-import org.junit.Test;
-
-import com.google.javascript.jscomp.Result;
-
-public class TestExternChrome extends TypedefsTestBase
-{
- @Test
- public void test_classes() throws IOException
- {
- client.cleanOutput();
- Result result = compile();
- assertTrue(result.success);
- if (model.problems.getProblems().size() > 0)
- {
- for (ICompilerProblem problem : model.problems.getProblems())
- System.out.println(problem.toString() + " " + problem.getSourcePath() + " " + problem.getLine());
- }
- assertEquals(0, model.problems.getProblems().size());
-
- String[] classes = {
- "chrome",
- "chrome.app",
- "chrome.webstore",
- "chrome.runtime",
- "chrome.runtime.lastError",
-
- "Port",
- "ChromeEvent",
- "ChromeStringEvent",
- "ChromeBooleanEvent",
- "ChromeNumberEvent",
- "ChromeObjectEvent",
- "ChromeStringArrayEvent",
- "ChromeStringStringEvent",
- "MessageSender",
- "Tab",
- "ChromeLoadTimes",
- "ChromeCsiInfo" };
-
- assertEquals(322, model.getClasses().size());
- for (String className : classes)
- {
- assertTrue(model.hasClass(className));
- }
-
- client.emit();
- }
-
- @Test
- public void test_members() throws IOException
- {
- client.cleanOutput();
- Result result = compile();
- assertTrue(result.success);
- if (model.problems.getProblems().size() > 0)
- {
- for (ICompilerProblem problem : model.problems.getProblems())
- System.out.println(problem.toString() + " " + problem.getSourcePath() + " " + problem.getLine());
- }
- assertEquals(0, model.problems.getProblems().size());
-
- // Port
- ClassReference Port = model.getClassReference("Port");
- assertNotNull(Port);
- assertTrue(Port.hasInstanceField("name"));
- assertTrue(Port.hasInstanceField("onDisconnect"));
- assertTrue(Port.hasInstanceField("onMessage"));
- assertTrue(Port.hasInstanceField("sender"));
-
- assertTrue(Port.hasInstanceMethod("postMessage"));
- assertTrue(Port.hasInstanceMethod("disconnect"));
-
- assertEquals("string", Port.getInstanceField("name").toTypeAnnotationString());
- assertEquals("ChromeEvent",
- Port.getInstanceField("onDisconnect").toTypeAnnotationString());
- assertEquals("ChromeEvent",
- Port.getInstanceField("onMessage").toTypeAnnotationString());
- assertEquals("(MessageSender|undefined)",
- Port.getInstanceField("sender").toTypeAnnotationString());
-
- // chrome
- ClassReference chrome = model.getClassReference("chrome");
- assertNotNull(chrome);
- assertTrue(chrome.hasStaticMethod("loadTimes"));
- assertTrue(chrome.hasStaticMethod("csi"));
- assertEquals("ChromeLoadTimes",
- chrome.getStaticMethod("loadTimes").toReturnTypeAnnotationString());
- assertEquals("ChromeCsiInfo",
- chrome.getStaticMethod("csi").toReturnTypeAnnotationString());
-
- // chrome.app
- ClassReference chrome_app = model.getClassReference("chrome.app");
- assertNotNull(chrome_app);
- assertTrue(chrome_app.hasStaticField("isInstalled"));
- assertEquals("boolean",
- chrome_app.getStaticField("isInstalled").toTypeAnnotationString());
-
- // chrome.runtime
- ClassReference chrome_runtime = model.getClassReference("chrome.runtime");
- assertNotNull(chrome_runtime);
- assertTrue(chrome_runtime.hasStaticMethod("connect"));
- assertTrue(chrome_runtime.hasStaticMethod("sendMessage"));
-
- // chrome.runtime.lastError
- ClassReference chrome_runtime_lastError = model.getClassReference("chrome.runtime.lastError");
- assertNotNull(chrome_runtime_lastError);
- assertTrue(chrome_runtime_lastError.hasStaticField("message"));
- assertEquals(
- "(string|undefined)",
- chrome_runtime_lastError.getStaticField("message").toTypeAnnotationString());
-
- // chrome.webstore
- ClassReference chrome_webstore = model.getClassReference("chrome.webstore");
- assertNotNull(chrome_webstore);
- assertTrue(chrome_webstore.hasStaticField("onInstallStageChanged"));
- assertTrue(chrome_webstore.hasStaticField("onDownloadProgress"));
- assertTrue(chrome_webstore.hasStaticMethod("install"));
-
- // Code generated
- assertTrue(chrome.hasStaticField("app"));
- assertTrue(chrome.hasStaticField("runtime"));
- assertTrue(chrome.hasStaticField("webstore"));
-
- assertTrue(chrome_runtime.hasInstanceField("lastError"));
- }
-
- @Override
- protected void configure(ExternCConfiguration install) throws IOException
- {
- TypedefsTestUtils.init();
- config.setASRoot(TypedefsTestUtils.AS_ROOT_DIR);
-
- String coreRoot = TypedefsTestUtils.TYPEDEFS_JS_DIR.getAbsolutePath();
- config.addTypedef(coreRoot + "/es3.js");
- config.addTypedef(coreRoot + "/es6.js");
- config.addTypedef(coreRoot + "/browser/chrome.js");
- config.addTypedef(coreRoot + "/browser/html5.js");
- config.addTypedef(coreRoot + "/browser/ie_dom.js");
- config.addTypedef(coreRoot + "/browser/gecko_dom.js");
- config.addTypedef(coreRoot + "/browser/w3c_css.js");
- config.addTypedef(coreRoot + "/browser/w3c_event.js");
- config.addTypedef(coreRoot + "/browser/w3c_range.js");
- config.addTypedef(coreRoot + "/browser/w3c_dom1.js");
- config.addTypedef(coreRoot + "/browser/w3c_dom2.js");
- config.addTypedef(coreRoot + "/browser/w3c_dom3.js");
- config.addTypedef(coreRoot + "/browser/w3c_xml.js");
- }
-
-}
diff --git a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternES3.java b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternES3.java
index 3acc4b0..e2a65c1 100644
--- a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternES3.java
+++ b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternES3.java
@@ -60,7 +60,7 @@
"Math" };
// IObject and IArrayLike are two extras
- assertEquals(23, model.getClasses().size());
+ assertEquals(24, model.getClasses().size());
for (String className : classes)
{
assertTrue(model.hasClass(className));
diff --git a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternJasmine.java b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternJasmine.java
index 233643b..e9b85f7 100644
--- a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternJasmine.java
+++ b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestExternJasmine.java
@@ -41,7 +41,7 @@
"jasmine",
"jasmine.Clock"};
- assertEquals(9, model.getClasses().size());
+ assertEquals(10, model.getClasses().size());
for (String className : classes)
{
assertTrue(model.hasClass(className));
diff --git a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestTypeTypedefs.java b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestTypeTypedefs.java
index b94ff5d..a631106 100644
--- a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestTypeTypedefs.java
+++ b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TestTypeTypedefs.java
@@ -82,7 +82,7 @@
JSTypeUtils.toParamTypeString(reference.getStaticMethod("test4"), "arg1"));
assertEquals("Object",
JSTypeUtils.toParamTypeString(reference.getStaticMethod("test5"), "arg1"));
- assertEquals("Function /* function (string, boolean): ? */",
+ assertEquals("Function /* function(string, boolean): ? */",
JSTypeUtils.toParamTypeString(reference.getStaticMethod("test6"), "arg1"));
}
diff --git a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TypedefsTestUtils.java b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TypedefsTestUtils.java
index 87daab5..0378c14 100644
--- a/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TypedefsTestUtils.java
+++ b/compiler-externc/src/test/java/org/apache/royale/compiler/internal/codegen/typedefs/TypedefsTestUtils.java
@@ -174,7 +174,6 @@
config.addTypedef(coreRoot + "/browser/whatwg_encoding.js");
- config.addTypedef(coreRoot + "/browser/chrome.js");
//config.addTypedef(coreRoot + "/browser/fetchapi.js");
config.addTypedef(coreRoot + "/browser/fileapi.js");
config.addTypedef(coreRoot + "/browser/flash.js");
diff --git a/compiler-externc/src/test/resources/typedefs/unit_tests/missing.js b/compiler-externc/src/test/resources/typedefs/unit_tests/missing.js
index 689f185..d868582 100644
--- a/compiler-externc/src/test/resources/typedefs/unit_tests/missing.js
+++ b/compiler-externc/src/test/resources/typedefs/unit_tests/missing.js
@@ -311,3 +311,34 @@
* @type {number}
*/
Date.prototype.timezoneOffset;
+
+/**
+ * @param {string} type
+ * @param {EventListener|function(!Event):*} listener
+ * @param {(boolean|!AddEventListenerOptions)=} opt_options
+ * @return {undefined}
+ * @see https://dom.spec.whatwg.org/#dom-eventtarget-addeventlistener
+ */
+BaseAudioContext.prototype.addEventListener = function(type, listener, opt_options) {
+};
+
+/**
+ * @param {string} type
+ * @param {EventListener|function(!Event):*} listener
+ * @param {(boolean|!EventListenerOptions)=} opt_options
+ * @return {undefined}
+ * @see https://dom.spec.whatwg.org/#dom-eventtarget-removeeventlistener
+ */
+BaseAudioContext.prototype.removeEventListener = function(
+ type, listener, opt_options) {};
+
+/**
+ * @param {!Event} evt
+ * @return {boolean}
+ * @see https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+BaseAudioContext.prototype.dispatchEvent = function(evt) {};
+
+
+
+
diff --git a/compiler-jburg-types/build.xml b/compiler-jburg-types/build.xml
index 9076f9b..2855b94 100644
--- a/compiler-jburg-types/build.xml
+++ b/compiler-jburg-types/build.xml
@@ -66,8 +66,10 @@
<compilerarg value="-Xlint:all,-path,-fallthrough"/>
<src path="${compiler-jburg-types}/src/main/java"/>
<include name="org/apache/royale/compiler/internal/as/codegen/IASNodeAdapter.java"/>
+ <include name="jburg/burg/JBurgGenerator.java"/>
<classpath>
<pathelement location="${compiler-jburg-types}/../compiler/lib/external/jburg.jar"/>
+ <pathelement location="${compiler-jburg-types}/../compiler/lib/external/antlr.jar"/>
</classpath>
</javac>
</target>
diff --git a/compiler-jburg-types/pom.xml b/compiler-jburg-types/pom.xml
index 885e49f..603b9f7 100644
--- a/compiler-jburg-types/pom.xml
+++ b/compiler-jburg-types/pom.xml
@@ -30,17 +30,97 @@
<groupId>org.apache.royale.compiler</groupId>
<artifactId>compiler-jburg-types</artifactId>
- <version>1.0.0</version>
+ <version>1.1.0</version>
<name>Apache Royale: JBurg Types</name>
<description>Types needed by JBurg to perform it's code generation.</description>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ </plugin>
+ </plugins>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>strip-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ <configuration>
+ <tags>
+ <tag>
+ <name>goal</name>
+ <placement>a</placement>
+ <head>Goal:</head>
+ </tag>
+ <tag>
+ <name>phase</name>
+ <placement>a</placement>
+ <head>Phase:</head>
+ </tag>
+ <tag>
+ <name>threadSafe</name>
+ <placement>a</placement>
+ <head>Thread Safe:</head>
+ </tag>
+ <tag>
+ <name>requiresDependencyResolution</name>
+ <placement>a</placement>
+ <head>Requires Dependency Resolution:</head>
+ </tag>
+ <tag>
+ <name>requiresProject</name>
+ <placement>a</placement>
+ <head>Requires Project:</head>
+ </tag>
+ <tag>
+ <name>note</name>
+ <placement>a</placement>
+ <head>note:</head>
+ </tag>
+ <tag>
+ <name>pre</name>
+ <placement>X</placement>
+ <head></head>
+ </tag>
+ </tags>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
<dependencies>
<dependency>
<groupId>net.sourceforge.jburg</groupId>
<artifactId>jburg</artifactId>
<version>1.10.3</version>
</dependency>
+ <dependency>
+ <groupId>antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>2.7.7</version>
+ </dependency>
</dependencies>
</project>
diff --git a/compiler-jburg-types/src/main/java/jburg/burg/JBurgGenerator.java b/compiler-jburg-types/src/main/java/jburg/burg/JBurgGenerator.java
new file mode 100644
index 0000000..a20c056
--- /dev/null
+++ b/compiler-jburg-types/src/main/java/jburg/burg/JBurgGenerator.java
@@ -0,0 +1,3763 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package jburg.burg;
+
+// BURM specification is parsed into ANTLR2 AST objects.
+import antlr.collections.AST;
+
+// The code emitter interface definition.
+import jburg.burg.emitlangs.EmitLang;
+
+// The factory that selects and creates an emitter.
+import jburg.burg.emitlangs.JBurgEmitterFactory;
+
+// The i-node adapter interface definition.
+import jburg.burg.inode.InodeAdapter;
+import jburg.burg.inode.InodeAdapter2;
+// Interface for i-node adapters that need
+// to emit support routines.
+import jburg.burg.inode.InodeAuxiliarySupport;
+
+// The factory that selects and creates an I-node adapter.
+import jburg.burg.inode.InodeAdapterFactory;
+
+// Token types from ANTLR.
+import jburg.parser.JBurgTokenTypes;
+
+// Version file, generated by build.
+import jburg.generator.version.JBurgVersion;
+
+
+import java.io.PrintStream;
+
+import java.lang.reflect.Modifier;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.Vector;
+
+
+@SuppressWarnings("nls")
+public class JBurgGenerator implements JBurgTokenTypes
+{
+ /**
+ * The JBurg specification's rules are categorized as:
+ * <ul>
+ * <li> Pattern (e.g., integer = PLUS(integer, integer) )
+ * <li> Simple Transformational (e.g., registerOperand = integer)
+ * <li> Complex Transformational (e.g., string = integer { code to convert integer to string} )
+ * </ul>
+ *
+ * Simple transformational rules allow a subgoal to satisfy
+ * other subgoals without additional processing; complex
+ * transformational rules allow one subgoal to feed additional
+ * processing that can satisfy other subgoals (at added cost).
+ *
+ * Syntactically, a simple transformational rule is distinguished
+ * by its lack of a block of code.
+ * Simple transformational rules are also known as "chain rules"
+ * in simpler BURGs that don't support complex transformational
+ * rules. This longer name was adopted to highlight that difference,
+ * but a simple transformational rule is, in fact, a chain rule
+ * by a different name.
+ */
+
+ /**
+ * The table of all transformation rules; keyed
+ * by the rules' necessary state, e.g., integer
+ * in the rule number = integer).
+ */
+ Map<String, Vector<JBurgRule>> transformationRules = new HashMap<String, Vector<JBurgRule>>();
+
+ /**
+ * The table of all pattern rules, keyed
+ * by the top-level operator of the pattern,
+ * e.g., PLUS in the pattern integer = PLUS(integer, integer).
+ */
+ Map<String, Vector<JBurgRule>> patternRules = new HashMap<String, Vector<JBurgRule>>();
+
+ /**
+ * The goal states' names become symbolic constants
+ * in the generated reducer.
+ */
+ Set<String> allGoalStates = new HashSet<String>();
+
+ /**
+ * Closure sets are organized by their goal state; each state's
+ * closure set contains an entry for every closure
+ * path from any other non-terminal state to the target state.
+ */
+ Map<String, Vector<ClosureRecord>> closureSets = new HashMap<String, Vector<ClosureRecord>>();
+
+ /** Action code fragments. */
+ ArrayList<JBurgReduceAction> reduceActions = new ArrayList<JBurgReduceAction>();
+
+ /**
+ * Cost function fragments.
+ * Note that cost functions may also be embedded
+ * in the inline code blocks in a specification.
+ */
+ ArrayList<AST> costFunctions = new ArrayList<AST>();
+
+ /** The names of any interfaces that the generated BURM implements. */
+ Vector<String> interfaceNames = new Vector<String>();
+
+ /** blocks of code to be added into the class verbatim */
+ Vector<String> inclassCode = new Vector<String>();
+
+ /**
+ * Rules that can generate compressed annotations.
+ */
+ RulesByOperatorAndArity compressedAnnotations = new RulesByOperatorAndArity();
+
+ /** The package name of the generated reducer. */
+ String packageName = null;
+
+ /** Header code, copied as-is into the reducer. */
+ String headerBlock = null;
+
+ /**
+ * The name of the i-node class that's being labeled and reduced.
+ */
+ String iNodeClass = null;
+
+ /**
+ * I-node adapter class name. The adapter is instantiated by name.
+ * @note: specified as an alternative to the I-node class' name,
+ * which selects a builtin adapter.
+ */
+ String iNodeAdapterClass;
+
+ /**
+ * The return types for specific states.
+ */
+ Map<String, String> returnTypeTable = new HashMap<String, String>();
+
+ /**
+ * The default return type of the reducer functions.
+ * If this is defaulted to null, the generated reducer will return nodes of the iNodeClass.
+ */
+ String defaultReturnType = null;
+
+ /**
+ * Table of properties to be added to the BURM.
+ * Each one is a name/type pair; the BURM gets
+ * a private member and get/set methods.
+ */
+ Map<String, String> burmProperties = new HashMap<String, String>();
+
+ /**
+ * Simple transformations simply delegate to their antecedent reduction,
+ * so all transformations to a given nonterminal state can share the
+ * same rule.
+ */
+ Map<String, JBurgRule> simpleTransformationRules = new HashMap<String,JBurgRule>();
+
+ /** Include debugging code in the generated reducer? */
+ boolean debugMode;
+
+ /**
+ * If the pattern-matcher generator fails, dump its annotation tree here.
+ * Note: this is only enabled (or useful) when debugging JBurg's own BURM.
+ */
+ String patternMatcherDumpFile = null;
+
+ /**
+ * Caller's logging interface. If defaulted to null, informational and
+ * error messages go to System.out and System.err respectively.
+ */
+ Logger logger = null;
+
+ /**
+ * Name for the language to emit code in (default is assumed to be java (=emitlang.EmitJava)
+ */
+ String emitLanguageName = null;
+
+ /** Code emitter to use (selected using the language name) */
+ EmitLang codeEmitter = null;
+
+ /** I-node adapter to use */
+ InodeAdapter iNodeAdapter;
+
+ /**
+ * If the InodeAdapter is also an InodeAdapter2,
+ * keep a reference to it.
+ */
+ InodeAdapter2 adapter2;
+
+ /** Cumulative error count. */
+ int errCount = 0;
+
+ /** Name of the initial parameter to the label routine. */
+ private static String initalParamName = "to_be_labelled";
+
+ /** Name of the node in the reducer */
+ private String reducerNodeName = "__p";
+
+ /** Name of the stack of reduced values */
+ private String reducedValuesName = "__reducedValues";
+
+ /** Default error handler. null means use hard-coded default, i.e., throw an exception. */
+ String defaultErrorHandler = null;
+
+ /** Prologue snippets mapped to the corresponding rule number. */
+ Map<Integer,String> prologueBlocks = new TreeMap<Integer,String>();
+
+ /**
+ * All operators known to any pattern accumulate in this set
+ * so that the BURG can generate operator-specific getNthChild()
+ * routines.
+ */
+ Set<String> allOperators = new TreeSet<String>();
+
+ /**
+ * operator mapped to node type. This map is populated by JBurg.NodeType
+ * directives.
+ * <p>
+ * For example, an operator named IdentifierID would be associated with
+ * {@code IIdentifierNode*} in this map if the input contained
+ * {@code JBurg.NodeType IdentifierID = IIdentifierNode*;
+ */
+ final Map<String, String> opcodeNodeTypes = new HashMap<String, String>();
+
+ /**
+ * The type of the INodes' opcode. Defaults to int but
+ * can be an enum for maintainability.
+ */
+ String opcodeType = "int";
+
+ /**
+ * Manifest constants in the JBurg specification.
+ */
+ Map<String,Integer> manifestConstants = new HashMap<String,Integer>();
+
+ /**
+ * Patterns that have been optimized out are represented
+ * by this not-likely-to-compile sequence.
+ */
+ final private static String nilPattern = "-null-";
+
+ /**
+ * Manifest constant for method declarations.
+ */
+ final private static Class<?>[] throwsNothing = null;
+
+ /**
+ * Manifest constant for method declarations.
+ */
+ final private static Class<?>[] throwsException = new Class<?>[] { Exception.class };
+
+
+ /**
+ * Manifest constant for method declarations.
+ */
+ final private static String[][] noFormalParameters = new String[][] { };
+
+ /**
+ * Manifest constant for method calls.
+ */
+ final private static String[] noActualParameters = { };
+
+ /**
+ * Manifest constant for an unfeasible rule.
+ */
+ final private static String NO_FEASIBLE_RULE = "-1";
+
+ /**
+ * Manifest constant for an uninitialized cost.
+ */
+ final private static String UNINITIALIZED = "-1";
+
+ /**
+ * NamedPattern holds a named pattern, and keeps a table of the reductions that refer to it.
+ * (See defect 3063143 for problems with multiple reductions sharing a pattern.)
+ */
+ class NamedPattern
+ {
+ String patternName;
+ AST pattern = null;
+ Vector<AST> reductions = new Vector<AST>();
+
+ NamedPattern(String name)
+ {
+ this.patternName = name;
+ }
+ }
+
+ /**
+ * A PatternMap keeps the map of pattern names to reductions.
+ */
+ @SuppressWarnings("serial")
+ class PatternMap extends TreeMap<String,NamedPattern>
+ {
+ NamedPattern getPattern(String key)
+ {
+ if ( !super.containsKey(key) )
+ put(key, new NamedPattern(key));
+ return super.get(key);
+ }
+
+ void addPattern(String key, AST pattern)
+ {
+ NamedPattern p = getPattern(key);
+ p.pattern = pattern;
+ }
+
+ void addReduction(String key, AST reduction)
+ {
+ NamedPattern p = getPattern(key);
+ p.reductions.add(reduction);
+ }
+ }
+
+ PatternMap namedPatterns = new PatternMap();
+
+ /**
+ * Aggregate path computations if more than this threshold
+ * number of pattern elements share a path.
+ */
+ private int aggregatePathThreshold = Integer.MAX_VALUE;
+
+ public void setAggregatePathThreshold(int threshold)
+ {
+ this.aggregatePathThreshold = threshold;
+ }
+
+ /**
+ * @param root - the root of the AST generated by parsing the .jburg specification.
+ */
+ public JBurgGenerator(AST root, Logger log) throws Exception
+ {
+ this.logger = log;
+
+ // Walk over the children of the root, each of which
+ // is a self-contained syntactical construct, and
+ // find an appropriate action for each.
+ for (AST currentNode = root; currentNode != null;
+ currentNode = currentNode.getNextSibling())
+ {
+ switch (currentNode.getType())
+ {
+ case COST_FUNCTION:
+ this.costFunctions.add(currentNode);
+ break;
+
+ case HEADER_DECLARATION:
+
+ if ( null == this.headerBlock )
+ {
+ this.headerBlock = getCodeBlock(currentNode);
+ }
+ else
+ {
+ throw new IllegalArgumentException("The class header may only be specified once.");
+ }
+
+ break;
+
+ case INCLASS_DECLARATION:
+ {
+ this.inclassCode.add( stripBrackets(getCodeBlock(currentNode)) );
+ }
+
+ break;
+
+ case INODE_ADAPTER_DECLARATION:
+
+ if (this.iNodeAdapterClass == null)
+ {
+ this.iNodeAdapterClass = getIdentifierText(currentNode.getFirstChild());
+ }
+ else
+ {
+ throw new IllegalArgumentException("INodeAdapter may only be specified once.");
+ }
+
+ break;
+
+ case INODE_TYPE_DECLARATION:
+
+ if (this.iNodeClass == null)
+ {
+ this.iNodeClass = getIdentifierText(currentNode.getFirstChild());
+ }
+ else
+ {
+ throw new IllegalArgumentException("INodeType may only be specified once.");
+ }
+
+ break;
+
+ case LANGUAGE_DECLARATION:
+
+ if ( null == this.emitLanguageName )
+ {
+ this.emitLanguageName = currentNode.getFirstChild().getText();
+ }
+ else
+ {
+ throw new IllegalArgumentException("Language may only be specified once.");
+ }
+
+ break;
+
+ case IMPLEMENTS_INTERFACE_SPECIFICATION:
+ this.interfaceNames.addElement(getIdentifierText( currentNode.getFirstChild()) );
+
+ break;
+
+ case PACKAGE_SPECIFICATION:
+ if ( null == this.packageName )
+ {
+ this.packageName = getIdentifierText(currentNode.getFirstChild());
+ }
+ else
+ {
+ throw new IllegalArgumentException("package may only be specified once.");
+ }
+
+ break;
+
+ case PROPERTY_SPECIFICATION:
+ {
+ String propertyType = getIdentifierText(currentNode.getFirstChild());
+ String propertyName = currentNode.getFirstChild().getNextSibling().getText();
+ this.burmProperties.put(propertyName, propertyType);
+ }
+
+ break;
+
+ case RETURN_DECLARATION:
+
+ if (this.defaultReturnType == null)
+ this.defaultReturnType = getIdentifierText(currentNode.getFirstChild());
+ else
+ throw new IllegalArgumentException( "ReturnType may only be specified once.");
+
+ break;
+
+ case PATTERN_RULE:
+ addPatternRule(currentNode);
+
+ break;
+
+ case SIMPLE_TRANSFORMATION_RULE:
+ addSimpleTransformationRule(currentNode);
+
+ break;
+
+ case TRANSFORMATION_RULE:
+ addComplexTransformationRule(currentNode);
+
+ break;
+
+ case TYPED_RETURN_DECLARATION:
+
+ {
+ String stateName = currentNode.getFirstChild().getText();
+ String returnType = getIdentifierText(currentNode.getFirstChild()
+ .getNextSibling());
+
+ // Put the return declaration in the table, but only once per state.
+ Object typeCollision = this.returnTypeTable.put(stateName, returnType);
+ if ( null != typeCollision )
+ {
+ throw new IllegalArgumentException(
+ "A state may only specify one ReturnType."
+ );
+ }
+ }
+
+ break;
+
+ case PATTERN_DECLARATION:
+ {
+ String pattern_name = currentNode.getFirstChild().getText();
+ namedPatterns.addPattern(pattern_name, currentNode);
+ }
+ break;
+
+ case REDUCTION_DECLARATION:
+ {
+ String pattern_name = currentNode.getFirstChild().getNextSibling().getText();
+ namedPatterns.addReduction(pattern_name, currentNode);
+ }
+ break;
+
+ case DEFAULT_ERROR_HANDLER:
+ this.defaultErrorHandler = getCodeBlock(currentNode);
+ break;
+ case NODE_TYPE:
+ {
+ final String operatorID = currentNode.getFirstChild().getText();
+ assert !operatorID.isEmpty() : "Parser should never create empty operator!";
+ final String nodeType = currentNode.getFirstChild().getNextSibling().getText();
+ assert !nodeType.isEmpty() : "Parser should never create empty node type!";
+
+ if (this.opcodeNodeTypes.put(operatorID, nodeType) != null)
+ {
+ final String message = "Duplicate node type declaration for '"
+ + operatorID
+ + "'.";
+ throw new IllegalArgumentException(message);
+ }
+ break;
+ }
+ case OPCODE_TYPE:
+ this.opcodeType = currentNode.getFirstChild().getText();
+ break;
+
+ case MANIFEST_CONSTANT:
+ manifestConstants.put(currentNode.getFirstChild().getText(), Integer.parseInt(currentNode.getFirstChild().getNextSibling().getText()));
+ break;
+
+ default:
+ throw new IllegalArgumentException("Unknown specification AST type " +
+ String.valueOf(currentNode.getType()));
+ }
+ }
+
+ // Set the language emitter.
+ codeEmitter = JBurgEmitterFactory.getEmitter(emitLanguageName, getLogger());
+
+ if ( codeEmitter == null )
+ {
+ throw new IllegalStateException("Unknown language specified: \""+ emitLanguageName +"\"");
+ }
+
+ if ( iNodeClass != null )
+ {
+ if ( iNodeAdapterClass != null )
+ {
+ try
+ {
+ this.iNodeAdapter = (InodeAdapter)Class.forName(iNodeAdapterClass).newInstance();
+ }
+ catch ( Exception ex )
+ {
+ ex.printStackTrace();
+ throw new IllegalArgumentException ("Unable to instantiate i-node adapter " + iNodeAdapterClass );
+ }
+ }
+ else
+ {
+ this.iNodeAdapter = InodeAdapterFactory.getAdapter(iNodeClass);
+ }
+
+ codeEmitter.setINodeType(this.iNodeClass);
+
+ if ( this.iNodeAdapter != null )
+ {
+ logger.info("Using i-node adapter " + this.iNodeAdapter.getClass().getName() );
+ }
+ else
+ {
+ getLogger().warning("using default i-node adapter, no adapter matches " + iNodeClass );
+ this.iNodeAdapter = new jburg.burg.inode.DefaultAdapter();
+ }
+
+ // See if the adapter is also an InodeAdapter2 implementation.
+ this.adapter2 = (this.iNodeAdapter instanceof InodeAdapter2)? (InodeAdapter2)this.iNodeAdapter : null;
+ }
+ else
+ {
+ throw new IllegalStateException("You must specify the i-node type.");
+ }
+
+ codeEmitter.setInodeAdapter(this.iNodeAdapter);
+
+ // Default return type is the same as the INode class.
+ if (this.defaultReturnType == null)
+ {
+ this.defaultReturnType = this.iNodeClass;
+ }
+
+ // Mutate pattern/reduction decl pairs into pattern rules.
+ for ( NamedPattern np: namedPatterns.values() )
+ {
+ if ( np.pattern != null && np.reductions.size() > 0 )
+ {
+ AST named_pattern = np.pattern.getFirstChild().getNextSibling().getFirstChild();
+
+ for ( AST reduction: np.reductions )
+ {
+ // Splice the pattern into the reduction AST.
+
+ AST nt_state = reduction.getFirstChild();
+ AST pattern_name = nt_state.getNextSibling();
+ AST cost_decl = pattern_name.getNextSibling();
+
+ // Create a new holder for the pattern
+ // so the original AST isn't mutated.
+ AST pattern_holder = new antlr.CommonAST();
+ pattern_holder.setFirstChild(named_pattern);
+ nt_state.setNextSibling(pattern_holder);
+ pattern_holder.setNextSibling(cost_decl);
+
+ // Give the composite AST the appropriate type
+ // for its pattern.
+ reduction.setType(PATTERN_RULE);
+
+ addPatternRule(reduction);
+ }
+ }
+ else if ( np.pattern != null )
+ {
+ getLogger().warning("pattern " + np.patternName + " has no reduction - ignored.");
+ }
+ else if ( np.reductions.size() > 0 )
+ {
+ throw new IllegalStateException("Reduction " + np.patternName + " has no associated pattern.");
+ }
+ }
+
+ // Add target-specific logic to the simple transformations' rules.
+ for ( JBurgRule rule: this.simpleTransformationRules.values() )
+ {
+ String actionCode = String.format(
+ "%s%s",
+ codeEmitter.genReturnValue(
+ codeEmitter.genPopFromStack(reducedValuesName, getReturnType(rule.getGoalState()))
+ ),
+ codeEmitter.genEndStmt()
+ );
+
+ JBurgReduceAction action = addAction(actionCode, rule.getGoalState());
+ action.setAntecedentState(rule.getAntecedentState());
+ rule.setReduceAction(action);
+ }
+
+ // Compute the closure sets.
+ computeClosureSets();
+ }
+
+ /**
+ * Add a reduce action to the action list.
+ * Actions are keyed by number in the generated BURM.
+ */
+ private JBurgReduceAction addAction(String strAction, String strState)
+ {
+ JBurgReduceAction newAction = new JBurgReduceAction(strAction);
+ this.reduceActions.add(newAction);
+
+ // The first index is used as the default action for
+ // simple transformation rules.
+ newAction.setIndex(this.reduceActions.size());
+ newAction.setState(strState);
+
+ return newAction;
+ }
+
+ /**
+ * Sort through a rule's action routine specifications and assemble
+ * a JBurgReduceAction from them.
+ * @param parent - the rule's AST.
+ * @param goal_state - the state the rule produces.
+ *
+ */
+ private JBurgReduceAction decodeReduction(AST parent, String goal_state)
+ {
+ JBurgReduceAction action = null;
+ AST reduction = null;
+
+ if ( hasASTOfType(parent, REDUCTION_ACTION) )
+ {
+ reduction = getASTByType(parent, REDUCTION_ACTION);
+ action = addAction(getCodeBlock(reduction), goal_state);
+ }
+ else if ( hasASTOfType(parent, EXPLICIT_REDUCTION ) )
+ {
+ reduction = getASTByType(parent, EXPLICIT_REDUCTION);
+ action = addAction( "return " + decodeProcedureCall(reduction) + ";", goal_state );
+ }
+ else
+ {
+ throw new IllegalStateException("A reduction must specify an implementation block or callback function");
+ }
+
+ if ( hasASTOfType(reduction, PROLOGUE) )
+ {
+ AST prologue = getASTByType(reduction, PROLOGUE);
+ String prologue_action = null;
+
+ if ( hasASTOfType(prologue, BLOCK) )
+ {
+ prologue_action = getCodeBlock(prologue);
+ }
+ else if ( hasASTOfType(prologue, PROCEDURE_CALL) )
+ {
+ prologue_action = "\t" + decodeProcedureCall(prologue) + ";";
+ }
+ else
+ {
+ throw new IllegalStateException("Prologue block with no inline code or callback");
+ }
+
+ this.prologueBlocks.put(action.index, prologue_action);
+ }
+
+ return action;
+ }
+
+ private String decodeProcedureCall(AST parent)
+ {
+ AST procall = getASTByType(parent, PROCEDURE_CALL);
+
+ StringBuilder buffer = new StringBuilder();
+
+ AST id = procall.getFirstChild();
+ buffer.append(id.getText());
+ buffer.append("(");
+
+ AST param = id.getNextSibling();
+ if ( param != null )
+ {
+ buffer.append(param.getText());
+
+ for ( param = param.getNextSibling(); param != null; param = param.getNextSibling() )
+ {
+ buffer.append(",");
+ buffer.append(param.getText());
+ }
+ }
+ buffer.append(")");
+
+ return buffer.toString();
+ }
+
+ /**
+ * Add a complex transformation rule to its table,
+ * and record the rule's reduction action.
+ */
+ private void addComplexTransformationRule(AST transform)
+ throws Exception
+ {
+ JBurgRule n = addNamedRule(this.transformationRules, transform);
+
+ // Prepare the rule's reduce action.
+ JBurgReduceAction action = decodeReduction(transform, n.getGoalState());
+ action.setAntecedentState(n.getAntecedentState());
+
+ // Add the antecedent state by name as an alias action routine "parameter."
+ // The "parameter" is popped off the reduced values stack into a local variable.
+ action.addParameter(
+ n.getAntecedentState(),
+ n.getAntecedentState(),
+ ParameterDescriptor.ArityType.Fixed
+ );
+
+ n.setReduceAction(action);
+ }
+
+ /**
+ * If this simple transformation is not yet known, add it to its rule table.
+ */
+ private void addSimpleTransformationRule(AST transform)
+ {
+ JBurgRule newRule = new JBurgRule(transform);
+
+ String key = String.format("%s=%s", newRule.getGoalState(), newRule.getAntecedentState());
+
+ if ( ! this.simpleTransformationRules.containsKey(key) )
+ {
+ // Ensure this rule's nonterminal is known.
+ this.allGoalStates.add(newRule.getGoalState());
+ addNamedRule(this.transformationRules, newRule);
+
+ // Target-specific action logic will be
+ // added once the code emitter is up.
+ this.simpleTransformationRules.put(key, newRule);
+ }
+ }
+
+ /**
+ * Wrap a pattern rule in an I-node, and add it to pattern rule table.
+ */
+ private void addPatternRule(AST newRule) throws Exception
+ {
+ JBurgRule n = addNamedRule(this.patternRules, newRule);
+
+ JBurgReduceAction newAction = decodeReduction(newRule, n.getGoalState());
+
+ n.setReduceAction(newAction);
+ }
+
+ /**
+ * Wrap a rule in an I-node, and add it to the list of rules
+ * that produce a particular subgoal.
+ */
+ private JBurgRule addNamedRule(Map<String, Vector<JBurgRule>> ruleTable, AST newAST)
+ {
+ JBurgRule newRule = new JBurgRule(newAST);
+
+ // Ensure this rule's nonterminal is known.
+ this.allGoalStates.add( newRule.getGoalState() );
+ return addNamedRule(ruleTable, newRule);
+ }
+
+ /**
+ * Add a rule to its rule table.
+ * @param ruleTable - the appropriate table for this type of rule. Keyed by operator.
+ * @param newRule - the rule to add.
+ */
+ private JBurgRule addNamedRule(Map<String, Vector<JBurgRule>> ruleTable, JBurgRule newRule)
+ {
+ // Store the rule by operator.
+ String operator = newRule.getOperator();
+
+ Vector<JBurgRule> vRules = ruleTable.get(operator);
+
+ if (vRules == null)
+ {
+ vRules = new Vector<JBurgRule>();
+ ruleTable.put(operator, vRules);
+ }
+
+ vRules.add(newRule);
+
+ return newRule;
+ }
+
+ /**
+ * Compute the closure set of a rule: the set of rules that
+ * that can transform this rule's goal to satsify another goal.
+ * @note computeClosure is public so that it can be applied
+ * by JBurgUtilities.
+ */
+ public void computeClosure(JBurgRule n) throws Exception
+ {
+ // Get the list of transformation rules that can use this rule's goal state.
+ Vector<JBurgRule> vClosureCandidate = this.transformationRules.get(n.getGoalState());
+
+ if (vClosureCandidate != null)
+ {
+ // Found some closures:
+ // create or fetch this target state's closure set.
+ Vector<ClosureRecord> vClosureSet = this.closureSets.get(n.getGoalState());
+
+ if (vClosureSet == null)
+ {
+ vClosureSet = new Vector<ClosureRecord>();
+ this.closureSets.put(n.getGoalState(), vClosureSet);
+ }
+
+ for (JBurgRule nPrime:vClosureCandidate )
+ {
+
+ // Add this closure to the closure set.
+ ClosureRecord newClosure = new ClosureRecord(nPrime);
+
+ if (!vClosureSet.contains(newClosure))
+ {
+ vClosureSet.add(newClosure);
+ }
+ }
+ }
+ }
+
+ /**
+ * Scan all the rules and compute their closure sets.
+ */
+ private void computeClosureSets() throws Exception
+ {
+ for (Vector<JBurgRule> patterns : this.patternRules.values() )
+ {
+ try
+ {
+ JBurgUtilities.applyToAll( this, patterns, "computeClosure", JBurgRule.class);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ for (Vector<JBurgRule> transformations : this.transformationRules.values() )
+ {
+ try
+ {
+ JBurgUtilities.applyToAll( this, transformations, "computeClosure", JBurgRule.class);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Emit the BURG specification's resultant BURM to an output stream.
+ */
+ public int generate(String className, PrintStream output)
+ {
+ try
+ {
+ codeEmitter.setOpcodeType(this.opcodeType);
+ emitHeader(className, output);
+ codeEmitter.emitInclass(iNodeClass, this.inclassCode, output);
+
+ emitNTConstants(this.allGoalStates, output);
+ emitStatics(output);
+
+ if ( this.iNodeAdapter instanceof InodeAuxiliarySupport )
+ {
+ ((InodeAuxiliarySupport)this.iNodeAdapter).emitAuxiliarySupport(codeEmitter, output);
+ }
+
+ emitLabelFunction(this.iNodeClass, output);
+ ruleSemanticAnalysis();
+
+ if ( codeEmitter.supportsSpecializedAnnotations() )
+ {
+ for (Vector<JBurgRule> vPatternRules: this.patternRules.values())
+ this.compressedAnnotations.addAll(vPatternRules);
+ }
+ else
+ {
+ emitComputeCostMatrixFunction(this.iNodeClass, output);
+ emitClosures(this.closureSets, this.iNodeClass, output);
+ }
+ emitActions(this.reduceActions, this.iNodeClass, output);
+ emitCostFunctions(this.costFunctions, this.iNodeClass, output);
+
+ if ( codeEmitter.supportsSpecializedAnnotations() )
+ emitCompressedAnnotations(output);
+
+ // If there's an InodeAdapter2 present,
+ // emit the getNthChild routine that
+ // implements the adapter's node-handling logic.
+ if ( this.adapter2 != null)
+ emitGetNthChild(output);
+
+ codeEmitter.emitTrailer(
+ className,
+ this.iNodeClass,
+ this.allGoalStates,
+ this.burmProperties,
+ this.debugMode,
+ this.defaultErrorHandler,
+ this.prologueBlocks,
+ output
+ );
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ this.errCount++;
+ }
+
+ return this.errCount;
+ }
+
+ // Emit static lookup tables.
+ private void emitStatics(PrintStream output)
+ {
+ // Emit the static table of subgoal records.
+ Map<Integer, Vector<JBurgPatternMatcher>> rules_by_action = new HashMap<Integer,Vector<JBurgPatternMatcher>>();
+ int max_action = 0;
+ for (Vector<JBurgRule> vPatternRules: patternRules.values())
+ {
+ for (JBurgRule p: vPatternRules)
+ {
+ int action_number = p.getReduceAction().getIndex();
+ max_action = Math.max(max_action, action_number);
+
+ if ( p.patternMatcher.isNary() )
+ {
+ rules_by_action.put(action_number,new Vector<JBurgPatternMatcher>());
+ rules_by_action.get(action_number).add(p.patternMatcher);
+ }
+ else if (!p.patternMatcher.getParameterizedSubtrees().isEmpty() )
+
+ {
+ rules_by_action.put(action_number,p.patternMatcher.getParameterizedSubtrees());
+ }
+ }
+ }
+
+ // Ensure the transformation rules' actions have subgoal records.
+ for ( Vector<JBurgRule> transformations: this.transformationRules.values() )
+ for ( JBurgRule t: transformations )
+ max_action = Math.max(max_action, t.getReduceAction().getIndex());
+
+ codeEmitter.emitStatics(max_action, rules_by_action, output);
+
+ // Generate manifest constant declarations.
+ for ( Map.Entry<String,Integer> constants : this.manifestConstants.entrySet() )
+ genInstanceField(
+ output,
+ Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL,
+ "int",
+ constants.getKey(),
+ constants.getValue().toString()
+ );
+ }
+
+ /**
+ * Get the payload of an identifier, with error checking.
+ * @return the identifier's text.
+ */
+ private String getIdentifierText(AST p)
+ {
+ if ( p.getType() != IDENTIFIER )
+ {
+ throw new IllegalStateException ( "Expected IDENTIFIER, found " + p.toStringTree() );
+ }
+
+ return p.getText();
+ }
+
+ /**
+ * Does this production have a closure set?
+ * @return true if n has a closure set.
+ * @param n - the production of interest.
+ */
+ public boolean hasClosure(JBurgProduction n)
+ {
+ return this.closureSets.get(n.getGoalState()) != null;
+ }
+
+ /**
+ * Emit the file/class header information.
+ */
+ private void emitHeader(String className, PrintStream output)
+ {
+ genComment(output, " Generated " + new java.util.Date().toString() + " by JBurg version " + JBurgVersion.version );
+ output.println();
+
+ codeEmitter.emitHeader(className, this.packageName, this.headerBlock, this.interfaceNames, this.debugMode, output);
+ }
+
+ /**
+ * @return the return type for a specific state.
+ */
+ public String getReturnType(String stateName)
+ {
+ Object result = returnTypeTable.get(stateName);
+
+ if (result == null)
+ result = defaultReturnType;
+
+ return result.toString();
+ }
+
+ /**
+ * setDebugMode controls the level of debugging code that will be generated in the reducer.
+ */
+ public void setDebugMode(boolean bDebugMode)
+ {
+ debugMode = bDebugMode;
+ }
+
+ /**
+ * @return the text of the parent AST's code block, which is represented as a BLOCK token.
+ */
+ private String getCodeBlock( AST parent )
+ {
+ return getASTByType(parent, BLOCK).getText();
+ }
+
+ /**
+ * @return the first child of the parent AST with the specified node type.
+ */
+ private AST getASTByType(AST parent, int node_type)
+ {
+ for ( AST current = parent.getFirstChild(); current != null; current = current.getNextSibling() )
+ {
+ if ( current.getType() == node_type )
+ return current;
+ }
+
+ throw new IllegalStateException ( "AST " + parent.toString() + " has no child of node type " + node_type + "." );
+ }
+
+ private boolean hasASTOfType(AST parent, int node_type)
+ {
+ for ( AST current = parent.getFirstChild(); current != null; current = current.getNextSibling() )
+ {
+ if ( current.getType() == node_type )
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * A JBurgProduction is a view of a pattern-matching rule (JBurgRule)
+ * or a nonterminal transformation rule (ClosureRecord) that exposes
+ * characteristics important in their static analysis.
+ */
+ public interface JBurgProduction
+ {
+ /**
+ * @return the nonterminal this production produces.
+ */
+ public String getGoalState();
+
+ /**
+ * @return the code snippet that computes
+ * or retrieves this production's
+ * (potentially) cached code.
+ */
+ public String getCachedCost();
+
+ /**
+ * @return this production's reduce action.
+ */
+ public JBurgReduceAction getReduceAction();
+
+ /**
+ * Is this production's cost constant in the
+ * context where it's to be invoked?
+ * @param productions - the set of productions at the
+ * point where this productions's cost is required.
+ */
+ public boolean computesConstantCost(Multimap<String, JBurgProduction> productions);
+
+ /**
+ * Get the constant cost of a production.
+ * @param productions - the set of productions at the
+ * point where this production's cost is required.
+ * @return the cost, with overflow-safe addition.
+ * @pre computesConstantCost(productions) must be true.
+ */
+ public int getConstantCost(Multimap<String, JBurgProduction> productions);
+ }
+
+ /**
+ * JBurgRule contains an AST that represents a rule,
+ * its associated JBurgReduceAction,
+ * and accessors to the AST's components.
+ */
+ public class JBurgRule implements JBurgProduction
+ {
+ /**
+ * The parsed rule.
+ */
+ AST m_AST;
+
+ /**
+ * If the rule is a pattern rule, its pattern matcher.
+ */
+ JBurgPatternMatcher patternMatcher = null;
+
+ /**
+ * The rule's reduction action.
+ */
+ JBurgReduceAction reduceAction;
+
+ /**
+ * The pattern as a String; precomputed so it can be used as a key
+ * to group labeling choices by common patterns.
+ */
+ private String encodedPattern;
+
+ public JBurgRule(AST n)
+ {
+ m_AST = n;
+
+ if ( m_AST.getType() == PATTERN_RULE )
+ {
+ AST pattern_root = m_AST.getFirstChild().getNextSibling().getFirstChild();
+ try
+ {
+ this.patternMatcher = generateMatcher(pattern_root);
+ }
+ catch ( Exception ex )
+ {
+ logger.exception("Building pattern recognizer for " + m_AST.toStringTree(), ex);
+ }
+ }
+ }
+
+ String getEncodedPattern()
+ {
+ if ( this.encodedPattern == null )
+ {
+ this.encodedPattern =
+ patternMatcher.generatePatternRecognizer(
+ codeEmitter,
+ "node",
+ JBurgGenerator.this.adapter2
+ );
+ }
+
+ if ( this.encodedPattern == null )
+ this.encodedPattern = nilPattern;
+
+ return this.encodedPattern;
+ }
+
+ /**
+ * @param baseNode - the path to the base of the subtree.
+ * @return the subtree's cost specification.
+ */
+ public String getCost(String baseNode)
+ {
+ if ( m_AST.getType() != SIMPLE_TRANSFORMATION_RULE )
+ {
+ AST cost_spec = m_AST.getFirstChild().getNextSibling()
+ .getNextSibling();
+
+ String costText = cost_spec.getFirstChild().getText();
+
+ if ( hasCostFunction() )
+ return genCallMethod(null, costText, baseNode);
+ else
+ return costText;
+ }
+ else
+ {
+ // Simple transformation rules don't cost anything.
+ return "0";
+ }
+ }
+
+ /**
+ * @return true if the rule has a constant cost.
+ */
+ public boolean hasConstantCost()
+ {
+ if ( m_AST.getType() != SIMPLE_TRANSFORMATION_RULE )
+ {
+ AST cost_spec = m_AST.getFirstChild().getNextSibling()
+ .getNextSibling();
+
+ String costText = cost_spec.getFirstChild().getText();
+
+ boolean ownCostConstant =
+ cost_spec.getType() == LITERAL_COST_SPEC ||
+ JBurgGenerator.this.manifestConstants.containsKey(costText);
+
+ return ownCostConstant &&
+ (this.isTerminalPattern() || this.patternMatcher == null);
+ }
+ else
+ {
+ // Simple transformation rules all cost 0.
+ return true;
+ }
+ }
+
+ /**
+ * @return the rule's cost.
+ * @throws IllegalStateException if the cost isn't constant.
+ */
+ public Integer getConstantCost()
+ {
+ if ( m_AST.getType() != SIMPLE_TRANSFORMATION_RULE )
+ {
+ AST cost_spec = m_AST.getFirstChild().getNextSibling()
+ .getNextSibling();
+
+ String costText = cost_spec.getFirstChild().getText();
+
+ if ( cost_spec.getType() == LITERAL_COST_SPEC )
+ {
+ return new Integer(costText);
+ }
+ else if ( JBurgGenerator.this.manifestConstants.containsKey(costText) )
+ {
+ return JBurgGenerator.this.manifestConstants.get(costText);
+ }
+ else
+ {
+ throw new IllegalStateException("non constant cost: " + costText);
+ }
+ }
+ else
+ {
+ // Simple transformation rules don't cost anything.
+ return 0;
+ }
+ }
+
+ /**
+ * @return true if the cost specification is a function call.
+ */
+ public boolean hasCostFunction()
+ {
+ boolean result = false;
+
+ if ( m_AST.getType() != SIMPLE_TRANSFORMATION_RULE )
+ result = m_AST.getFirstChild().getNextSibling().getNextSibling().getType() == FUNCTION_CALL;
+
+ return result;
+ }
+
+ /**
+ * @return the rule's cached cost.
+ */
+ @Override
+ public String getCachedCost()
+ {
+ if ( this.hasCostFunction() )
+ return String.format("cachedCost_%h()", getCost(reducerNodeName));
+ else
+ return getCost(reducerNodeName);
+
+ }
+
+ /**
+ * @return the rule's reduction action.
+ */
+ @Override
+ public JBurgReduceAction getReduceAction()
+ {
+ if ( null == this.reduceAction )
+ {
+ throw new IllegalStateException( "getReduceAction() has no action to return." );
+ }
+
+ return this.reduceAction;
+ }
+
+ /**
+ * @return the antecedent state of a nonterminal-to-nonterminal
+ * reduction, i.e., the state that the subtree must be reduced
+ * to before this reduction can run.
+ */
+ public String getAntecedentState()
+ {
+ if ( m_AST.getType() == SIMPLE_TRANSFORMATION_RULE )
+ {
+ return m_AST.getFirstChild().getNextSibling().getText();
+ }
+ else if ( m_AST.getType() == TRANSFORMATION_RULE )
+ {
+ return m_AST.getFirstChild().getNextSibling().getText();
+ }
+ else
+ throw new IllegalStateException(String.format("no antecedent for %s", m_AST.getType()));
+ }
+
+ /**
+ * @return the node ID of the node at the root of the subtree.
+ */
+ public String getOperator()
+ {
+ int type = m_AST.getType();
+
+ if ( PATTERN_RULE == type )
+ {
+ return m_AST.getFirstChild().getNextSibling().getFirstChild().getFirstChild().getText();
+ }
+ else
+ {
+ // A transformation rule.
+ return m_AST.getFirstChild().getNextSibling().getText();
+ }
+ }
+
+ /**
+ * @return the nonterminal produced by this reduction.
+ */
+ @Override
+ public String getGoalState()
+ {
+ return m_AST.getFirstChild().getText();
+ }
+
+ /**
+ * Set this rule's associated action code.
+ */
+ public void setReduceAction(JBurgReduceAction reduceAction)
+ {
+ this.reduceAction = reduceAction;
+ }
+
+ /**
+ * @return true if this node has no children (a "leaf" node).
+ */
+ public boolean isTerminalPattern()
+ {
+ return this.isFixedArity() && this.patternMatcher.getNominalArity() == 0;
+ }
+
+ /**
+ * @return true if this rule's pattern has a fixed number of "operand" subtrees.
+ */
+ public boolean isFixedArity()
+ {
+ return this.patternMatcher != null && !this.patternMatcher.hasNaryTail();
+ }
+
+ /**
+ * @return true if this rule needs an out-of-line method to check its cost.
+ */
+ public boolean needsCostFunction()
+ {
+ if ( this.isTerminalPattern() )
+ return false;
+ else if ( this.patternMatcher.hasNaryTail() )
+ return this.patternMatcher.getNominalArity() != this.patternMatcher.getMinimumNaryChildCount();
+ else
+ return true;
+ }
+
+ /**
+ * Is this production's cost constant in the
+ * context where it's to be invoked?
+ * @param productions - the set of productions at the
+ * point where this productions's cost is required.
+ */
+ @Override
+ public boolean computesConstantCost(Multimap<String, JBurgProduction> productions)
+ {
+ return hasConstantCost();
+ }
+
+ /**
+ * Get the constant cost of a production.
+ * @param productions - the set of productions at the
+ * point where this production's cost is required.
+ * @return the cost, with overflow-safe addition.
+ * @pre computesConstantCost(productions) must be true.
+ */
+ @Override
+ public int getConstantCost(Multimap<String, JBurgProduction> productions)
+ {
+ return getConstantCost();
+ }
+
+ @Override
+ public String toString()
+ {
+ return m_AST.toStringTree();
+ }
+ }
+
+ /**
+ * JBurgReduceAction holds action code fragments and their associated "parameters."
+ * A rule specifies "parameters" by naming individual subgoal states within a pattern
+ * rule specifiction, for example,
+ * <xmp>integer = PLUS ( integer i1, integer i2 )</xmp>
+ * In this example, i1 and i2 are the action routine's "parameters." Since the action
+ * routines all share a common signature, the parameters are passed via the reducer's
+ * reduced values stack.
+ */
+ private class JBurgReduceAction
+ {
+ /** The routine's source, from the input specification. */
+ private String actionCode;
+
+ /**
+ * The non-terminal state produced by this action, e.g., expression from
+ * <xmp>expression = ADD(expression l, expression r)</xmp>
+ */
+ private String m_state;
+
+ /**
+ * The antecedent reduction of a nonterminal-to-nonterminal rule.
+ */
+ private String antecedentState;
+
+ /**
+ * The operator ID of a pattern rule; used to find content-handling
+ * code from the InodeAdapter2.
+ */
+ private String m_operator;
+
+ /**
+ * Names and types of the routine's parameters.
+ * Types are given as their non-terminal state names; toString()
+ * translates these BURM-centric types into the corresponding
+ * types in the target language using the mapping set up by
+ * the ReturnType directives in the input specification.
+ */
+ private Vector<ParameterDescriptor> m_parameterList = new Vector<ParameterDescriptor>();
+
+ /**
+ * This action routine's index, assigned in entry order.
+ * The action routines are enumerated as action_1(JBurgNode p), action_2(JBurgNode p),
+ * etc. in the generated reducer.
+ */
+ int index;
+
+ /**
+ * Track name-to-subtree mappings to be emitted.
+ */
+ class NamedSubtree
+ {
+ String path;
+ String name;
+
+ NamedSubtree(String path, String name)
+ {
+ this.path = path;
+ this.name = name;
+ }
+ }
+ /**
+ * Saved name-to-subtree mappings.
+ */
+ Vector<NamedSubtree> namedChildNodes = new Vector<NamedSubtree>();
+
+ /**
+ * Construct a reduce action.
+ * @param strActionCode - the action's implementation
+ * code, in a target-specific language
+ */
+ public JBurgReduceAction(String strActionCode)
+ {
+ this.actionCode = strActionCode;
+ }
+
+ /**
+ * Add a parameter to the action's parameter list.
+ */
+ public void addParameter(String parmName, String parmState, ParameterDescriptor.ArityType arityType)
+ throws Exception
+ {
+ m_parameterList.add(new ParameterDescriptor(parmName, parmState, arityType));
+ }
+
+ /**
+ * Return this action's index (the N constituent of its generated name, action_N).
+ */
+ public int getIndex()
+ {
+ return this.index;
+ }
+
+ /**
+ * Set this action's index (the N constituent of its generated name, action_N).
+ */
+ public void setIndex(int index)
+ {
+ this.index = index;
+ }
+
+ /**
+ * Set the non-terminal state this reduction derives.
+ * @param state - the non-terminal state, e.g., expression from
+ * <xmp>expression = ADD(expression l, expression r)</xmp>
+ */
+ public void setState(String state)
+ {
+ this.m_state = state;
+ }
+
+ /**
+ * @return the non-terminal state this reduction derives.
+ */
+ public String getState()
+ {
+ return this.m_state;
+ }
+
+ /**
+ * @param operator the operator at the root of
+ * the matched subtree.
+ */
+ public void setOperator(String operator)
+ {
+ this.m_operator = operator;
+ }
+
+ /**
+ * @return the operator at the root of
+ * the matched subtree.
+ */
+ public String getOperator()
+ {
+ return m_operator;
+ }
+
+ /**
+ * Return the reduction action's code,
+ * with prepended logic to pop its parameters off the stack.
+ */
+ @Override
+ public String toString()
+ {
+ String result = "";
+
+ for ( ParameterDescriptor next_param: m_parameterList )
+ {
+ String paramName = next_param.paramName;
+ String paramType = getReturnType(next_param.paramState);
+
+ if ( next_param.arityType == ParameterDescriptor.ArityType.Variable )
+ {
+ paramType = codeEmitter.genNaryContainerType(paramType);
+ }
+
+ result += codeEmitter.genActionRoutineParameter(reducedValuesName, paramType, paramName);
+ }
+
+ for ( NamedSubtree named_child: this.namedChildNodes )
+ {
+ result += "\n\t" + iNodeClass + " " + named_child.name + " = " + named_child.path + ";";
+ }
+
+ // insert 2 tabs into each line, and convert \r\n to \n so the generated
+ // files have consistent line endings.
+ String[] actionlines = this.actionCode.toString().split("\n");
+ for( int l = 0; l < actionlines.length; ++l )
+ {
+ if(actionlines[l].endsWith("\r"))
+ {
+ actionlines[l] = actionlines[l].substring(0,actionlines[l].length()-1);
+ }
+ result += "\n\t\t" + actionlines[l];
+ }
+
+ return result;
+ }
+
+ /**
+ * Track a name-to-subtree mapping. These are unreduced I-nodes,
+ * typically a terminal identified by pattern match.
+ * @param path - the path from the root node to the subtree.
+ * @param name - the name to give to the subtree.
+ */
+ public void addNamedSubtree(String path, String name)
+ {
+ namedChildNodes.add(new NamedSubtree(path, name));
+ }
+
+ /**
+ * Set this reduction's antecedent state, which
+ * determines what reduction needs to run before
+ * this one to transform one nonterminal to another.
+ */
+ public void setAntecedentState(String antecedentState)
+ {
+ this.antecedentState = antecedentState;
+ }
+
+ /**
+ * @return true if this rule has an antecedent state,
+ * which also means it's a nonterminal-to-nonterminal rule.
+ */
+ public boolean hasAntecedentState()
+ {
+ return getAntecedentState() != null;
+ }
+
+ /**
+ * @return this rule's antecedent state,
+ * or null if no antecedent is present.
+ */
+ public String getAntecedentState()
+ {
+ return this.antecedentState;
+ }
+ }
+
+ /**
+ * ClosureRecord tracks the target state, cost, and action code associated
+ * with a reduction from an antecedent nonterminal to a target nonterminal state.
+ */
+ private class ClosureRecord implements JBurgProduction
+ {
+ private JBurgRule rule;
+
+ public ClosureRecord(JBurgRule rule) throws Exception
+ {
+ this.rule = rule;
+ }
+
+ /**
+ * Get the closure's uncached cost.
+ * @deprecated Will be removed when rules start caching costs.
+ */
+ public String getCost(String baseNT)
+ {
+ return this.rule.getCost(baseNT);
+ }
+
+ /**
+ * Get the closure's (potentially) cached cost.
+ */
+ @Override
+ public String getCachedCost()
+ {
+ String cost = this.rule.getCost(reducerNodeName);
+
+ // The cost function result will be cached;
+ // return a unique accessor method name.
+ if ( hasCostFunction() )
+ return genCallMethod(null, String.format("getCostFunctionResult_%h", cost));
+ else
+ return cost;
+ }
+
+ /**
+ * @return the rule's hasCostFunction() result.
+ */
+ public boolean hasCostFunction()
+ {
+ return rule.hasCostFunction();
+ }
+
+ /**
+ * @return the rule's getConstantCost() result.
+ */
+ public int getConstantCost()
+ {
+ return this.rule.getConstantCost();
+ }
+
+ /**
+ * @return the rule's hasConstantCost() result.
+ */
+ public boolean hasConstantCost()
+ {
+ return this.rule.hasConstantCost();
+ }
+
+ /**
+ * @return the rule's getAntecedentState() result.
+ */
+ public String getAntecedentState()
+ {
+ return this.rule.getAntecedentState();
+ }
+
+ /**
+ * @return the rule's getGoalState() result.
+ */
+ @Override
+ public String getGoalState()
+ {
+ return this.rule.getGoalState();
+ }
+
+ /**
+ * @return this closure's reduce action.
+ */
+ @Override
+ public JBurgReduceAction getReduceAction()
+ {
+ return rule.getReduceAction();
+ }
+
+ /**
+ * Closure records are equal if they have the same goal state, action, and cost.
+ * @see java.lang.Object#equals
+ *
+ * @param o -- the object to test for equality.
+ * @return true if o is a ClosureRecord and it equals this one.
+ *
+ */
+ @Override
+ public boolean equals(Object o)
+ {
+ boolean result = false;
+
+ if (o instanceof ClosureRecord)
+ {
+ ClosureRecord cuz = (ClosureRecord) o;
+
+ result = getGoalState().equals(cuz.getGoalState());
+ result &= getReduceAction().equals(cuz.getReduceAction());
+ result &= this.rule.getCost(reducerNodeName).equals(cuz.rule.getCost(reducerNodeName));
+ }
+
+ return result;
+ }
+
+ /**
+ * @return true if the cost of this closure is known to be zero.
+ */
+ public boolean costIsZero()
+ {
+ return hasConstantCost() && getConstantCost() == 0;
+ }
+
+ /**
+ * @return the computation of this closure's cost,
+ * which is somewhat error-prone when open coded.
+ */
+ public String getCostComputation()
+ {
+ String antecedentCost =
+ genCallMethod(
+ null,
+ "getCost",
+ getNonterminal(this.getAntecedentState())
+ );
+
+ if ( this.costIsZero() )
+ {
+ return antecedentCost;
+ }
+ else
+ return codeEmitter.genOverflowSafeAdd(this.getCachedCost(), antecedentCost);
+ }
+
+ /**
+ * Precompute the cost of this closure if possible.
+ * @param productions - the set of productions at the
+ * point where the closure's cost is required. If
+ * the closure derives a single pattern-match
+ * rule that has a constant cost, and the closure
+ * itself has a constant cost, then the cost
+ * can be precomputed.
+ * @return the precomputed cost, or the result of
+ * calling {@link getCostComputation()} to get
+ * a non-constant cost.
+ */
+ public String getCostComputation(Multimap<String, JBurgProduction> productions)
+ {
+ // A closure back to a pattern-match with constant cost can be precomputed.
+ if ( this.computesConstantCost(productions) )
+ {
+ return Integer.toString(getConstantCost(productions));
+ }
+ else
+ {
+ // Return the naive cost computation.
+ return getCostComputation();
+ }
+ }
+
+ /**
+ * Get the constant cost of a closure.
+ * @param productions - the set of productions at the
+ * point where the closure's cost is required.
+ * @return the cost, with overflow-safe addition.
+ * @pre computesConstantCost(productions) must be true.
+ */
+ @Override
+ public int getConstantCost(Multimap<String, JBurgProduction> productions)
+ {
+ long constantAntecedent;
+ JBurgProduction production = productions.get(this.getAntecedentState()).get(0);
+
+ if ( production instanceof JBurgRule )
+ constantAntecedent = ((JBurgRule)production).getConstantCost();
+ else
+ constantAntecedent = ((ClosureRecord)production).getConstantCost(productions);
+
+ // Integer-overflow safe addition.
+ @SuppressWarnings("cast")
+ long accum = (long)this.getConstantCost() + constantAntecedent;
+
+ if ( accum < Integer.MAX_VALUE )
+ return (int) accum;
+ else
+ return Integer.MAX_VALUE;
+ }
+
+ /**
+ * Does this closure compute a constant cost
+ * in the context of the given productions?
+ * @param productions - the set of productions at the
+ * point where the closure's cost is required. If
+ * the closure derives a single pattern-match
+ * rule that has a constant cost, and the closure
+ * itself has a constant cost, then the cost
+ * can be precomputed.
+ * @return true if the computed cost is constant.
+ */
+ @Override
+ public boolean computesConstantCost(Multimap<String, JBurgProduction> productions)
+ {
+ boolean result = false;
+ if ( this.hasConstantCost() )
+ {
+ ArrayList<JBurgProduction> antecedents = productions.get(this.getAntecedentState());
+
+ if ( antecedents.size() == 1 )
+ {
+ JBurgProduction production = antecedents.get(0);
+
+ if ( production instanceof JBurgRule )
+ result = ((JBurgRule)production).hasConstantCost();
+ else
+ result = ((ClosureRecord)production).computesConstantCost(productions);
+ }
+ }
+
+ return result;
+ }
+
+ }
+
+ /**
+ * A ParameterDescriptor is a pair (name, subgoalState) which parallels
+ * the FOO(name, subgoalState) found in the specification's syntax.
+ */
+ private static class ParameterDescriptor
+ {
+ String paramName;
+ String paramState;
+ ArityType arityType;
+
+ enum ArityType {Fixed, Variable}
+
+ ParameterDescriptor(String paramName, String paramState, ArityType arityType)
+ {
+ this.paramName = paramName;
+ this.paramState = paramState;
+ this.arityType = arityType;
+ }
+ }
+
+ /**
+ * Finish semantic analysis of the pattern rules.
+ */
+ private void ruleSemanticAnalysis() throws Exception
+ {
+ for (Vector<JBurgRule> vPatternRules: this.patternRules.values())
+ {
+ for (JBurgRule rule: vPatternRules)
+ {
+ for (JBurgPatternMatcher subgoal: rule.patternMatcher.getParameterizedSubtrees())
+ {
+ rule.getReduceAction().addParameter(
+ subgoal.getParameterName(),
+ subgoal.getSubgoal(),
+ subgoal.isNary()? ParameterDescriptor.ArityType.Variable: ParameterDescriptor.ArityType.Fixed
+ );
+ }
+
+ // Add the named subtrees as a convenience.
+ for ( JBurgPatternMatcher named_terminal: rule.patternMatcher.getNamedSubtrees())
+ {
+ rule.getReduceAction().addNamedSubtree(
+ named_terminal.generateReduceTimePath(codeEmitter, reducerNodeName, this.iNodeAdapter, this.adapter2 != null),
+ named_terminal.getParameterName()
+ );
+ }
+
+ // If the pattern matches an operator, send that operator
+ // to the rule so it can be matched in content-access snippets.
+ if ( rule.patternMatcher.matchesOperator() )
+ rule.getReduceAction().setOperator(rule.patternMatcher.getOperator());
+ }
+ }
+ }
+
+ private void emitComputeCostMatrixFunction(String iNodeClass, PrintStream output) throws Exception
+ {
+ // Emit the method declaration and local variables.
+ genDeclareMethod( output, Modifier.PRIVATE, "void", "computeCostMatrix", "JBurgAnnotation", "node");
+ genBeginBlock(output);
+ genLocalVar(output, "long", "iCost", null );
+
+ // The calculations are based on finding patterns
+ // that can label the node's type.
+ genSwitch(output, genCallMethod( "node", "getOperator" ));
+
+ // Try each pattern for a match.
+ // Any pattern that matches then checks its
+ // cost to see if it's less than the current
+ // best cost for the node, and replaces the
+ // node's current rule and cost with its own
+ // if it's the new best cost.
+
+ for (Vector<JBurgRule> vPatternRules: this.patternRules.values())
+ {
+ genCase( output, vPatternRules.firstElement().getOperator() );
+
+ // Group rules by the patterns they match.
+ Multimap<String, JBurgRule> rules_by_pattern = new Multimap<String, JBurgRule>();
+
+ for (JBurgRule rule: vPatternRules)
+ {
+ String encoded_pattern = rule.getEncodedPattern();
+ rules_by_pattern.addToSet(encoded_pattern, rule);
+ }
+
+
+ for ( String encoded_pattern: rules_by_pattern.keySet() )
+ {
+ ArrayList<JBurgRule> current_rules = rules_by_pattern.get(encoded_pattern);
+
+ // Emit the structural pattern match if it was not optimized out.
+ if ( !encoded_pattern.equals(nilPattern))
+ genIf(output, encoded_pattern);
+
+ // Begin a block whether there was a test or not, to scope variables.
+ // TODO: This will not work for a target that doesn't block-scope locals.
+ genBeginBlock(output);
+
+ // Find common path and cost subexpressions.
+ Multimap<JBurgPatternMatcher, JBurgPatternMatcher> aggregated_matchers = new Multimap<JBurgPatternMatcher, JBurgPatternMatcher>();
+
+ Multimap<String, JBurgPatternMatcher> costs = new Multimap<String, JBurgPatternMatcher>();
+
+ for ( JBurgRule rule: rules_by_pattern.get(encoded_pattern))
+ {
+ for (JBurgPatternMatcher subgoal: rule.patternMatcher.getParameterizedSubtrees() )
+ {
+ subgoal.aggregatePaths(aggregated_matchers);
+ costs.addToSet(subgoal.generateCost(codeEmitter, "node"), subgoal);
+ }
+ }
+
+ // Factor out common paths.
+ int factored_path_count = 0;
+ for ( JBurgPatternMatcher key: aggregated_matchers.keySet())
+ {
+ ArrayList<JBurgPatternMatcher> matchers = aggregated_matchers.get(key);
+
+ if ( matchers.size() > aggregatePathThreshold )
+ {
+ String factored_path_var = "factored_path_" + Integer.toString(++factored_path_count);
+ genLocalVar(output, "JBurgAnnotation ", factored_path_var, key.generatePathToRoot(codeEmitter, "node"));
+
+ for ( JBurgPatternMatcher matcher: matchers)
+ matcher.factoredPath = factored_path_var;
+
+ }
+ }
+
+ // Now that the paths have been factored, factor out common costs.
+ int factored_cost_count = 0;
+
+ for (String key: costs.keySet() )
+ {
+ if ( costs.get(key).size() > 1 )
+ {
+ String factored_cost_var = "factored_cost" + Integer.toString(++factored_cost_count);
+ // Regenerate the cost because it may now use factored path expressions.
+ ArrayList<JBurgPatternMatcher> matchers = costs.get(key);
+ genLocalVar(output, "int", factored_cost_var, matchers.get(0).generateCost(codeEmitter, "node"));
+ for ( JBurgPatternMatcher subgoal: matchers)
+ {
+ subgoal.factoredCost = factored_cost_var;
+ }
+ }
+ }
+
+ // Emit the cost checks and their labeling logic.
+
+ int patternPosition = 0;
+
+ for ( JBurgRule rule: current_rules )
+ emitPatternRule(rule, iNodeClass, output, patternPosition++ == 0);
+
+ genEndBlock(output);
+ }
+
+ genEndCase(output);
+ }
+
+ genEndSwitch(output);
+ genEndBlock(output);
+ }
+
+ /**
+ * Emit a routine that inspects the operators found at compiler compile time,
+ * and emits code to get the corresponding node's Nth child.
+ * @param output - the current output stream.
+ */
+ private void emitGetNthChild(PrintStream output)
+ {
+ genDeclareMethod(
+ output,
+ Modifier.PRIVATE,
+ this.iNodeClass,
+ "getNthChild",
+ genFormals(this.iNodeClass, "node", "int", "index"),
+ throwsNothing
+ );
+ genBeginBlock(output);
+ genLocalVar(output, this.iNodeClass, "result", null);
+
+ genSwitch(output, this.iNodeAdapter.genGetOperator("node", this.codeEmitter));
+ for ( String opcode: this.allOperators)
+ {
+ Integer choice_count = this.adapter2.getMaxNthChildChoice(opcode);
+ if ( choice_count != null )
+ {
+ genCase(output, opcode);
+ genSwitch(output, "index");
+ for ( int i = 0; i < choice_count; i++ )
+ {
+ genCase(output, Integer.toString(i));
+ genAssignment(output, "result", this.adapter2.genGetNthChild(opcode, "node", i, codeEmitter));
+ genEndCase(output);
+
+ }
+ // generate the default case for the index.
+ {
+ genDefaultCase(output);
+ genAssignment(output, "result", this.adapter2.genGetDefaultChild(opcode, "node", "index", codeEmitter));
+ genEndCase(output);
+ }
+
+ genEndSwitch(output);
+ genEndCase(output);
+ }
+
+ }
+ // generate the default case for the opcode.
+ {
+ genDefaultCase(output);
+ genAssignment(output, "result", this.iNodeAdapter.genGetNthChild("node", "index", codeEmitter));
+ genEndCase(output);
+ }
+ genEndSwitch(output);
+ genReturnValue(output, "result");
+ genEndBlock(output);
+ }
+
+ private void emitPatternRule(JBurgRule p, String iNodeClass, PrintStream output, boolean isFirstRule ) throws Exception
+ {
+ genComment(output, "Try matching " + p.getOperator() + " ==> " + p.getGoalState());
+
+ /*
+ * Emit code to compute this rule's cost, which is the cost of the rule itself
+ * and all the non-terminals associated with it; then emit a comparison with
+ * the current best cost.
+ */
+ Vector<String> sub_costs = new Vector<String>();
+
+ // Compute the basic cost of the pattern match.
+ sub_costs.add(
+ p.getCost(
+ codeEmitter.genCast(
+ iNodeClass,
+ codeEmitter.genAccessMember("node", "m_node")
+ )
+ )
+ );
+
+ // Try and compute a constant cost.
+ Integer constant_cost = null;
+
+ if ( p.hasConstantCost() )
+ {
+ constant_cost = p.getConstantCost();
+ }
+
+
+ for ( JBurgPatternMatcher subgoal: p.patternMatcher.getParameterizedSubtrees() )
+ {
+ String subgoal_cost = subgoal.generateCost(codeEmitter, "node");
+ if ( subgoal_cost != null )
+ {
+ sub_costs.add(subgoal_cost);
+ constant_cost = null;
+ }
+ }
+
+ String cost_factor;
+ boolean checkCostFactor = true;
+
+ if ( constant_cost != null )
+ {
+ cost_factor = constant_cost.toString();
+ checkCostFactor = constant_cost == Integer.MAX_VALUE;
+ }
+ else if ( sub_costs.size() == 1 )
+ {
+ cost_factor = sub_costs.get(0);
+ }
+ else
+ {
+ // Compute the cost using a long accumulator.
+ cost_factor = "iCost";
+
+ String match_cost = codeEmitter.genCast("long", sub_costs.get(0));
+
+ for ( int i = 1; i < sub_costs.size(); i++ )
+ match_cost = codeEmitter.genAddition(match_cost, codeEmitter.genCast("long", sub_costs.get(i)));
+
+ genAssignment(output, "iCost", match_cost);
+ }
+
+ if ( !isFirstRule || checkCostFactor )
+ {
+ // Does this pattern match cost less than the previously best match?
+ String getCostCall = genCallMethod ( "node", "getCost", codeEmitter.genGetGoalState(p) );
+ String costCheck = codeEmitter.genCmpLess( getCostCall, cost_factor );
+ genIf(output, costCheck );
+ }
+
+ output.print( codeEmitter.genBeginBlock() );
+
+ /*
+ * Emit code to handle a successful match.
+ */
+
+ // Reset the reduce-time rule to fire.
+ String strRule = String.valueOf(p.getReduceAction().getIndex());
+
+ // Now that the comparison has been done using long arithmetic,
+ // iCost can be safely truncated to fit in an int.
+ if ( cost_factor.equals("iCost"))
+ cost_factor = codeEmitter.genCast("int", cost_factor);
+
+ genExpressionStmt(
+ output,
+ codeEmitter.genCallMethod(
+ "node",
+ "reset",
+ new String[] { codeEmitter.genGetGoalState(p), cost_factor, strRule }
+ )
+ );
+
+ if (hasClosure(p))
+ {
+ genExpressionStmt(
+ output,
+ genCallMethod(
+ null,
+ "closure_" + p.getGoalState(),
+ "node", cost_factor
+ )
+ );
+ }
+
+ // End the block begun by the cost comparison above.
+ genEndBlock(output);
+ }
+
+ private JBurgPatternMatcher generateMatcher(AST pattern_root)
+ throws Exception
+ {
+ JBurgPatternEncoder patternBURM = new JBurgPatternEncoder();
+
+ // As we traverse the subtree, we may find parameterized subtrees,
+ // for example, in ADD(expr lhs, expr rhs) lhs and rhs are paramterized
+ // subtrees. These subtrees play several parts in the computation of the
+ // locally-optimal reduction:
+ // - They contribute to the rule's computed cost.
+ // - The reduction's action code may refer to these elements by name.
+ // - If the rule is of the form OP(nttype1 a [, nttype2 b]), then the rule
+ // must enforce this reduce-time goal state on its subtrees' reductions.
+ patternBURM.setSubgoals(new Vector<JBurgPatternMatcher>());
+
+ // There may also be named terminals in the pattern;
+ // as a convenience, record these so that they
+ // can be used by name in the reduction.
+ patternBURM.setNamedterminals(new Vector<JBurgPatternMatcher>());
+
+ patternBURM.setOperators(this.allOperators);
+
+ try
+ {
+ patternBURM.burm( pattern_root );
+ }
+ catch (IllegalStateException burm_error )
+ {
+ if ( this.patternMatcherDumpFile != null )
+ {
+ // Dump the BURM's debugging info.
+ java.io.PrintWriter dumper = new java.io.PrintWriter(new java.io.FileWriter(patternMatcherDumpFile));
+ dumper.println ( "<?xml version=\"1.0\"?>");
+ dumper.println("<BurmDump date=\"" + new java.util.Date().toString() + "\">");
+ patternBURM.dump(dumper);
+ dumper.println("<AST>");
+ dumper.println("<![CDATA[");
+ dumper.println(pattern_root.toStringTree());
+ dumper.println("]]>");
+ dumper.println("</AST>");
+ dumper.println("</BurmDump>");
+ dumper.flush();
+ dumper.close();
+ }
+
+ throw burm_error;
+ }
+
+ JBurgPatternMatcher recognizer = (JBurgPatternMatcher) patternBURM.getResult();
+ recognizer.setParameterizedSubtrees(patternBURM.getSubgoals());
+ recognizer.setNamedSubtrees(patternBURM.getNamedterminals());
+
+ return recognizer;
+ }
+
+ private void emitActions(ArrayList<JBurgReduceAction> reduceActions, String iNodeClass, PrintStream output)
+ {
+ int i = 1;
+
+ // Print out the individual action routines.
+ for (JBurgReduceAction nextAction: reduceActions )
+ {
+ output.println();
+ genComment(output, nextAction.getState());
+
+ // Compute the type of the i-node.
+ String typeOfOperatorINode;
+ final String actionOperator = nextAction.getOperator();
+
+ if ( opcodeNodeTypes.containsKey(actionOperator) )
+ typeOfOperatorINode = opcodeNodeTypes.get(actionOperator);
+ else
+ typeOfOperatorINode = iNodeClass;
+
+ genDeclareMethod(
+ output,
+ Modifier.PRIVATE,
+ getReturnType(nextAction.getState()),
+ "action_" + String.valueOf(i++),
+ genFormals(typeOfOperatorINode, reducerNodeName),
+ throwsException
+ );
+
+ genBeginBlock(output);
+
+ String action_routine = nextAction.toString();
+
+ // Replace #OPERATOR# with a content-access snippet.
+ if ( this.adapter2 != null && nextAction.getOperator() != null )
+ {
+ String content_access = this.adapter2.genGetContent(nextAction.getOperator(), this.reducerNodeName, nextAction.getState(), codeEmitter);
+
+ if ( content_access != null )
+ {
+ String content_pattern = "#" + nextAction.getOperator() + "#";
+ action_routine = action_routine.replaceAll( content_pattern, content_access );
+ }
+ }
+ // Replace #goalstate with the name of the action's input node.
+
+ String goalPattern = "#" + nextAction.getState();
+ action_routine = action_routine.replaceAll( goalPattern, this.reducerNodeName );
+
+ output.print( action_routine );
+
+ genEndBlock(output);
+ }
+
+ // Emit their common dispatch routine.
+ genDeclareMethod(
+ output,
+ Modifier.PRIVATE,
+ "void",
+ "dispatchAction",
+ genFormals("JBurgAnnotation", "___node", "int", "iRule"),
+ throwsException
+ );
+
+ genBeginBlock(output);
+
+ genLocalVar(
+ output,
+ iNodeClass,
+ this.reducerNodeName,
+ genCallMethod("___node", "getNode")
+ );
+
+ genSwitch(output, "iRule" );
+
+ // Emit the dispatch case statement.
+ for (i = 1; i <= reduceActions.size(); i++)
+ {
+ JBurgReduceAction action = reduceActions.get(i-1);
+
+ genCase(output, String.valueOf(i));
+ {
+ // If this is a nonterminal-to-nonterminal
+ // transformation, run the antecedent
+ // reduction action.
+ if ( action.hasAntecedentState() )
+ {
+ genExpressionStmt(
+ output,
+ genCallMethod(
+ "this",
+ "reduceAntecedent",
+ "___node", codeEmitter.genGetGoalState(action.getAntecedentState())
+ )
+ );
+ }
+
+ final String operatorName = action.getOperator();
+ final String nodeTypeForOperator =
+ operatorName != null ? opcodeNodeTypes.get(operatorName) : null;
+ String nodeParameterString = reducerNodeName;
+ if (nodeTypeForOperator != null)
+ nodeParameterString = codeEmitter.genCast(nodeTypeForOperator, nodeParameterString);
+
+ genExpressionStmt(
+ output,
+ codeEmitter.genPushToStack(
+ reducedValuesName,
+ genCallMethod(
+ "this",
+ "action_" + String.valueOf(i),
+ nodeParameterString
+ )
+ )
+ );
+ }
+ genEndCase(output);
+ }
+
+ genDefaultCase(output);
+ {
+ genThrow(output, "\"Unmatched reduce action \" + iRule" );
+ }
+ genEndBlock(output); // genEndCase() without unreachable break
+
+ genEndSwitch(output);
+ genEndBlock(output);
+ }
+
+ private void emitNTConstants(Set<String> goal_states, PrintStream output)
+ {
+ Iterator<String> keys = goal_states.iterator();
+
+ int nthConstant = 0;
+
+ output.print(codeEmitter.genBeginLine());
+ while (keys.hasNext())
+ {
+ nthConstant++;
+
+ String strNTName = codeEmitter.genGetGoalState(keys.next().toString() );
+
+ genInstanceField(
+ output,
+ Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL,
+ "int",
+ strNTName,
+ String.valueOf(nthConstant)
+ );
+ }
+
+ genInstanceField(
+ output,
+ Modifier.PUBLIC + Modifier.STATIC + Modifier.FINAL,
+ "int",
+ "nStates",
+ String.valueOf(nthConstant)
+ );
+ }
+
+ public void emitCostFunctions(ArrayList<AST> costFunctions, String iNodeClass, PrintStream output)
+ {
+ String[][] costParms = genFormals( iNodeClass, reducerNodeName );
+
+ for (int i = 0; i < costFunctions.size(); i++)
+ {
+ AST currentNode = costFunctions.get(i);
+
+ String functionName = currentNode.getFirstChild().getText();
+
+ genDeclareMethod(output, Modifier.PRIVATE, "int", functionName, costParms, throwsNothing );
+ output.print( codeEmitter.genBeginLine() );
+ output.print( getCodeBlock(currentNode) );
+ }
+ }
+
+ public void emitClosures(Map<String, Vector<ClosureRecord>> closureSets, String iNodeClass, PrintStream output)
+ {
+ // TODO: This method can be removed once the C++ target
+ // has been updated to 1.9.0 style semantics.
+ for (String strClosureNT: closureSets.keySet())
+ {
+ genDeclareMethod(
+ output,
+ Modifier.PRIVATE,
+ "void",
+ "closure_" + strClosureNT,
+ genFormals("JBurgAnnotation", reducerNodeName, "long", "c"),
+ throwsNothing
+ );
+
+ genBeginBlock(output);
+
+ genLocalVar(output, "long", "iCost", null );
+
+ for (ClosureRecord newClosure: closureSets.get(strClosureNT) )
+ {
+ String strRule;
+
+ if (newClosure.getReduceAction() != null)
+ strRule = String.valueOf(newClosure.getReduceAction()
+ .getIndex());
+ else
+ strRule = "0";
+
+ String closureCost = newClosure.getCost( codeEmitter.genAccessMember(reducerNodeName, "m_node"));
+
+ if (closureCost.equals("0") )
+ {
+ genAssignment( output, "iCost", "c");
+ }
+ else
+ {
+ genAssignment( output, "iCost", codeEmitter.genAddition( "c", closureCost ));
+ }
+
+ genIf(
+ output,
+ codeEmitter.genCmpLess(
+ genCallMethod (
+ reducerNodeName,
+ "getCost",
+ getNonterminal(newClosure.getGoalState())
+ ),
+ "iCost"
+ )
+ );
+ output.print( codeEmitter.genBeginBlock() );
+
+ genExpressionStmt(
+ output,
+ codeEmitter.genCallMethod(
+ reducerNodeName,
+ "reset",
+ new String[] { getNonterminal(newClosure.getGoalState()), codeEmitter.genCast("int","iCost"), strRule }
+ )
+ );
+
+ genExpressionStmt(
+ output,
+ codeEmitter.genCallMethod(
+ reducerNodeName,
+ "recordAntecedent",
+ new String[] { getNonterminal(newClosure.getGoalState() ), getNonterminal(strClosureNT ) }
+ )
+ );
+
+ if (hasClosure(newClosure))
+ {
+ genExpressionStmt(
+ output,
+ genCallMethod(
+ "this",
+ "closure_" + newClosure.getGoalState(),
+ reducerNodeName, "iCost"
+ )
+ );
+ }
+
+ genEndBlock(output);
+ }
+
+ genEndBlock(output);
+ }
+ }
+
+
+ public void emitLabelFunction(String iNodeClass, PrintStream output)
+ {
+ genDeclareMethod(
+ output,
+ Modifier.PUBLIC,
+ "JBurgAnnotation",
+ "label",
+ genFormals(iNodeClass, JBurgGenerator.initalParamName),
+ throwsNothing
+ );
+
+ genBeginBlock(output);
+ genLocalVar (output, "JBurgAnnotation", "result", codeEmitter.genNullPointer() );
+ genLocalVar (output, "int", "i", null);
+ genLocalVar (output, "int", "arity", null);
+
+ String nodeAlloc = null;
+
+ if ( codeEmitter.supportsSpecializedAnnotations() )
+ {
+ nodeAlloc = genCallMethod( "this", "getJBurgAnnotation", JBurgGenerator.initalParamName);
+ }
+ else
+ {
+ nodeAlloc = codeEmitter.genNewObject( "JBurgAnnotation", new String[] { JBurgGenerator.initalParamName, "nStates + 1" } );
+ }
+ genAssignment( output, "result", nodeAlloc );
+
+ // Generate a loop over children that labels them,
+ // and adds their labelled JBurgAnnotation nodes to the current node.
+ genAssignment(output, "arity", this.iNodeAdapter.genGetArity(JBurgGenerator.initalParamName, codeEmitter));
+ genAssignment(output, "i", "0");
+
+ genLine(output, codeEmitter.genWhileLoop( codeEmitter.genCmpLess("arity", "i")));
+ genBeginBlock(output);
+ {
+ genExpressionStmt(
+ output,
+ genCallMethod(
+ "result",
+ "addChild",
+ genCallLabel("i")
+ )
+ );
+
+ genAssignment(output, "i", codeEmitter.genAddition("i", "1") );
+ }
+ genEndBlock(output); // while
+
+ // Call the costing function.
+ if ( ! this.codeEmitter.supportsSpecializedAnnotations() )
+ genExpressionStmt(output, genCallMethod( "this", "computeCostMatrix", "result"));
+
+ genReturnValue(output, "result" );
+ genEndBlock(output);
+ }
+
+ /**
+ * Emit the subclasses of JBurgAnnotation that encode data for specific pattern matches.
+ * @param output - the destination output stream.
+ */
+ void emitCompressedAnnotations(PrintStream output)
+ {
+ // Emit an annotation object for each equivalence class of rules.
+ for ( String operator: this.compressedAnnotations.getOperators() )
+ for ( ArrayList<JBurgRule> currentRules : this.compressedAnnotations.getRulesFor(operator) )
+ emitAnnotation(output, currentRules);
+
+ // Emit getJBurgAnnotation
+ genDeclareMethod(
+ output,
+ Modifier.PUBLIC,
+ "JBurgAnnotation",
+ "getJBurgAnnotation",
+ genFormals(iNodeClass, "node"),
+ throwsNothing
+ );
+
+ genBeginBlock(output);
+
+ genSwitch(output, this.iNodeAdapter.genGetOperator("node", this.codeEmitter));
+
+ for ( String operator: compressedAnnotations.getOperators() )
+ {
+ genCase(output, operator);
+
+ for ( ArrayList<JBurgRule> rules : this.compressedAnnotations.getRulesFor(operator) )
+ {
+ int arity = getMinumumArity(rules);
+
+ if ( hasNaryness(rules) )
+ genIf(output, String.format("%s >= %d", this.iNodeAdapter.genGetArity("node", codeEmitter), arity));
+ else
+ genIf(output, String.format("%s == %d", this.iNodeAdapter.genGetArity("node", codeEmitter), arity));
+ indentNextLine();
+ genReturnValue(output, String.format("new %s(node)", getSpecializedClassName(rules)));
+ }
+
+ genEndCase(output);
+ }
+
+ genEndSwitch(output);
+
+ genLine(output, "return new JBurgAnnotationGeneral(node, nStates+1);");
+ genEndBlock(output); // getJBurgAnnotation
+
+ }
+
+ /**
+ * Emit an annotation subclass.
+ * @param output - the output stream.
+ * @param currentRules - the set of rules that are this annotation's
+ * domain. The rules all have the same operator, but their arity
+ * may differ if some of them are n-ary.
+ */
+ void emitAnnotation(PrintStream output, ArrayList<JBurgRule> currentRules )
+ {
+ int nominalArity = getMinumumArity(currentRules);
+
+ // The coalesced graph of closures for all the rules.
+ ClosureGraph closureCosts = new ClosureGraph();
+
+ // Factored common subtrees of each pattern matcher.
+ // TODO: These can be further coalesced by using the right comparator.
+ Multimap<JBurgPatternMatcher,JBurgPatternMatcher> commonSubtrees = new Multimap<JBurgPatternMatcher,JBurgPatternMatcher>();
+
+ // Rules and closures by nonterminal.
+ Multimap<String, JBurgProduction> productions = new Multimap<String, JBurgProduction>();
+
+ // Cached subtree costs.
+ Map<String, String> cachedCosts = new HashMap<String, String>();
+
+ // Are all these rules fixed-arity?
+ // If so, the annotation knows its arity a priori.
+ boolean fixedArity = !hasNaryness(currentRules);
+
+ /*
+ * ** Semantic analysis **
+ */
+
+ // Populate the closure graph and factor the pattern matchers.
+ for ( JBurgRule rule: currentRules)
+ {
+ productions.addToSet(rule.getGoalState(), rule);
+
+ closureCosts.addClosures(rule.getGoalState());
+
+ if ( fixedArity )
+ rule.patternMatcher.setFixedArityContext(true);
+
+ for ( JBurgPatternMatcher subgoal: rule.patternMatcher.getParameterizedSubtrees() )
+ subgoal.findFactors(commonSubtrees);
+
+ if ( rule.patternMatcher.getNominalArity() > 0 )
+ {
+ cachedCosts.put(rule.getGoalState(), String.format("cachedCostFor_%s", rule.getGoalState()));
+ }
+ }
+
+ // Add the closures from the coalesced closure graph
+ // to the set of productions.
+ for ( Map.Entry<String, ArrayList<ClosureRecord>> closures: closureCosts.entrySet() )
+ {
+ for ( ClosureRecord closure: closures.getValue() )
+ productions.addToSet(closures.getKey(), closure);
+ }
+
+ // Emitting these variable declarations mutates the
+ // pattern matchers, so they can only be emitted once.
+ // Capture the results so we can write it more than once.
+ Map<JBurgPatternMatcher,String> factored_variables = emitFactoredPathVariables(commonSubtrees);
+
+ /*
+ * Begin code-gen of the class.
+ */
+ output.println();
+ String annotationClass = getSpecializedClassName(currentRules);
+
+ genLine(output, String.format("class %s extends JBurgSpecializedAnnotation", annotationClass));
+ genBeginBlock(output);
+
+ // Emit a field for each child.
+ for ( int fieldIdx = 0; fieldIdx < nominalArity; fieldIdx++ )
+ {
+ genInstanceField( output, Modifier.PRIVATE, "JBurgAnnotation", String.format("subtree%d", fieldIdx), null);
+ }
+
+ if ( !fixedArity )
+ {
+ genInstanceField(
+ output,
+ Modifier.PRIVATE,
+ codeEmitter.genNaryContainerType("JBurgAnnotation"),
+ "narySubtrees",
+ String.format("new %s()", codeEmitter.genNaryContainerType("JBurgAnnotation"))
+ );
+ }
+
+ // Emit the constructor.
+ // TODO: The emitter needs a genConstructor() API.
+ genLine(output, String.format("%s(%s node)", annotationClass, this.iNodeClass));
+ genBeginBlock(output);
+ // TODO: The emitter also needs a callSuperclassConstructor() API.
+ genLine(output, "super(node);");
+ genEndBlock(output);
+
+ for ( String cachedCostVar: cachedCosts.values() )
+ {
+ genInstanceField( output, Modifier.PRIVATE, "int", cachedCostVar, UNINITIALIZED);
+ }
+
+ /*
+ * ** Emit getCost() **
+ */
+ genDeclareMethod( output, Modifier.PUBLIC, "int", "getCost", "int", "goalState" );
+ genBeginBlock(output);
+
+ genSwitch(output, "goalState");
+
+ for ( Map.Entry<String, ArrayList<JBurgProduction>> productionsByNonterminal: productions.entrySet() )
+ {
+ genCase(output, getNonterminal(productionsByNonterminal.getKey()));
+
+ ArrayList<JBurgProduction> currentProductions = productionsByNonterminal.getValue();
+
+ // Try to find the optimal production at compiler-compile time.
+ JBurgProduction optimalProduction = findOptimalProduction(currentProductions, productions);
+
+ if ( optimalProduction != null )
+ {
+ genReturnValue(output, Integer.toString(optimalProduction.getConstantCost(productions)));
+ }
+ else
+ {
+ final boolean hasMultipleProductions = currentProductions.size() > 1;
+ final boolean cacheCost = cachedCosts.containsKey(productionsByNonterminal.getKey());
+
+ boolean currentCostDeclared = false;
+
+ String bestCostVar;
+
+ if ( cacheCost )
+ {
+ bestCostVar = cachedCosts.get(productionsByNonterminal.getKey());
+ genIf ( output, codeEmitter.genCmpEquality(bestCostVar, UNINITIALIZED, true) );
+ genBeginBlock(output);
+ }
+ else if ( hasMultipleProductions )
+ {
+ // Store the best cost in a local.
+ bestCostVar = "bestCost";
+ genLocalVar(output, "int", "bestCost");
+ }
+ else
+ {
+ bestCostVar = codeEmitter.genMaxIntValue();
+ }
+
+ for ( int i = 0; i < currentProductions.size(); i++ )
+ {
+ JBurgProduction production = currentProductions.get(i);
+ String productionCost = getCostForProduction(production, productions);
+
+ if ( currentProductions.size() == 1 && !cacheCost )
+ {
+ // Only one production, just return its cost.
+ genReturnValue(output, productionCost);
+ }
+ else if ( i == 0 )
+ {
+ // Emit an assignment with no if guards
+ // if this is the first (or only) assignment.
+ genAssignment(output, bestCostVar, productionCost);
+ output.println();
+ }
+ else
+ {
+ // If the cost uses a computation, put it in a temp.
+ if ( !production.computesConstantCost(productions) )
+ {
+ if ( ! currentCostDeclared )
+ {
+ genLocalVar(output, "int", "currentCost", productionCost);
+ currentCostDeclared = true;
+ }
+ else
+ {
+ genAssignment(output, "currentCost", productionCost);
+ }
+
+ productionCost = "currentCost";
+ }
+
+ genIf(output, codeEmitter.genCmpLess(bestCostVar, productionCost));
+ indentNextLine();
+ genAssignment(output, bestCostVar, productionCost);
+ }
+ }
+
+ if ( cacheCost )
+ // End the if statement.
+ genEndBlock(output);
+
+ if ( cacheCost || hasMultipleProductions )
+ genReturnValue(output, bestCostVar);
+ // else the cost has already been returned.
+ }
+
+ genEndBlock(output); // end case without unreachable break
+ }
+ genEndSwitch(output);
+ genReturnValue(output, codeEmitter.genMaxIntValue());
+ genEndBlock(output); // getCost
+
+ /*
+ * ** Emit getRule() **
+ */
+ genDeclareMethod(output, Modifier.PUBLIC, "int", "getRule", "int", "goalState" );
+ genBeginBlock(output);
+
+ genSwitch(output, "goalState");
+
+ for ( Map.Entry<String, ArrayList<JBurgProduction>> productionsByNonterminal: productions.entrySet() )
+ {
+ genCase(output, getNonterminal(productionsByNonterminal.getKey()));
+
+ ArrayList<JBurgProduction> currentProductions = productionsByNonterminal.getValue();
+
+ // Try to resolve the optimal production at compiler-compile time.
+ JBurgProduction optimalProduction = findOptimalProduction(currentProductions, productions);
+
+ if ( optimalProduction != null )
+ {
+ genReturnValue(output, Integer.toString(optimalProduction.getReduceAction().getIndex()));
+ }
+ else
+ {
+ // Emit the analogous compile-time computation.
+ genLocalVar(output, "int", "rule", NO_FEASIBLE_RULE);
+ genLocalVar(output, "int", "bestCost", codeEmitter.genMaxIntValue());
+
+ // Emit this declaration at its first use.
+ boolean currentCostDeclared = false;
+
+ for ( int i = 0; i < currentProductions.size(); i++ )
+ {
+ boolean costIsConstant = false;
+ String currentProductionCost;
+
+ // Extract required information from the production:
+ // what is its cost, and is it constant?
+ JBurgProduction production = currentProductions.get(i);
+
+ if ( production.computesConstantCost(productions) )
+ {
+ int constantCost = production.getConstantCost(productions);
+ costIsConstant = constantCost < Integer.MAX_VALUE;
+ currentProductionCost = Integer.toString(constantCost);
+ }
+ else
+ {
+ currentProductionCost = getCostForProduction(production, productions);
+ }
+
+ // Generate the necessary tests and assignments.
+
+ // If the first production's cost is constant
+ // (and feasible, which has been checked and
+ // incorporated into costIsConstant), then
+ // testing it against bestCost is a tautology.
+ boolean needComparison = (!costIsConstant) || i > 0;
+
+ if ( needComparison )
+ {
+ // If the cost uses a computation, put it in a temp.
+ if ( ! costIsConstant )
+ {
+ if ( ! currentCostDeclared )
+ {
+ genLocalVar(output, "int", "currentCost", currentProductionCost);
+ currentCostDeclared = true;
+ }
+ else
+ {
+ genAssignment(output, "currentCost", currentProductionCost);
+ }
+ currentProductionCost = "currentCost";
+ }
+
+ genIf(output, codeEmitter.genCmpLess("bestCost", currentProductionCost));
+ genBeginBlock(output);
+ }
+
+ // Track the new best cost if there's another choice to be evaluated.
+ if ( i + 1 < currentProductions.size() )
+ genAssignment(output, "bestCost", currentProductionCost);
+
+ genAssignment(output, "rule", Integer.toString(production.getReduceAction().getIndex()));
+
+ if ( needComparison )
+ genEndBlock(output);
+ }
+
+ genReturnValue(output,"rule");
+ }
+
+ genEndBlock(output); // endCase() without unreachable break statement
+ }
+
+ genEndSwitch(output);
+ genReturnValue(output, NO_FEASIBLE_RULE);
+ genEndBlock(output); // getRule
+
+ /*
+ * ** Emit getArity() **
+ */
+ genDeclareMethod(output, Modifier.PUBLIC, "int", "getArity");
+ genBeginBlock(output);
+
+ if ( fixedArity )
+ {
+ genReturnValue(output, Integer.toString(nominalArity));
+ }
+ else if ( nominalArity != 0 )
+ {
+ // TODO: Need an emitter method to get the correct size() call
+ genReturnValue(output, String.format("%d + %s", nominalArity, "narySubtrees.size()" ));
+ }
+ else
+ {
+ genReturnValue(output, "narySubtrees.size()" );
+ }
+
+ genEndBlock(output); // getArity
+
+ /*
+ * ** Emit overrides for getNthChild() and addChild() if necessary **
+ */
+ if ( nominalArity > 0 || ! fixedArity )
+ {
+ // getNthChild
+ genDeclareMethod( output, Modifier.PUBLIC, "JBurgAnnotation", "getNthChild", "int", "index");
+
+ genBeginBlock(output); // getNthChild
+ genSwitch(output, "index");
+
+ for ( int i = 0; i < nominalArity; i++ )
+ {
+ genLine(output, String.format("case %d:", i));
+ genSingleLineBlock(output, String.format("return subtree%d;", i));
+ }
+
+ genDefaultCase(output);
+ if ( ! fixedArity )
+ {
+ if ( nominalArity == 0 )
+ genLine(output, "return narySubtrees.get(index);");
+ else
+ genLine(output, String.format("return narySubtrees.get(index - %d);", nominalArity));
+ }
+ else
+ {
+ genThrow(output, "\"Invalid index \" + index");
+ }
+ genEndBlock(output); // genEndCase() without unreachable break
+
+ genEndBlock(output); // switch
+ genEndBlock(output); // getNthChild
+
+ // addChild
+ genDeclareMethod(output, Modifier.PUBLIC, "void", "addChild", "JBurgAnnotation", "child");
+
+ genBeginBlock(output); // addChild
+
+ for ( int i = 0; i < nominalArity; i++ )
+ {
+ if ( i == 0 )
+ genLine(output, String.format("if ( subtree%d == null )", i));
+ else
+ genLine(output, String.format("else if ( subtree%d == null )", i));
+ genSingleLineBlock(output, String.format("subtree%d = child;", i));
+ }
+
+ if ( nominalArity > 0 )
+ genLine(output, String.format("else"));
+
+ if ( ! fixedArity )
+ genSingleLineBlock(output, "narySubtrees.add(child);");
+ else
+ genSingleLineBlock(output, "throw new IllegalStateException(\"too many children\");");
+
+ genEndBlock(output); // addChild
+ }
+
+ // Emit caches for any costs that require a function call;
+ // the BURM's contract says these functions are only called once.
+ Set<String> emittedCosts = new HashSet<String>();
+
+ for ( ArrayList<ClosureRecord> closures: closureCosts.values() )
+ for ( ClosureRecord closure: closures )
+ if ( closure.hasCostFunction() && emittedCosts.add(closure.getCachedCost()) )
+ emitCachedCost(output, closure.getCachedCost(), closure.getCost("m_node"));
+
+ for ( JBurgRule rule: currentRules )
+ {
+ if ( rule.needsCostFunction() )
+ emitGetCostForRule(output, rule, factored_variables);
+
+ if ( rule.hasCostFunction() && emittedCosts.add(rule.getCachedCost()) )
+ emitCachedCost(output, rule.getCachedCost(), rule.getCost("m_node"));
+ }
+
+ // Finish the compressed annotation's class declaration.
+ genEndBlock(output);
+ }
+
+ /**
+ * @param productions - a list of productions.
+ * @return true if the list has one member and that member has a constant cost.
+ */
+ boolean hasConstantCost(ArrayList<JBurgProduction> productions)
+ {
+ return productions != null &&
+ productions.size() == 1 &&
+ productions.get(0) instanceof JBurgRule &&
+ ((JBurgRule)productions.get(0)).hasConstantCost();
+ }
+
+ /**
+ * @return the expression to use for a production's cost;
+ * this may be an arithmetic expression or a call
+ * to an implementation method, depending on
+ * the production's complexity.
+ */
+ String getCostForProduction(JBurgProduction production, Multimap<String,JBurgProduction> productions)
+ {
+ if ( production instanceof JBurgRule )
+ {
+ JBurgRule rule = (JBurgRule) production;
+ if ( rule.needsCostFunction() )
+ return genCallMethod(null, getCostingFunctionForRule(rule), "goalState");
+ else
+ return getCompositeCostOfRule(rule);
+ }
+ else
+ {
+ return ((ClosureRecord)production).getCostComputation(productions);
+ }
+ }
+
+ /**
+ * Do compiler-compile time dynamic programming to choose
+ * the best alternative from a list of possibilities.
+ * @param currentProductions - the list of productions to choose from.
+ * @param allProductions - the entire set of productions active at the site.
+ */
+ JBurgProduction findOptimalProduction(List<JBurgProduction> currentProductions, Multimap<String, JBurgProduction> allProductions)
+ {
+ int bestCost = Integer.MAX_VALUE;
+ JBurgProduction result = null;
+
+ for ( JBurgProduction production: currentProductions )
+ {
+ if ( production.computesConstantCost(allProductions) )
+ {
+ int cost = production.getConstantCost(allProductions);
+ if ( cost < bestCost )
+ {
+ result = production;
+ bestCost = cost;
+ }
+ }
+ else
+ {
+ // Can't be determined at compiler-compile time.
+ result = null;
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Emit a rule's cost function.
+ * @param output - the current output stream.
+ * @param rule - the rule to emit.
+ * @param factored_variables - the list of pattern matchers it's worth factoring.
+ */
+ void emitGetCostForRule(PrintStream output, JBurgRule rule, Map<JBurgPatternMatcher,String> factored_variables )
+ {
+ assert(rule.needsCostFunction());
+
+ genDeclareMethod(output, Modifier.PRIVATE, "int", getCostingFunctionForRule(rule), "int", "goalState");
+ genBeginBlock(output);
+ {
+ for ( String var_decl: factored_variables.values() )
+ if ( rule.patternMatcher.usesFactoredVariable(var_decl) )
+ genLine(output, var_decl);
+
+ output.println();
+
+ String patternMatch = rule.patternMatcher.generatePatternRecognizer(
+ codeEmitter,
+ "this",
+ JBurgGenerator.this.adapter2
+ );
+
+ // The pattern match may be null if it's trival.
+ if ( patternMatch != null )
+ {
+ genIf(output, patternMatch);
+ indentNextLine();
+ }
+
+ genReturnValue(output, getCompositeCostOfRule(rule));
+
+ if ( patternMatch != null )
+ {
+ genLine(output, codeEmitter.genElse());
+ indentNextLine();
+ genReturnValue(output, codeEmitter.genMaxIntValue());
+ }
+
+ }
+ genEndBlock(output);
+ }
+
+ /**
+ * @return a unique identifier for the method that computes
+ * a rule's cost (note: this is not the rule's cost function).
+ */
+ String getCostingFunctionForRule(JBurgRule rule)
+ {
+ if ( ! ruleNumber.containsKey(rule) )
+ ruleNumber.put(rule, String.format("getCostForRule%x", ruleNumber.size()));
+ return ruleNumber.get(rule);
+ }
+
+ private Map<JBurgRule,String> ruleNumber = new HashMap<JBurgRule, String>();
+
+ /**
+ * Emit the cache field and accessor function for a cached
+ * result of a cost function call.
+ */
+ void emitCachedCost(PrintStream output, String functionName, String payload)
+ {
+ // Strip () characters.
+ functionName = functionName.substring(0, functionName.length() -2);
+
+ String varName = String.format("cachedCostFunctionResult_%h", functionName);
+
+ genInstanceField( output, Modifier.PRIVATE, "int", varName, UNINITIALIZED);
+
+ genDeclareMethod( output, Modifier.PRIVATE, "int", functionName );
+
+ genBeginBlock(output);
+ {
+ genIf ( output, codeEmitter.genCmpEquality(varName, UNINITIALIZED, true) );
+ indentNextLine();
+ genAssignment(output, varName, payload);
+ genReturnValue(output, varName);
+ }
+ genEndBlock(output);
+ }
+
+ /**
+ * Add up all of a rule's cost factors.
+ * @param rule - the rule of interest.
+ * @return an overflow-safe addition of the
+ * rule's cost and the costs of its subtrees.
+ */
+ String getCompositeCostOfRule(JBurgRule rule)
+ {
+ String subtreeCost = null;
+
+ for ( JBurgPatternMatcher subgoal: rule.patternMatcher.getParameterizedSubtrees() )
+ {
+ String subgoalCost = subgoal.generateCost(codeEmitter, "this");
+
+ if ( subgoalCost != null )
+ subtreeCost = codeEmitter.genAddition(subtreeCost, codeEmitter.genCast("long", subgoalCost));
+ }
+
+ if ( subtreeCost != null )
+ return codeEmitter.genOverflowSafeAdd(rule.getCachedCost(), subtreeCost);
+ else
+ return rule.getCachedCost();
+ }
+
+ /**
+ * Emit the factored path variables into a map,
+ * and mutate the affected pattern matchers
+ * to refer to the factored variable.
+ * @param commonSubtrees - the map of common subtrees to their pattern matchers.
+ */
+ Map<JBurgPatternMatcher,String> emitFactoredPathVariables(Multimap<JBurgPatternMatcher, JBurgPatternMatcher> commonSubtrees)
+ {
+ Map<JBurgPatternMatcher,String> result = new TreeMap<JBurgPatternMatcher, String>();
+
+ int varNum = 0;
+ for ( Map.Entry<JBurgPatternMatcher, ArrayList<JBurgPatternMatcher>> factored: commonSubtrees.entrySet() )
+ {
+ String varName = String.format("factoredPath_%d", varNum++);
+
+ result.put(factored.getKey(), codeEmitter.genLocalVar("JBurgAnnotation", varName, factored.getKey().generateFactoredReference(codeEmitter)));
+
+ for ( JBurgPatternMatcher matcher: factored.getValue() )
+ matcher.factoredPath = varName;
+ }
+
+ return result;
+ }
+
+ /**
+ * ClosuresByNonterminal is a convenience class that holds
+ * closure sets grouped by nonterminal; the NT may
+ * be the production or the antecedent, depending on usage.
+ */
+ class ClosuresByNonterminal extends Multimap<String, ClosureRecord>
+ {
+ /**
+ * Add a closure record.
+ * @param nt - the nonterminal that indexes this closure.
+ * May be the production or the antecedent.
+ */
+ public void addClosure(String nt, ClosureRecord closure)
+ {
+ if ( ! this.getSet(nt).contains(closure) )
+ this.getSet(nt).add(closure);
+ }
+ }
+
+ /**
+ * A ClosureGraph holds the graph of closures that
+ * can be reached from a starting nonterminal.
+ */
+ class ClosureGraph extends ClosuresByNonterminal
+ {
+ /**
+ * Sweep the set of nonterminal-to-nonterminal rules and
+ * add any that can be produced by the most recently
+ * added nonterminal.
+ * @param currentNT - the most recently added nonterminal.
+ */
+ void addClosures(String currentNT)
+ {
+ addClosures(currentNT, currentNT);
+ }
+
+ /**
+ * Sweep the set of nonterminal-to-nonterminal rules and
+ * add any that can be produced by the most recently
+ * added nonterminal.
+ * @param currentNT - the most recently added nonterminal.
+ * @param patternNT - the nonterminal produced by the pattern match.
+ */
+ void addClosures(String currentNT, String patternNT)
+ {
+ if ( JBurgGenerator.this.closureSets.containsKey(currentNT) )
+ {
+ for ( ClosureRecord closure: JBurgGenerator.this.closureSets.get(currentNT) )
+ {
+ String newNT = closure.getGoalState();
+
+ // Can't replace the pattern with a closure.
+ if ( !newNT.equals(patternNT) )
+ {
+ if ( ! this.containsKey ( newNT ) )
+ {
+ super.addClosure(newNT, closure);
+ addClosures(newNT);
+ }
+ else
+ {
+ // Add this closure, but its consequent
+ // closures are already in the set so
+ // it's not necessary to add them.
+ super.addClosure(newNT, closure);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @return the current Logger implementation;
+ * constructs a Logger that emits messages
+ * to stdout/stderr.
+ */
+ Logger getLogger()
+ {
+ if ( null == this.logger )
+ this.logger = new Logger(true, true, true);
+ return this.logger;
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genAssignment and prints the result.
+ */
+ void genAssignment(PrintStream output, String lvalue, String rvalue)
+ {
+ genLine(output, codeEmitter.genAssignment( lvalue, rvalue ) );
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genComment and prints the result.
+ */
+ void genComment(PrintStream output, String comment)
+ {
+ genLine(output, codeEmitter.genComment(comment) );
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genLine and prints the result.
+ * @param output - the current output stream
+ * @param contents - the contents to write. Contents will be trimmed
+ * of whitespace before output.
+ */
+ void genLine(PrintStream output, String contents)
+ {
+ String formattedContents = contents.trim();
+
+ if ( doIndentNextLine )
+ formattedContents = "\t" + formattedContents;
+
+ doIndentNextLine = false;
+ output.print(codeEmitter.genLine(formattedContents) );
+ }
+
+ /**
+ * When set, indent the next line of output to note that
+ * the statement on that line is an if/then branch.
+ * @see {@link #indentNextLine()}, which sets this field.
+ * @see {@link #genLine(PrintStream,String)}, which consumes this field and resets it.
+ *
+ */
+ boolean doIndentNextLine = false;
+
+ /**
+ * Signal that the next line should be indented.
+ * @see {@link #doIndentNextLine}, which this method sets.
+ */
+ void indentNextLine()
+ {
+ doIndentNextLine = true;
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genLine and prints the result,
+ * with an extra level of nesting added to improve readability.
+ */
+ void genSingleLineBlock (PrintStream output, String contents)
+ {
+ indentNextLine();
+ genLine(output, contents);
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genBeginBlock and prints the result.
+ */
+ void genBeginBlock(PrintStream output)
+ {
+ output.print(codeEmitter.genBeginBlock());
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genEndBlock and prints the result.
+ */
+ void genEndBlock(PrintStream output)
+ {
+ output.print(codeEmitter.genEndBlock());
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genSwitch and prints the result.
+ */
+ void genSwitch(PrintStream output, String expression)
+ {
+ genLine(output, codeEmitter.genSwitch(expression) );
+ genBeginBlock(output);
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genEndSwitch and prints the result.
+ */
+ void genEndSwitch(PrintStream output)
+ {
+ genLine(output, codeEmitter.genEndSwitch() );
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genCase and prints the result.
+ */
+ void genCase(PrintStream output, String selector )
+ {
+ output.print(codeEmitter.genCase(selector));
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genEndCase and prints the result.
+ */
+ void genEndCase(PrintStream output)
+ {
+ output.print(codeEmitter.genEndCase());
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genDefaultCase and prints the result.
+ */
+ void genDefaultCase(PrintStream output)
+ {
+ genLine(output, codeEmitter.genDefaultCase());
+ genBeginBlock(output);
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genIf and prints the result.
+ */
+ void genIf(PrintStream output, String condition )
+ {
+ genLine(output, codeEmitter.genIf(condition));
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genReturnValue and prints the result.
+ */
+ void genReturnValue(PrintStream output, String value )
+ {
+ genLine(output, codeEmitter.genReturnValue(value) + codeEmitter.genEndStmt());
+ }
+
+ /**
+ * Convenience method prints an expression as a statement.
+ */
+ void genExpressionStmt(PrintStream output, String expr)
+ {
+ genLine(output, expr + codeEmitter.genEndStmt());
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genDeclareMethod and prints the result.
+ */
+ void genDeclareMethod(PrintStream output, int modifiers, String returnClass, String name, String[][] plist, Class<?>[] exceptions )
+ {
+ output.print(codeEmitter.declareMethod(modifiers, returnClass, name, plist, exceptions));
+ }
+
+ /**
+ * Convenience method declares BURM methods that don't throw.
+ */
+ void genDeclareMethod(PrintStream output, int modifiers, String returnClass, String name, Object ... plist)
+ {
+ genDeclareMethod(output, modifiers, returnClass, name, genFormals(plist), throwsNothing);
+ }
+
+ /**
+ * Convenience method declares BURM methods that don't throw or have parameters.
+ */
+ void genDeclareMethod(PrintStream output, int modifiers, String returnClass, String name)
+ {
+ genDeclareMethod(output, modifiers, returnClass, name, noFormalParameters, throwsNothing);
+ }
+
+ /**
+ * Generate formal parameters from a list of type, name pairs.
+ * @param raw_formals - a variadic list of type, name pairs.
+ * @return the raw formals marshalled into a 2-dimensional array.
+ */
+ String[][] genFormals(Object ... raw_formals)
+ {
+ assert(raw_formals.length % 2 == 0): "n-ary formal parameters must be in (type, name) pairs";
+
+ String[][] plist = new String[raw_formals.length/2][2];
+ for ( int i = 0; i < raw_formals.length - 1; i += 2 )
+ {
+ plist[i/2][0] = raw_formals[i].toString();
+ plist[i/2][1] = raw_formals[i+1].toString();
+ }
+
+ return plist;
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genLocalVar and prints the result.
+ */
+ void genLocalVar(PrintStream output, String varType, String varName, String initializer)
+ {
+ genLine(output, codeEmitter.genLocalVar(varType, varName, initializer));
+ output.println();
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genLocalVar and prints the result.
+ */
+ void genLocalVar(PrintStream output, String varType, String varName)
+ {
+ genLocalVar(output, varType, varName, null);
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genThrow and prints the result.
+ */
+ void genThrow( PrintStream output, String diagnostic )
+ {
+ genLine(output, codeEmitter.genThrow(diagnostic) + codeEmitter.genEndStmt() );
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genInstanceField and prints the result.
+ */
+ void genInstanceField(PrintStream output, int modifiers, String type, String name, String initializer)
+ {
+ genLine(output, codeEmitter.genInstanceField(modifiers, type, name, initializer));
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genGetGoalState.
+ */
+ String getNonterminal(String raw_nt)
+ {
+ return codeEmitter.genGetGoalState(raw_nt);
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genCallMethod for methods with no parameters.
+ */
+ String genCallMethod(String stem, String methodName)
+ {
+ return codeEmitter.genCallMethod(stem, methodName, noActualParameters );
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genCallMethod for methods with one parameter.
+ */
+ String genCallMethod(String stem, String methodName, Object param)
+ {
+ return codeEmitter.genCallMethod(stem, methodName, new String[] { param.toString() } );
+ }
+
+ /**
+ * Convenience method wraps codeEmitter.genCallMethod for methods with two parameters.
+ */
+ String genCallMethod(String stem, String methodName, Object param1, Object param2)
+ {
+ return codeEmitter.genCallMethod(stem, methodName, new String[] { param1.toString(), param2.toString() } );
+ }
+
+
+ /**
+ * @return the input string with its outer
+ * layer of {} brackets stripped off.
+ */
+ public static String stripBrackets(String src)
+ {
+ int startchar = src.indexOf('{') + 1;
+ int lentoend = src.lastIndexOf('}');
+ return src.substring( startchar, lentoend-startchar );
+
+ }
+
+ /**
+ * Generate the correct calling sequence to get the nth child
+ * of an input i-node.
+ * @param indexTerm - the n in nth child.
+ */
+ String genGetNthChild(String indexTerm)
+ {
+ return this.adapter2 != null ?
+ genCallMethod("this", "getNthChild", JBurgGenerator.initalParamName, indexTerm):
+ this.iNodeAdapter.genGetNthChild( JBurgGenerator.initalParamName, indexTerm, codeEmitter );
+ }
+
+ /**
+ * Generate the calling sequence for the label() method.
+ */
+ String genCallLabel(String indexTerm)
+ {
+ return genCallMethod(
+ "this",
+ "label",
+ codeEmitter.genCast(
+ iNodeClass,
+ genGetNthChild(indexTerm)
+ )
+ );
+ }
+
+ /**
+ * @return true if any rules in the list have n-ary operands.
+ */
+ private boolean hasNaryness(Collection<JBurgRule> rules)
+ {
+ boolean result = false;
+
+ for ( JBurgRule rule: rules )
+ result |= rule.patternMatcher.hasNaryness();
+
+ return result;
+ }
+
+ /**
+ * @return the minumum arity of a list of rules.
+ */
+ private int getMinumumArity(Collection<JBurgRule> rules)
+ {
+ int result = Integer.MAX_VALUE;
+
+ for ( JBurgRule rule: rules )
+ result = Math.min(result, rule.patternMatcher.getNominalArity());
+
+ return result;
+ }
+
+ /**
+ * @return the name of a JBurgAnnotation specialized subclass.
+ */
+ String getSpecializedClassName(ArrayList<JBurgRule> rules )
+ {
+ if ( hasNaryness(rules) )
+ return String.format("JBurgAnnotation_%s_%d_n", rules.get(0).getOperator(), getMinumumArity(rules));
+ else
+ return String.format("JBurgAnnotation_%s_%d", rules.get(0).getOperator(), getMinumumArity(rules));
+ }
+
+ /**
+ * RulesByOperatorAndArity is a multidimensional associative store that
+ * sorts JBurgRules into equivalence classes, where the equivalaence
+ * relation is "these rules can share an annotation object."
+ */
+ class RulesByOperatorAndArity
+ {
+ /**
+ * Unsorted rules.
+ */
+ Multimap<String, JBurgRule> unsortedRules = new Multimap<String, JBurgRule>();
+
+ Map<String, Iterable<ArrayList<JBurgRule>>> sortedRules = null;
+
+ public void addAll(List<JBurgRule> rules)
+ {
+ assert sortedRules == null;
+
+ String operator = rules.get(0).getOperator();
+ this.unsortedRules.addAllToSet(operator, rules);
+ }
+
+ public void addRule(JBurgRule rule)
+ {
+ assert sortedRules == null;
+ this.unsortedRules.addToSet(rule.getOperator(), rule);
+ }
+
+ public Set<String> getOperators()
+ {
+ return unsortedRules.keySet();
+ }
+
+ public Iterable<ArrayList<JBurgRule>> getRulesFor(String operator)
+ {
+ if ( this.sortedRules == null )
+ {
+ this.sortedRules = new TreeMap<String, Iterable<ArrayList<JBurgRule>>>();
+
+ for ( String op: getOperators() )
+ this.sortedRules.put(op, sortRules(this.unsortedRules.get(op)));
+ }
+
+ return this.sortedRules.get(operator);
+ }
+
+ private Iterable<ArrayList<JBurgRule>> sortRules( ArrayList<JBurgRule> unsorted_rules)
+ {
+ // Find the minumum arity of all n-ary patterns;
+ // any rule with arity >= this limit gets sorted
+ // into the "variable-arity" bucket.
+ int arity_requires_variable = Integer.MAX_VALUE;
+
+ for ( JBurgRule rule: unsorted_rules )
+ if ( rule.patternMatcher.hasNaryness() )
+ arity_requires_variable = Math.min(arity_requires_variable, rule.patternMatcher.getNominalArity());
+
+ Multimap<Integer, JBurgRule> rules = new Multimap<Integer, JBurgRule>();
+
+ for ( JBurgRule rule: unsorted_rules )
+ {
+ // All n-ary patterns and any fixed-arity patterns that
+ // overlap with n-ary patterns go into a common annotation;
+ // fixed-arity patterns of arity less than the smallest
+ // n-ary arity can't be confused with an n-ary pattern
+ // and can go in their own annotation.
+ Integer key =
+ rule.patternMatcher.getNominalArity() < arity_requires_variable?
+ rule.patternMatcher.getNominalArity():
+ arity_requires_variable;
+
+ rules.addToSet(key,rule);
+ }
+
+ return rules.values();
+ }
+
+ }
+}
diff --git a/compiler-jx/.classpath b/compiler-jx/.classpath
index 31d0100..36d2686 100644
--- a/compiler-jx/.classpath
+++ b/compiler-jx/.classpath
@@ -17,5 +17,6 @@
<classpathentry combineaccessrules="false" kind="src" path="/compiler-common"/>
<classpathentry combineaccessrules="false" kind="src" path="/compiler-externc"/>
<classpathentry combineaccessrules="false" kind="src" path="/compiler-test-utils"/>
+ <classpathentry kind="lib" path="/compiler-externc/target/test-classes"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>
diff --git a/compiler-jx/pom.xml b/compiler-jx/pom.xml
index 628aedc..4608343 100644
--- a/compiler-jx/pom.xml
+++ b/compiler-jx/pom.xml
@@ -1,137 +1,237 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>compiler-jx</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: Compiler-JX</name>
-
- <build>
- <plugins>
- <!-- Make the surefire execute all unit-tests -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>2.19</version>
- <configuration>
- <includes>
- <include>org/**/Test*.java</include>
- </includes>
- <excludes>
- <exclude>**/TestRoyaleFile.java</exclude>
- <exclude>**/TestRoyaleMXML*.java</exclude>
- <exclude>**/TestSourceMap*.java</exclude>
- <exclude>**/TestMXML*.java</exclude>
- <exclude>**/TestRoyaleClass.java</exclude>
- <exclude>**/TestTypedefsCompile.java</exclude>
- </excludes>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-failsafe-plugin</artifactId>
- <version>2.18.1</version>
- <configuration>
- <includes>
- <include>**/TestMXML*.java</include>
- </includes>
- <excludes>
- <exclude>**/TestTypedefsCompile.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-common</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-externc</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-compress</artifactId>
- <version>1.11</version>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.6</version>
- </dependency>
-
- <dependency>
- <groupId>args4j</groupId>
- <artifactId>args4j</artifactId>
- <version>2.33</version>
- </dependency>
- <dependency>
- <groupId>com.google.javascript</groupId>
- <artifactId>closure-compiler</artifactId>
- <version>v20170626</version>
- </dependency>
- <dependency>
- <groupId>org.clojure</groupId>
- <artifactId>google-closure-library</artifactId>
- <version>0.0-20170809-b9c14c6b</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-test-utils</artifactId>
- <version>0.9.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-externc</artifactId>
- <version>0.9.4</version>
- <type>test-jar</type>
- <scope>test</scope>
- </dependency>
-
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>compiler-jx</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: Compiler-JX</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>copy-externc-resources</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/../compiler-externc/target</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../compiler-externc/src/test/config</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-custom-resources</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/target</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/test/config</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!-- Make the surefire execute all unit-tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19</version>
+ <configuration>
+ <includes>
+ <include>org/**/Test*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/TestRoyaleFile.java</exclude>
+ <exclude>**/TestRoyaleMXML*.java</exclude>
+ <exclude>**/TestSourceMap*.java</exclude>
+ <exclude>**/TestMXML*.java</exclude>
+ <exclude>**/TestRoyaleClass.java</exclude>
+ <exclude>**/TestTypedefsCompile.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <includes>
+ <include>**/TestMXML*.java</include>
+ </includes>
+ <excludes>
+ <exclude>**/TestTypedefsCompile.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.5.0</version>
+ <executions>
+ <execution>
+ <id>generate-test-js-typedefs</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>org.apache.royale.compiler.clients.EXTERNC</arguments>
+ <argument>-load-config+=../compiler-externc/src/test/config/externc-config.xml</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-test-js-swc</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>org.apache.royale.compiler.clients.COMPJSC</arguments>
+ <argument>-targets=SWF</argument>
+ <argument>-load-config+=../compiler-externc/target/compile-as-config.xml</argument>
+ <argument>-output=../compiler-externc/target/js.swc</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-test-custom-swc</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>org.apache.royale.compiler.clients.COMPJSC</arguments>
+ <argument>-load-config+=target/compile-js-config.xml</argument>
+ <argument>-output=target/custom.swc</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-common</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-externc</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.11</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
+
+ <dependency>
+ <groupId>args4j</groupId>
+ <artifactId>args4j</artifactId>
+ <version>2.33</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.javascript</groupId>
+ <artifactId>closure-compiler</artifactId>
+ <version>v20181210</version>
+ </dependency>
+ <dependency>
+ <groupId>org.clojure</groupId>
+ <artifactId>google-closure-library</artifactId>
+ <version>0.0-20170809-b9c14c6b</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-test-utils</artifactId>
+ <version>0.9.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-externc</artifactId>
+ <version>0.9.6</version>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+
+ </dependencies>
+
+</project>
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/CollapsePropertiesWithModuleSupport.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/CollapsePropertiesWithModuleSupport.java
new file mode 100644
index 0000000..2593e82
--- /dev/null
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/CollapsePropertiesWithModuleSupport.java
@@ -0,0 +1,1035 @@
+/*
+ * Copyright 2006 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.javascript.jscomp;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.io.Files;
+import com.google.javascript.jscomp.CompilerOptions.PropertyCollapseLevel;
+import com.google.javascript.jscomp.GlobalNamespace.Name;
+import com.google.javascript.jscomp.GlobalNamespace.Ref;
+import com.google.javascript.jscomp.Normalize.PropagateConstantAnnotationsOverVars;
+import com.google.javascript.rhino.IR;
+import com.google.javascript.rhino.InputId;
+import com.google.javascript.rhino.JSDocInfo;
+import com.google.javascript.rhino.Node;
+import com.google.javascript.rhino.Token;
+import com.google.javascript.rhino.TokenStream;
+import com.google.javascript.rhino.jstype.JSType;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Apache Royale copied CollapseProperties and modified it to handle
+ * Royale modules.
+ *
+ * Flattens global objects/namespaces by replacing each '.' with '$' in
+ * their names. This reduces the number of property lookups the browser has
+ * to do and allows the {@link RenameVars} pass to shorten namespaced names.
+ * For example, goog.events.handleEvent() -> goog$events$handleEvent() -> Za().
+ *
+ * <p>If a global object's name is assigned to more than once, or if a property
+ * is added to the global object in a complex expression, then none of its
+ * properties will be collapsed (for safety/correctness).
+ *
+ * <p>If, after a global object is declared, it is never referenced except when
+ * its properties are read or set, then the object will be removed after its
+ * properties have been collapsed.
+ *
+ * <p>Uninitialized variable stubs are created at a global object's declaration
+ * site for any of its properties that are added late in a local scope.
+ *
+ * <p> Static properties of constructors are always collapsed, unsafely!
+ * For other objects: if, after an object is declared, it is referenced directly
+ * in a way that might create an alias for it, then none of its properties will
+ * be collapsed.
+ * This behavior is a safeguard to prevent the values associated with the
+ * flattened names from getting out of sync with the object's actual property
+ * values. For example, in the following case, an alias a$b, if created, could
+ * easily keep the value 0 even after a.b became 5:
+ * <code> a = {b: 0}; c = a; c.b = 5; </code>.
+ *
+ * <p>This pass doesn't flatten property accesses of the form: a[b].
+ *
+ * <p>For lots of examples, see the unit test.
+ *
+ */
+class CollapsePropertiesWithModuleSupport implements CompilerPass {
+ // Warnings
+ static final DiagnosticType UNSAFE_NAMESPACE_WARNING =
+ DiagnosticType.warning(
+ "JSC_UNSAFE_NAMESPACE",
+ "incomplete alias created for namespace {0}");
+
+ static final DiagnosticType NAMESPACE_REDEFINED_WARNING =
+ DiagnosticType.warning(
+ "JSC_NAMESPACE_REDEFINED",
+ "namespace {0} should not be redefined");
+
+ static final DiagnosticType UNSAFE_THIS = DiagnosticType.warning(
+ "JSC_UNSAFE_THIS",
+ "dangerous use of ''this'' in static method {0}");
+
+ private final AbstractCompiler compiler;
+ private final PropertyCollapseLevel propertyCollapseLevel;
+
+ /** Global namespace tree */
+ private List<Name> globalNames;
+
+ /** Maps names (e.g. "a.b.c") to nodes in the global namespace tree */
+ private Map<String, Name> nameMap;
+
+ /** name of a source file we can use to inject other code */
+ private String sourceFileName;
+
+ /** name of the file of renamed variables */
+ private File varRenameMapFile;
+
+ /** list of renamed variables */
+ private ArrayList<String> renamedVars = null;
+
+ /** list of aliases that are also in externs */
+ private List<String> externAliases;
+
+ /** list of aliases that came from goog.provides */
+ private List<String> providedAliases = new ArrayList<String>();
+
+ /** list of namespaces that came from goog.provides */
+ private List<String> providedNamespaces = new ArrayList<String>();
+
+ CollapsePropertiesWithModuleSupport(AbstractCompiler compiler, PropertyCollapseLevel propertyCollapseLevel, String sourceFileName, File varRenameMapFile) {
+ this.compiler = compiler;
+ this.propertyCollapseLevel = propertyCollapseLevel;
+ this.varRenameMapFile = varRenameMapFile;
+ this.sourceFileName = sourceFileName;
+ }
+
+ @Override
+ public void process(Node externs, Node root) {
+ // ProcessClosurePrimitives runs first and builds up an initial list of
+ // namespaces from goog.provides that were also in externs.
+ externAliases = ProcessClosurePrimitivesWithModuleSupport.externedAliases.get(externs);
+ int n = externAliases.size();
+ for (int i = 0; i < n; i++)
+ {
+ String s = externAliases.get(i);
+ String t = s.replace(".", "$");
+ externAliases.set(i, t);
+ }
+ // ProcessClosurePrimitives runs first and builds up an initial list of
+ // namespaces from goog.provides.
+ providedAliases = ProcessClosurePrimitivesWithModuleSupport.providedsMap.get(externs);
+ providedNamespaces.addAll(providedAliases);
+ n = providedAliases.size();
+ for (int i = 0; i < n; i++)
+ {
+ String s = providedAliases.get(i);
+ String t = s.replace(".", "$");
+ providedAliases.set(i, t);
+ }
+ /*
+ * The goal is to use knowledge of the aliases and which are externed
+ * to eliminate warnings and allow aliases in more places than
+ * closure compiler would normally. Closure compiler doesn't want to
+ * collapse things found in externs, but we want to collapse
+ * them to save size and need to collapse them when there are
+ * overrides in the module of a collapsed property in code
+ * in the main app. Or when the code in the main app is calling
+ * via an interface and code in the module implements that
+ * interface.
+ */
+
+ GlobalNamespace namespace = new GlobalNamespace(compiler, externs, root);
+ nameMap = namespace.getNameIndex();
+ globalNames = namespace.getNameForest();
+ checkNamespaces();
+
+ for (Name name : globalNames) {
+ flattenReferencesToCollapsibleDescendantNames(name, name.getBaseName());
+ }
+
+ // We collapse property definitions after collapsing property references
+ // because this step can alter the parse tree above property references,
+ // invalidating the node ancestry stored with each reference.
+ for (Name name : globalNames) {
+ collapseDeclarationOfNameAndDescendants(name, name.getBaseName());
+ }
+
+ // This shouldn't be necessary, this pass should already be setting new constants as constant.
+ // TODO(b/64256754): Investigate.
+ (new PropagateConstantAnnotationsOverVars(compiler, false)).process(externs, root);
+ }
+
+
+ private boolean canCollapse(Name name) {
+ if (!name.canCollapse()) {
+ return false;
+ }
+
+ if (propertyCollapseLevel == PropertyCollapseLevel.MODULE_EXPORT && !name.isModuleExport()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ private boolean canEliminate(Name name) {
+ if (!name.canEliminate()) {
+ return false;
+ }
+
+ if (name.props == null
+ || name.props.isEmpty()
+ || propertyCollapseLevel != PropertyCollapseLevel.MODULE_EXPORT) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Runs through all namespaces (prefixes of classes and enums), and checks if any of them have
+ * been used in an unsafe way.
+ */
+ private void checkNamespaces() {
+ for (Name name : nameMap.values()) {
+ if (name.isNamespaceObjectLit()
+ && (name.getAliasingGets() > 0
+ || name.getLocalSets() + name.getGlobalSets() > 1
+ || name.getDeleteProps() > 0)) {
+ boolean initialized = name.getDeclaration() != null;
+ for (Ref ref : name.getRefs()) {
+ if (ref == name.getDeclaration()) {
+ continue;
+ }
+
+ if (ref.type == Ref.Type.DELETE_PROP) {
+ if (initialized) {
+ warnAboutNamespaceRedefinition(name, ref);
+ }
+ } else if (
+ ref.type == Ref.Type.SET_FROM_GLOBAL
+ || ref.type == Ref.Type.SET_FROM_LOCAL) {
+ if (initialized && !isSafeNamespaceReinit(ref) &&
+ !providedNamespaces.contains(name.getFullName())) {
+ warnAboutNamespaceRedefinition(name, ref);
+ }
+
+ initialized = true;
+ } else if (ref.type == Ref.Type.ALIASING_GET) {
+ if (!providedNamespaces.contains(name.getFullName()) &&
+ !ref.name.inExterns())
+ warnAboutNamespaceAliasing(name, ref);
+ }
+ }
+ }
+ }
+ }
+
+ static boolean isSafeNamespaceReinit(Ref ref) {
+ // allow "a = a || {}" or "var a = a || {}" or "var a;"
+ Node valParent = getValueParent(ref);
+ Node val = valParent.getLastChild();
+ if (val != null && val.isOr()) {
+ Node maybeName = val.getFirstChild();
+ if (ref.node.matchesQualifiedName(maybeName)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets the parent node of the value for any assignment to a Name.
+ * For example, in the assignment
+ * {@code var x = 3;}
+ * the parent would be the NAME node.
+ */
+ private static Node getValueParent(Ref ref) {
+ // there are four types of declarations: VARs, LETs, CONSTs, and ASSIGNs
+ Node n = ref.node.getParent();
+ return (n != null && NodeUtil.isNameDeclaration(n)) ? ref.node : ref.node.getParent();
+ }
+
+ /**
+ * Reports a warning because a namespace was aliased.
+ *
+ * @param nameObj A namespace that is being aliased
+ * @param ref The reference that forced the alias
+ */
+ private void warnAboutNamespaceAliasing(Name nameObj, Ref ref) {
+ compiler.report(
+ JSError.make(ref.node,
+ UNSAFE_NAMESPACE_WARNING, nameObj.getFullName()));
+ }
+
+ /**
+ * Reports a warning because a namespace was redefined.
+ *
+ * @param nameObj A namespace that is being redefined
+ * @param ref The reference that set the namespace
+ */
+ private void warnAboutNamespaceRedefinition(Name nameObj, Ref ref) {
+ compiler.report(
+ JSError.make(ref.node,
+ NAMESPACE_REDEFINED_WARNING, nameObj.getFullName()));
+ }
+
+ /**
+ * Flattens all references to collapsible properties of a global name except
+ * their initial definitions. Recurs on subnames.
+ *
+ * @param n An object representing a global name
+ * @param alias The flattened name for {@code n}
+ */
+ private void flattenReferencesToCollapsibleDescendantNames(
+ Name n, String alias) {
+ if (n.props == null || n.isCollapsingExplicitlyDenied()) {
+ return;
+ }
+
+ for (Name p : n.props) {
+ String propAlias = appendPropForAlias(alias, p.getBaseName());
+
+ boolean isAllowedToCollapse =
+ propertyCollapseLevel != PropertyCollapseLevel.MODULE_EXPORT || p.isModuleExport();
+
+ if (isAllowedToCollapse && (p.canCollapse() || wasCollapsed(propAlias) || shouldCollapse(propAlias))) {
+ flattenReferencesTo(p, propAlias);
+ } else if (isAllowedToCollapse
+ && p.isSimpleStubDeclaration()
+ && !p.isCollapsingExplicitlyDenied()) {
+ flattenSimpleStubDeclaration(p, propAlias);
+ }
+
+ flattenReferencesToCollapsibleDescendantNames(p, propAlias);
+ }
+ }
+
+ /**
+ * we should collapse aliases in the module no matter what.
+ *
+ * @param propAlias The alias being considered.
+ * @return true If alias is for a namespace provided in the module.
+ */
+ private boolean shouldCollapse(String propAlias) {
+ if (providedAliases.contains(propAlias))
+ {
+ InputId inputId = new InputId(
+ sourceFileName);
+ CompilerInput compilerInput = compiler.getInput(inputId);
+ Node nameNode = IR.name(propAlias);
+ Node child = IR.var(nameNode);
+ compilerInput.getAstRoot(compiler).addChildToBack(child);
+ compiler.reportChangeToEnclosingScope(child);
+ if (!externAliases.contains(propAlias))
+ externAliases.add(propAlias);
+ return true;
+ }
+ return false;
+}
+
+ /**
+ * See if this property was collapse by the loading app.
+ * @param propAlias The alias that might have been collapsed.
+ * @return true If the alias was collapsed in the loading app.
+ */
+ private boolean wasCollapsed(String propAlias) {
+ if (varRenameMapFile == null)
+ return false;
+
+ if (renamedVars == null)
+ {
+ List<String> fileLines;
+
+ renamedVars = new ArrayList<String>();
+ try {
+ fileLines = Files.readLines(varRenameMapFile, Charset.defaultCharset());
+ for (String line : fileLines)
+ {
+ int c = line.indexOf(":");
+ if (c > 0)
+ {
+ renamedVars.add(line.substring(0, c));
+ }
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ if (renamedVars.contains(propAlias) || externAliases.contains(propAlias)) {
+ // if it was collapsed, add a var for it in our source for now.
+ // RemoveUnusedNames will move the var before it gets code-genned.
+ InputId inputId = new InputId(
+ sourceFileName);
+ CompilerInput compilerInput = compiler.getInput(inputId);
+ Node nameNode = IR.name(propAlias);
+ Node child = IR.var(nameNode);
+ compilerInput.getAstRoot(compiler).addChildToBack(child);
+ compiler.reportChangeToEnclosingScope(child);
+ // add it to the list of aliases from the externs so
+ // rename vars can know what variables we created here.
+ if (!externAliases.contains(propAlias))
+ externAliases.add(propAlias);
+ return true;
+ }
+ return false;
+ }
+
+
+ /**
+ * Flattens a stub declaration.
+ * This is mostly a hack to support legacy users.
+ */
+ private void flattenSimpleStubDeclaration(Name name, String alias) {
+ Ref ref = Iterables.getOnlyElement(name.getRefs());
+ Node nameNode = NodeUtil.newName(
+ compiler, alias, ref.node,
+ name.getFullName());
+ Node varNode = IR.var(nameNode).useSourceInfoIfMissingFrom(nameNode);
+
+ checkState(ref.node.getParent().isExprResult());
+ Node parent = ref.node.getParent();
+ Node grandparent = parent.getParent();
+ grandparent.replaceChild(parent, varNode);
+ compiler.reportChangeToEnclosingScope(varNode);
+ }
+
+ /**
+ * Flattens all references to a collapsible property of a global name except
+ * its initial definition.
+ *
+ * @param n A global property name (e.g. "a.b" or "a.b.c.d")
+ * @param alias The flattened name (e.g. "a$b" or "a$b$c$d")
+ */
+ private void flattenReferencesTo(Name n, String alias) {
+ String originalName = n.getFullName();
+ for (Ref r : n.getRefs()) {
+ if (r == n.getDeclaration()) {
+ // Declarations are handled separately.
+ continue;
+ }
+ Node rParent = r.node.getParent();
+ // There are two cases when we shouldn't flatten a reference:
+ // 1) Object literal keys, because duplicate keys show up as refs.
+ // 2) References inside a complex assign. (a = x.y = 0). These are
+ // called TWIN references, because they show up twice in the
+ // reference list. Only collapse the set, not the alias.
+ if (!r.node.isFromExterns() && !NodeUtil.isObjectLitKey(r.node) && (r.getTwin() == null || r.isSet())) {
+ flattenNameRef(alias, r.node, rParent, originalName);
+ }
+ }
+
+ // Flatten all occurrences of a name as a prefix of its subnames. For
+ // example, if {@code n} corresponds to the name "a.b", then "a.b" will be
+ // replaced with "a$b" in all occurrences of "a.b.c", "a.b.c.d", etc.
+ if (n.props != null) {
+ for (Name p : n.props) {
+ flattenPrefixes(alias, p, 1);
+ }
+ }
+ }
+
+ /**
+ * Flattens all occurrences of a name as a prefix of subnames beginning
+ * with a particular subname.
+ *
+ * @param n A global property name (e.g. "a.b.c.d")
+ * @param alias A flattened prefix name (e.g. "a$b")
+ * @param depth The difference in depth between the property name and
+ * the prefix name (e.g. 2)
+ */
+ private void flattenPrefixes(String alias, Name n, int depth) {
+ // Only flatten the prefix of a name declaration if the name being
+ // initialized is fully qualified (i.e. not an object literal key).
+ String originalName = n.getFullName();
+ Ref decl = n.getDeclaration();
+ if (decl != null && decl.node != null && !decl.node.isFromExterns() && decl.node.isGetProp()) {
+ flattenNameRefAtDepth(alias, decl.node, depth, originalName);
+ }
+
+ for (Ref r : n.getRefs()) {
+ if (r == decl) {
+ // Declarations are handled separately.
+ continue;
+ }
+
+ // References inside a complex assign (a = x.y = 0)
+ // have twins. We should only flatten one of the twins.
+ if (r.getTwin() == null || r.isSet()) {
+ if (r.node != null && !r.node.isFromExterns())
+ flattenNameRefAtDepth(alias, r.node, depth, originalName);
+ }
+ }
+
+ if (n.props != null) {
+ for (Name p : n.props) {
+ flattenPrefixes(alias, p, depth + 1);
+ }
+ }
+ }
+
+ /**
+ * Flattens a particular prefix of a single name reference.
+ *
+ * @param alias A flattened prefix name (e.g. "a$b")
+ * @param n The node corresponding to a subproperty name (e.g. "a.b.c.d")
+ * @param depth The difference in depth between the property name and
+ * the prefix name (e.g. 2)
+ * @param originalName String version of the property name.
+ */
+ private void flattenNameRefAtDepth(String alias, Node n, int depth,
+ String originalName) {
+ // This method has to work for both GETPROP chains and, in rare cases,
+ // OBJLIT keys, possibly nested. That's why we check for children before
+ // proceeding. In the OBJLIT case, we don't need to do anything.
+ Token nType = n.getToken();
+ boolean isQName = nType == Token.NAME || nType == Token.GETPROP;
+ boolean isObjKey = NodeUtil.isObjectLitKey(n);
+ checkState(isObjKey || isQName);
+ if (isQName) {
+ for (int i = 1; i < depth && n.hasChildren(); i++) {
+ n = n.getFirstChild();
+ }
+ if (n.isGetProp() && n.getFirstChild().isGetProp()) {
+ flattenNameRef(alias, n.getFirstChild(), n, originalName);
+ }
+ }
+ }
+
+ /**
+ * Replaces a GETPROP a.b.c with a NAME a$b$c.
+ *
+ * @param alias A flattened prefix name (e.g. "a$b")
+ * @param n The GETPROP node corresponding to the original name (e.g. "a.b")
+ * @param parent {@code n}'s parent
+ * @param originalName String version of the property name.
+ */
+ private void flattenNameRef(String alias, Node n, Node parent,
+ String originalName) {
+ Preconditions.checkArgument(
+ n.isGetProp(), "Expected GETPROP, found %s. Node: %s", n.getToken(), n);
+
+ // BEFORE:
+ // getprop
+ // getprop
+ // name a
+ // string b
+ // string c
+ // AFTER:
+ // name a$b$c
+ Node ref = NodeUtil.newName(compiler, alias, n, originalName);
+ NodeUtil.copyNameAnnotations(n.getLastChild(), ref);
+ if (parent != null && parent.isCall() && n == parent.getFirstChild()) {
+ // The node was a call target, we are deliberately flatten these as
+ // we node the "this" isn't provided by the namespace. Mark it as such:
+ parent.putBooleanProp(Node.FREE_CALL, true);
+ }
+
+ JSType type = n.getJSType();
+ if (type != null) {
+ ref.setJSType(type);
+ }
+
+ if (parent == null)
+ {
+ // in some cases parent is null (not sure why)
+ // but ref is a StringNode and a child of n
+ // is a StringNode so replace that StringNode
+ parent = n;
+ n = n.getFirstChild();
+ parent.replaceChild(n, ref);
+ }
+ else
+ {
+ parent.replaceChild(n, ref);
+ Node enclosingScopeNode = NodeUtil.getEnclosingChangeScopeRoot(n.getParent());
+ if (enclosingScopeNode != null)
+ compiler.reportChangeToEnclosingScope(ref);
+ }
+ }
+
+ /**
+ * Collapses definitions of the collapsible properties of a global name.
+ * Recurs on subnames that also represent JavaScript objects with
+ * collapsible properties.
+ *
+ * @param n A node representing a global name
+ * @param alias The flattened name for {@code n}
+ */
+ private void collapseDeclarationOfNameAndDescendants(Name n, String alias) {
+ boolean canCollapseChildNames = n.canCollapseUnannotatedChildNames();
+
+ // Handle this name first so that nested object literals get unrolled.
+ if (canCollapse(n)/* && !externStrings.contains(n.getName())*/) {
+ updateGlobalNameDeclaration(n, alias, canCollapseChildNames);
+ }
+
+ if (n.props == null) {
+ return;
+ }
+ for (Name p : n.props) {
+ collapseDeclarationOfNameAndDescendants(p, appendPropForAlias(alias, p.getBaseName()));
+ }
+ }
+
+ /**
+ * Updates the initial assignment to a collapsible property at global scope
+ * by adding a VAR stub and collapsing the property. e.g. c = a.b = 1; => var a$b; c = a$b = 1;
+ * This specifically handles "twinned" assignments, which are those where the assignment is also
+ * used as a reference and which need special handling.
+ *
+ * @param alias The flattened property name (e.g. "a$b")
+ * @param refName The name for the reference being updated.
+ * @param ref An object containing information about the assignment getting updated
+ */
+ private void updateTwinnedDeclaration(String alias, Name refName, Ref ref) {
+ checkNotNull(ref.getTwin());
+ // Don't handle declarations of an already flat name, just qualified names.
+ if (!ref.node.isGetProp()) {
+ return;
+ }
+ Node rvalue = ref.node.getNext();
+ Node parent = ref.node.getParent();
+ Node grandparent = parent.getParent();
+
+ if (rvalue != null && rvalue.isFunction()) {
+ checkForHosedThisReferences(rvalue, refName.docInfo, refName);
+ }
+
+ // Create the new alias node.
+ Node nameNode =
+ NodeUtil.newName(compiler, alias, grandparent.getFirstChild(), refName.getFullName());
+ NodeUtil.copyNameAnnotations(ref.node.getLastChild(), nameNode);
+
+ // BEFORE:
+ // ... (x.y = 3);
+ //
+ // AFTER:
+ // var x$y;
+ // ... (x$y = 3);
+
+ Node current = grandparent;
+ Node currentParent = grandparent.getParent();
+ for (;
+ !currentParent.isScript() && !currentParent.isBlock();
+ current = currentParent, currentParent = currentParent.getParent()) {}
+
+ // Create a stub variable declaration right
+ // before the current statement.
+ Node stubVar = IR.var(nameNode.cloneTree()).useSourceInfoIfMissingFrom(nameNode);
+ currentParent.addChildBefore(stubVar, current);
+
+ parent.replaceChild(ref.node, nameNode);
+ compiler.reportChangeToEnclosingScope(nameNode);
+ }
+
+ /**
+ * Updates the first initialization (a.k.a "declaration") of a global name.
+ * This involves flattening the global name (if it's not just a global
+ * variable name already), collapsing object literal keys into global
+ * variables, declaring stub global variables for properties added later
+ * in a local scope.
+ *
+ * It may seem odd that this function also takes care of declaring stubs
+ * for direct children. The ultimate goal of this function is to eliminate
+ * the global name entirely (when possible), so that "middlemen" namespaces
+ * disappear, and to do that we need to make sure that all the direct children
+ * will be collapsed as well.
+ *
+ * @param n An object representing a global name (e.g. "a", "a.b.c")
+ * @param alias The flattened name for {@code n} (e.g. "a", "a$b$c")
+ * @param canCollapseChildNames Whether it's possible to collapse children of
+ * this name. (This is mostly passed for convenience; it's equivalent to
+ * n.canCollapseChildNames()).
+ */
+ private void updateGlobalNameDeclaration(
+ Name n, String alias, boolean canCollapseChildNames) {
+ Ref decl = n.getDeclaration();
+ if (decl == null) {
+ // Some names do not have declarations, because they
+ // are only defined in local scopes.
+ return;
+ }
+
+ if (decl.node == null)
+ return; // package stubs (org.apache.royale)
+
+ switch (decl.node.getParent().getToken()) {
+ case ASSIGN:
+ updateGlobalNameDeclarationAtAssignNode(
+ n, alias, canCollapseChildNames);
+ break;
+ case VAR:
+ case LET:
+ case CONST:
+ updateGlobalNameDeclarationAtVariableNode(n, canCollapseChildNames);
+ break;
+ case FUNCTION:
+ updateGlobalNameDeclarationAtFunctionNode(n, canCollapseChildNames);
+ break;
+ case CLASS:
+ updateGlobalNameDeclarationAtClassNode(n, canCollapseChildNames);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Updates the first initialization (a.k.a "declaration") of a global name
+ * that occurs at an ASSIGN node. See comment for
+ * {@link #updateGlobalNameDeclaration}.
+ *
+ * @param n An object representing a global name (e.g. "a", "a.b.c")
+ * @param alias The flattened name for {@code n} (e.g. "a", "a$b$c")
+ */
+ private void updateGlobalNameDeclarationAtAssignNode(
+ Name n, String alias, boolean canCollapseChildNames) {
+ // NOTE: It's important that we don't add additional nodes
+ // (e.g. a var node before the exprstmt) because the exprstmt might be
+ // the child of an if statement that's not inside a block).
+
+ // All qualified names - even for variables that are initially declared as LETS and CONSTS -
+ // are being declared as VAR statements, but this is not incorrect because
+ // we are only collapsing for global names.
+ Ref ref = n.getDeclaration();
+ Node rvalue = ref.node.getNext();
+ if (ref.getTwin() != null) {
+ updateTwinnedDeclaration(alias, ref.name, ref);
+ return;
+ }
+ Node varNode = new Node(Token.VAR);
+ Node varParent = ref.node.getAncestor(3);
+ Node grandparent = ref.node.getAncestor(2);
+ boolean isObjLit = rvalue.isObjectLit();
+ boolean insertedVarNode = false;
+
+ if (isObjLit && canEliminate(n)) {
+ // Eliminate the object literal altogether.
+ varParent.replaceChild(grandparent, varNode);
+ ref.node = null;
+ insertedVarNode = true;
+ compiler.reportChangeToEnclosingScope(varNode);
+ } else if (!n.isSimpleName()) {
+ // Create a VAR node to declare the name.
+ if (rvalue.isFunction()) {
+ checkForHosedThisReferences(rvalue, n.docInfo, n);
+ }
+
+ compiler.reportChangeToEnclosingScope(rvalue);
+ ref.node.getParent().removeChild(rvalue);
+
+ Node nameNode = NodeUtil.newName(compiler,
+ alias, ref.node.getAncestor(2), n.getFullName());
+
+ JSDocInfo info = NodeUtil.getBestJSDocInfo(ref.node.getParent());
+ if (ref.node.getLastChild().getBooleanProp(Node.IS_CONSTANT_NAME)
+ || (info != null && info.isConstant())) {
+ nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
+ }
+
+ if (info != null) {
+ varNode.setJSDocInfo(info);
+ }
+ varNode.addChildToBack(nameNode);
+ nameNode.addChildToFront(rvalue);
+ varParent.replaceChild(grandparent, varNode);
+
+ // Update the node ancestry stored in the reference.
+ ref.node = nameNode;
+ insertedVarNode = true;
+ compiler.reportChangeToEnclosingScope(varNode);
+ }
+
+ if (canCollapseChildNames) {
+ if (isObjLit) {
+ declareVariablesForObjLitValues(
+ n, alias, rvalue, varNode, varNode.getPrevious(), varParent);
+ }
+
+ addStubsForUndeclaredProperties(n, alias, varParent, varNode);
+ }
+
+ if (insertedVarNode) {
+ if (!varNode.hasChildren()) {
+ varParent.removeChild(varNode);
+ }
+ }
+ }
+
+ /**
+ * Warns about any references to "this" in the given FUNCTION. The function
+ * is getting collapsed, so the references will change.
+ */
+ private void checkForHosedThisReferences(Node function, JSDocInfo docInfo,
+ final Name name) {
+ // A function is getting collapsed. Make sure that if it refers to "this",
+ // it must be a constructor, interface, record, arrow function, or documented with @this.
+ boolean isAllowedToReferenceThis =
+ (docInfo != null && (docInfo.isConstructorOrInterface() || docInfo.hasThisType()))
+ || function.isArrowFunction();
+ if (!isAllowedToReferenceThis) {
+ NodeTraversal.traverse(compiler, function.getLastChild(),
+ new NodeTraversal.AbstractShallowCallback() {
+ @Override
+ public void visit(NodeTraversal t, Node n, Node parent) {
+ if (n.isThis()) {
+ compiler.report(
+ JSError.make(n, UNSAFE_THIS, name.getFullName()));
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Updates the first initialization (a.k.a "declaration") of a global name that occurs at a VAR
+ * node. See comment for {@link #updateGlobalNameDeclaration}.
+ *
+ * @param n An object representing a global name (e.g. "a")
+ */
+ private void updateGlobalNameDeclarationAtVariableNode(
+ Name n, boolean canCollapseChildNames) {
+ if (!canCollapseChildNames) {
+ return;
+ }
+
+ Ref ref = n.getDeclaration();
+ String name = ref.node.getString();
+ Node rvalue = ref.node.getFirstChild();
+ Node variableNode = ref.node.getParent();
+ Node grandparent = variableNode.getParent();
+
+ boolean isObjLit = rvalue.isObjectLit();
+
+ if (isObjLit) {
+ declareVariablesForObjLitValues(
+ n, name, rvalue, variableNode, variableNode.getPrevious(), grandparent);
+ }
+
+ addStubsForUndeclaredProperties(n, name, grandparent, variableNode);
+
+ if (isObjLit && canEliminate(n)) {
+ variableNode.removeChild(ref.node);
+ compiler.reportChangeToEnclosingScope(variableNode);
+ if (!variableNode.hasChildren()) {
+ grandparent.removeChild(variableNode);
+ }
+
+ // Clear out the object reference, since we've eliminated it from the
+ // parse tree.
+ ref.node = null;
+ }
+ }
+
+ /**
+ * Updates the first initialization (a.k.a "declaration") of a global name
+ * that occurs at a FUNCTION node. See comment for
+ * {@link #updateGlobalNameDeclaration}.
+ *
+ * @param n An object representing a global name (e.g. "a")
+ */
+ private void updateGlobalNameDeclarationAtFunctionNode(
+ Name n, boolean canCollapseChildNames) {
+ if (!canCollapseChildNames || !canCollapse(n)) {
+ return;
+ }
+
+ Ref ref = n.getDeclaration();
+ String fnName = ref.node.getString();
+ addStubsForUndeclaredProperties(n, fnName, ref.node.getAncestor(2), ref.node.getParent());
+ }
+
+ /**
+ * Updates the first initialization (a.k.a "declaration") of a global name that occurs at a CLASS
+ * node. See comment for {@link #updateGlobalNameDeclaration}.
+ *
+ * @param n An object representing a global name (e.g. "a")
+ */
+ private void updateGlobalNameDeclarationAtClassNode(Name n, boolean canCollapseChildNames) {
+ if (!canCollapseChildNames || !canCollapse(n)) {
+ return;
+ }
+
+ Ref ref = n.getDeclaration();
+ String className = ref.node.getString();
+ addStubsForUndeclaredProperties(
+ n, className, ref.node.getAncestor(2), ref.node.getParent());
+ }
+
+ /**
+ * Declares global variables to serve as aliases for the values in an object literal, optionally
+ * removing all of the object literal's keys and values.
+ *
+ * @param alias The object literal's flattened name (e.g. "a$b$c")
+ * @param objlit The OBJLIT node
+ * @param varNode The VAR node to which new global variables should be added as children
+ * @param nameToAddAfter The child of {@code varNode} after which new variables should be added
+ * (may be null)
+ * @param varParent {@code varNode}'s parent
+ */
+ private void declareVariablesForObjLitValues(
+ Name objlitName,
+ String alias,
+ Node objlit,
+ Node varNode,
+ Node nameToAddAfter,
+ Node varParent) {
+ int arbitraryNameCounter = 0;
+ boolean discardKeys = !objlitName.shouldKeepKeys();
+
+ for (Node key = objlit.getFirstChild(), nextKey; key != null;
+ key = nextKey) {
+ Node value = key.getFirstChild();
+ nextKey = key.getNext();
+
+ // A computed property, or a get or a set can not be rewritten as a VAR.
+ if (key.isGetterDef() || key.isSetterDef() || key.isComputedProp()) {
+ continue;
+ }
+
+ // We generate arbitrary names for keys that aren't valid JavaScript
+ // identifiers, since those keys are never referenced. (If they were,
+ // this object literal's child names wouldn't be collapsible.) The only
+ // reason that we don't eliminate them entirely is the off chance that
+ // their values are expressions that have side effects.
+ boolean isJsIdentifier = !key.isNumber() && TokenStream.isJSIdentifier(key.getString());
+ String propName = isJsIdentifier ? key.getString() : String.valueOf(++arbitraryNameCounter);
+
+ // If the name cannot be collapsed, skip it.
+ String qName = objlitName.getFullName() + '.' + propName;
+ Name p = nameMap.get(qName);
+ if (p != null && !canCollapse(p)) {
+ continue;
+ }
+
+ String propAlias = appendPropForAlias(alias, propName);
+ Node refNode = null;
+ if (discardKeys) {
+ objlit.removeChild(key);
+ value.detach();
+ // Don't report a change here because the objlit has already been removed from the tree.
+ } else {
+ // Substitute a reference for the value.
+ refNode = IR.name(propAlias);
+ if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
+ refNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
+ }
+
+ key.replaceChild(value, refNode);
+ compiler.reportChangeToEnclosingScope(refNode);
+ }
+
+ // Declare the collapsed name as a variable with the original value.
+ Node nameNode = IR.name(propAlias);
+ nameNode.addChildToFront(value);
+ if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
+ nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
+ }
+ Node newVar = IR.var(nameNode).useSourceInfoIfMissingFromForTree(key);
+ if (nameToAddAfter != null) {
+ varParent.addChildAfter(newVar, nameToAddAfter);
+ } else {
+ varParent.addChildBefore(newVar, varNode);
+ }
+ compiler.reportChangeToEnclosingScope(newVar);
+ nameToAddAfter = newVar;
+
+ // Update the global name's node ancestry if it hasn't already been
+ // done. (Duplicate keys in an object literal can bring us here twice
+ // for the same global name.)
+ if (isJsIdentifier && p != null) {
+ if (!discardKeys) {
+ Ref newAlias =
+ p.getDeclaration().cloneAndReclassify(Ref.Type.ALIASING_GET);
+ newAlias.node = refNode;
+ p.addRef(newAlias);
+ }
+
+ p.getDeclaration().node = nameNode;
+
+ if (value.isFunction()) {
+ checkForHosedThisReferences(value, key.getJSDocInfo(), p);
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds global variable "stubs" for any properties of a global name that are only set in a local
+ * scope or read but never set.
+ *
+ * @param n An object representing a global name (e.g. "a", "a.b.c")
+ * @param alias The flattened name of the object whose properties we are adding stubs for (e.g.
+ * "a$b$c")
+ * @param parent The node to which new global variables should be added as children
+ * @param addAfter The child of after which new variables should be added
+ */
+ private void addStubsForUndeclaredProperties(Name n, String alias, Node parent, Node addAfter) {
+ checkState(n.canCollapseUnannotatedChildNames(), n);
+ checkArgument(NodeUtil.isStatementBlock(parent), parent);
+ checkNotNull(addAfter);
+ if (n.props == null) {
+ return;
+ }
+ for (Name p : n.props) {
+ if (p.needsToBeStubbed()) {
+ String propAlias = appendPropForAlias(alias, p.getBaseName());
+ Node nameNode = IR.name(propAlias);
+ Node newVar = IR.var(nameNode).useSourceInfoIfMissingFromForTree(addAfter);
+ parent.addChildAfter(newVar, addAfter);
+ addAfter = newVar;
+ compiler.reportChangeToEnclosingScope(newVar);
+ // Determine if this is a constant var by checking the first
+ // reference to it. Don't check the declaration, as it might be null.
+ if (p.getRefs().get(0).node.getLastChild().getBooleanProp(
+ Node.IS_CONSTANT_NAME)) {
+ nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
+ compiler.reportChangeToEnclosingScope(nameNode);
+ }
+ }
+ }
+ }
+
+ private String appendPropForAlias(String root, String prop) {
+ if (prop.indexOf('$') != -1) {
+ // Encode '$' in a property as '$0'. Because '0' cannot be the
+ // start of an identifier, this will never conflict with our
+ // encoding from '.' -> '$'.
+ prop = prop.replace("$", "$0");
+ }
+ String result = root + '$' + prop;
+ int id = 1;
+ while (nameMap.containsKey(result)) {
+ result = root + '$' + prop + '$' + id;
+ id++;
+ }
+ return result;
+ }
+}
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/CompilerMapFetcher.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/CompilerMapFetcher.java
index 5fbb7ae..a9c818b 100644
--- a/compiler-jx/src/main/java/com/google/javascript/jscomp/CompilerMapFetcher.java
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/CompilerMapFetcher.java
@@ -22,7 +22,7 @@
public class CompilerMapFetcher
{
- private static final long serialVersionUID = 2021530437904249081L;
+ //private static final long serialVersionUID = 2021530437904249081L;
public CompilerMapFetcher()
{
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/ProcessClosurePrimitivesWithModuleSupport.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/ProcessClosurePrimitivesWithModuleSupport.java
new file mode 100644
index 0000000..68ee660
--- /dev/null
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/ProcessClosurePrimitivesWithModuleSupport.java
@@ -0,0 +1,1811 @@
+/*
+ * Copyright 2006 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.javascript.jscomp;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.javascript.jscomp.ClosurePrimitiveErrors.INVALID_CLOSURE_CALL_SCOPE_ERROR;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
+import com.google.javascript.jscomp.GlobalNamespace.Name;
+import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
+import com.google.javascript.jscomp.parsing.JsDocInfoParser;
+import com.google.javascript.rhino.IR;
+import com.google.javascript.rhino.JSDocInfo;
+import com.google.javascript.rhino.JSDocInfoBuilder;
+import com.google.javascript.rhino.JSTypeExpression;
+import com.google.javascript.rhino.Node;
+import com.google.javascript.rhino.Token;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import javax.annotation.Nullable;
+
+/**
+ * Apache Royale copied ProcessClosurePrimitives and modified it to handle
+ * Royale modules.
+ *
+ * Replaces goog.provide calls, removes goog.{require,requireType} calls, verifies that each
+ * goog.{require,requireType} has a corresponding goog.provide, and performs some Closure-pecific
+ * simplifications.
+ *
+ * @author chrisn@google.com (Chris Nokleberg)
+ */
+class ProcessClosurePrimitivesWithModuleSupport extends AbstractPostOrderCallback implements HotSwapCompilerPass {
+
+ static final DiagnosticType NULL_ARGUMENT_ERROR = DiagnosticType.error(
+ "JSC_NULL_ARGUMENT_ERROR",
+ "method \"{0}\" called without an argument");
+
+ static final DiagnosticType EXPECTED_OBJECTLIT_ERROR = DiagnosticType.error(
+ "JSC_EXPECTED_OBJECTLIT_ERROR",
+ "method \"{0}\" expected an object literal argument");
+
+ static final DiagnosticType EXPECTED_STRING_ERROR =
+ DiagnosticType.error(
+ "JSC_EXPECTED_STRING_ERROR", "method \"{0}\" expected a string argument");
+
+ static final DiagnosticType INVALID_ARGUMENT_ERROR = DiagnosticType.error(
+ "JSC_INVALID_ARGUMENT_ERROR",
+ "method \"{0}\" called with invalid argument");
+
+ static final DiagnosticType INVALID_STYLE_ERROR = DiagnosticType.error(
+ "JSC_INVALID_CSS_NAME_MAP_STYLE_ERROR",
+ "Invalid CSS name map style {0}");
+
+ static final DiagnosticType TOO_MANY_ARGUMENTS_ERROR = DiagnosticType.error(
+ "JSC_TOO_MANY_ARGUMENTS_ERROR",
+ "method \"{0}\" called with more than one argument");
+
+ static final DiagnosticType DUPLICATE_NAMESPACE_ERROR =
+ DiagnosticType.error(
+ "JSC_DUPLICATE_NAMESPACE_ERROR",
+ "namespace \"{0}\" cannot be provided twice\n" //
+ + "Originally provided at {1}");
+
+ static final DiagnosticType WEAK_NAMESPACE_TYPE = DiagnosticType.warning(
+ "JSC_WEAK_NAMESPACE_TYPE",
+ "Provided symbol declared with type Object. This is rarely useful. "
+ + "For more information see "
+ + "https://github.com/google/closure-compiler/wiki/A-word-about-the-type-Object");
+
+ static final DiagnosticType CLASS_NAMESPACE_ERROR = DiagnosticType.error(
+ "JSC_CLASS_NAMESPACE_ERROR",
+ "\"{0}\" cannot be both provided and declared as a class. Try var {0} = class '{'...'}'");
+
+ static final DiagnosticType FUNCTION_NAMESPACE_ERROR = DiagnosticType.error(
+ "JSC_FUNCTION_NAMESPACE_ERROR",
+ "\"{0}\" cannot be both provided and declared as a function");
+
+ static final DiagnosticType MISSING_PROVIDE_ERROR = DiagnosticType.error(
+ "JSC_MISSING_PROVIDE_ERROR",
+ "required \"{0}\" namespace never provided");
+
+ static final DiagnosticType LATE_PROVIDE_ERROR = DiagnosticType.error(
+ "JSC_LATE_PROVIDE_ERROR",
+ "required \"{0}\" namespace not provided yet");
+
+ static final DiagnosticType INVALID_PROVIDE_ERROR = DiagnosticType.error(
+ "JSC_INVALID_PROVIDE_ERROR",
+ "\"{0}\" is not a valid {1} qualified name");
+
+ static final DiagnosticType INVALID_DEFINE_NAME_ERROR = DiagnosticType.error(
+ "JSC_INVALID_DEFINE_NAME_ERROR",
+ "\"{0}\" is not a valid JS identifier name");
+
+ static final DiagnosticType MISSING_DEFINE_ANNOTATION = DiagnosticType.error(
+ "JSC_INVALID_MISSING_DEFINE_ANNOTATION",
+ "Missing @define annotation");
+
+ static final DiagnosticType XMODULE_REQUIRE_ERROR =
+ DiagnosticType.warning(
+ "JSC_XMODULE_REQUIRE_ERROR",
+ "namespace \"{0}\" is required in module {2} but provided in module {1}."
+ + " Is module {2} missing a dependency on module {1}?");
+
+ static final DiagnosticType NON_STRING_PASSED_TO_SET_CSS_NAME_MAPPING_ERROR =
+ DiagnosticType.error(
+ "JSC_NON_STRING_PASSED_TO_SET_CSS_NAME_MAPPING_ERROR",
+ "goog.setCssNameMapping only takes an object literal with string values");
+
+ static final DiagnosticType INVALID_CSS_RENAMING_MAP = DiagnosticType.warning(
+ "INVALID_CSS_RENAMING_MAP",
+ "Invalid entries in css renaming map: {0}");
+
+ static final DiagnosticType GOOG_BASE_CLASS_ERROR = DiagnosticType.error(
+ "JSC_GOOG_BASE_CLASS_ERROR",
+ "incorrect use of goog.base: {0}");
+
+ static final DiagnosticType BASE_CLASS_ERROR = DiagnosticType.error(
+ "JSC_BASE_CLASS_ERROR",
+ "incorrect use of {0}.base: {1}");
+
+ static final DiagnosticType CLOSURE_DEFINES_ERROR = DiagnosticType.error(
+ "JSC_CLOSURE_DEFINES_ERROR",
+ "Invalid CLOSURE_DEFINES definition");
+
+ static final DiagnosticType INVALID_FORWARD_DECLARE = DiagnosticType.error(
+ "JSC_INVALID_FORWARD_DECLARE",
+ "Malformed goog.forwardDeclaration");
+
+ static final DiagnosticType USE_OF_GOOG_BASE = DiagnosticType.disabled(
+ "JSC_USE_OF_GOOG_BASE",
+ "goog.base is not compatible with ES5 strict mode.\n"
+ + "Please use an alternative.\n"
+ + "For EcmaScript classes use the super keyword. For traditional Closure classes,\n"
+ + "use the class specific base method instead. For example, for the constructor MyClass:\n"
+ + " MyClass.base(this, ''constructor'')");
+
+ static final DiagnosticType CLOSURE_CALL_CANNOT_BE_ALIASED_ERROR =
+ DiagnosticType.error(
+ "JSC_CLOSURE_CALL_CANNOT_BE_ALIASED_ERROR",
+ "Closure primitive method {0} may not be aliased");
+
+ static final DiagnosticType CLOSURE_CALL_CANNOT_BE_ALIASED_OUTSIDE_MODULE_ERROR =
+ DiagnosticType.error(
+ "JSC_CLOSURE_CALL_CANNOT_BE_ALIASED_ERROR",
+ "Closure primitive method {0} may not be aliased outside a module (ES "
+ + "module, CommonJS module, or goog.module)");
+
+ /** The root Closure namespace */
+ static final String GOOG = "goog";
+
+ private final AbstractCompiler compiler;
+ private final JSModuleGraph moduleGraph;
+
+ // The goog.provides must be processed in a deterministic order.
+ private final Map<String, ProvidedName> providedNames = new LinkedHashMap<String, ProvidedName>();
+
+ private final Set<String> knownClosureSubclasses = new HashSet<String>();
+
+ private final List<UnrecognizedRequire> unrecognizedRequires = new ArrayList<UnrecognizedRequire>();
+ private final Set<String> exportedVariables = new HashSet<String>();
+ private final CheckLevel requiresLevel;
+ private final PreprocessorSymbolTable preprocessorSymbolTable;
+ private final List<Node> defineCalls = new ArrayList<Node>();
+ private final boolean preserveGoogProvidesAndRequires;
+ private final List<Node> requiresToBeRemoved = new ArrayList<Node>();
+ private final Set<Node> maybeTemporarilyLiveNodes = new HashSet<Node>();
+
+ ProcessClosurePrimitivesWithModuleSupport(AbstractCompiler compiler,
+ @Nullable PreprocessorSymbolTable preprocessorSymbolTable,
+ CheckLevel requiresLevel,
+ boolean preserveGoogProvidesAndRequires) {
+ this.compiler = compiler;
+ this.preprocessorSymbolTable = preprocessorSymbolTable;
+ this.moduleGraph = compiler.getModuleGraph();
+ this.requiresLevel = requiresLevel;
+ this.preserveGoogProvidesAndRequires = preserveGoogProvidesAndRequires;
+
+ // goog is special-cased because it is provided in Closure's base library.
+ providedNames.put(GOOG,
+ new ProvidedName(GOOG, null, null, false /* implicit */));
+ }
+
+ Set<String> getExportedVariableNames() {
+ return exportedVariables;
+ }
+
+ /** list of strings from the externs */
+ private ArrayList<String> externStrings = new ArrayList<String>();
+
+ /** a map extern node trees to their list of vars that are in the externs but also renamed/aliased */
+ public static WeakHashMap<Node, List<String>> externedAliases = new WeakHashMap<Node, List<String>>();
+
+ /** list of namespaces that are in the externs but also renamed/aliased */
+ private ArrayList<String> externAliases = new ArrayList<String>();
+
+ /** a map extern node trees to the processed goog.provides */
+ public static WeakHashMap<Node, List<String>> providedsMap = new WeakHashMap<Node, List<String>>();
+
+ /** list of namespaces that are goog.provided */
+ private ArrayList<String> provideds = new ArrayList<String>();
+
+ @Override
+ public void process(Node externs, Node root) {
+ /*
+ * ApacheRoyale: build list of namespaces from externs
+ */
+ GlobalNamespace externNamespace = new GlobalNamespace(compiler, externs);
+ List<Name> externNames = externNamespace.getNameForest();
+ for (Name en : externNames) {
+ addExternNameAndDescendants(en, externStrings);
+ }
+ externedAliases.put(externs, externAliases);
+ providedsMap.put(externs, provideds);
+
+ NodeTraversal.traverseRoots(compiler, this, externs, root);
+
+ for (Node n : defineCalls) {
+ replaceGoogDefines(n);
+ }
+
+ for (ProvidedName pn : providedNames.values()) {
+ pn.replace();
+ }
+
+ if (requiresLevel.isOn()) {
+ for (UnrecognizedRequire r : unrecognizedRequires) {
+ checkForLateOrMissingProvide(r);
+ }
+ }
+
+ for (Node closureRequire : requiresToBeRemoved) {
+ compiler.reportChangeToEnclosingScope(closureRequire);
+ closureRequire.detach();
+ }
+ for (Node liveNode : maybeTemporarilyLiveNodes) {
+ compiler.reportChangeToEnclosingScope(liveNode);
+ }
+ }
+
+ private void checkForLateOrMissingProvide(UnrecognizedRequire r) {
+ // Both goog.require and goog.requireType must have a matching goog.provide.
+ // However, goog.require must match an earlier goog.provide, while goog.requireType is allowed
+ // to match a later goog.provide.
+ DiagnosticType error;
+ ProvidedName expectedName = providedNames.get(r.namespace);
+ if (expectedName != null && expectedName.firstNode != null) {
+ if (r.isRequireType) {
+ return;
+ }
+ error = LATE_PROVIDE_ERROR;
+ } else {
+ error = MISSING_PROVIDE_ERROR;
+ }
+ compiler.report(JSError.make(r.requireNode, requiresLevel, error, r.namespace));
+ }
+
+ private Node getAnyValueOfType(JSDocInfo jsdoc) {
+ checkArgument(jsdoc.hasType());
+ Node typeAst = jsdoc.getType().getRoot();
+ if (typeAst.getToken() == Token.BANG) {
+ typeAst = typeAst.getLastChild();
+ }
+ checkState(typeAst.isString(), typeAst);
+ /** Converted switch to else/if for Java 1.6 compatibility */
+ String astType = typeAst.getString();
+ if (astType.contentEquals("boolean"))
+ return IR.falseNode();
+ if (astType.contentEquals("string"))
+ return IR.string("");
+ if (astType.contentEquals("number"))
+ return IR.number(0);
+
+ throw new RuntimeException(typeAst.getString());
+ }
+
+ /**
+ * @param n
+ */
+ private void replaceGoogDefines(Node n) {
+ Node parent = n.getParent();
+ checkState(parent.isExprResult());
+ String name = n.getSecondChild().getString();
+ JSDocInfo jsdoc = n.getJSDocInfo();
+ Node value =
+ n.isFromExterns() ? getAnyValueOfType(jsdoc).srcref(n) : n.getChildAtIndex(2).detach();
+
+ Node replacement = NodeUtil.newQNameDeclaration(compiler, name, value, jsdoc);
+ replacement.useSourceInfoIfMissingFromForTree(parent);
+ parent.replaceWith(replacement);
+ compiler.reportChangeToEnclosingScope(replacement);
+ }
+
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ // TODO(bashir): Implement a real hot-swap version instead and make it fully
+ // consistent with the full version.
+ this.compiler.process(this);
+ }
+
+ @Override
+ public void visit(NodeTraversal t, Node n, Node parent) {
+ switch (n.getToken()) {
+ case CALL:
+ Node left = n.getFirstChild();
+ if (left.isGetProp()) {
+ Node name = left.getFirstChild();
+ if (name.isName() && GOOG.equals(name.getString())) {
+ // For the sake of simplicity, we report code changes
+ // when we see a provides/requires, and don't worry about
+ // reporting the change when we actually do the replacement.
+ String methodName = name.getNext().getString();
+ /** Converted switch to else/if for Java 1.6 compatibility */
+ if (methodName.contentEquals("base"))
+ processBaseClassCall(t, n);
+ else if (methodName.contentEquals("define"))
+ {
+ if (validateUnaliasablePrimitiveCall(t, n, methodName)) {
+ processDefineCall(t, n, parent);
+ }
+ }
+ else if (methodName.contentEquals("require") ||
+ methodName.contentEquals("requireType"))
+ {
+ if (validateAliasiablePrimitiveCall(t, n, methodName)) {
+ processRequireCall(t, n, parent);
+ }
+ }
+ else if (methodName.contentEquals("provide"))
+ {
+ if (validateUnaliasablePrimitiveCall(t, n, methodName)) {
+ processProvideCall(t, n, parent);
+ }
+ }
+ else if (methodName.contentEquals("inherits"))
+ processInheritsCall(n);
+ else if (methodName.contentEquals("exportSymbol"))
+ {
+ // Note: exportSymbol is allowed in local scope
+ Node arg = left.getNext();
+ if (arg.isString()) {
+ String argString = arg.getString();
+ int dot = argString.indexOf('.');
+ if (dot == -1) {
+ exportedVariables.add(argString);
+ } else {
+ exportedVariables.add(argString.substring(0, dot));
+ }
+ }
+ }
+ else if (methodName.contentEquals("forwardDeclare"))
+ {
+ if (validateAliasiablePrimitiveCall(t, n, methodName)) {
+ processForwardDeclare(t, n, parent);
+ }
+ }
+ else if (methodName.contentEquals("addDependency"))
+ {
+ if (validateUnaliasablePrimitiveCall(t, n, methodName)) {
+ processAddDependency(n, parent);
+ }
+ }
+ else if (methodName.contentEquals("setCssNameMapping")) {
+ processSetCssNameMapping(t, n, parent);
+ }
+ } else if (left.getLastChild().getString().equals("base")) {
+ // maybe an "base" setup by goog.inherits
+ maybeProcessClassBaseCall(t, n);
+ }
+ }
+ break;
+
+ case ASSIGN:
+ case NAME:
+ if (n.isName() && n.getString().equals("CLOSURE_DEFINES")) {
+ handleClosureDefinesValues(t, n);
+ } else {
+ // If this is an assignment to a provided name, remove the provided
+ // object.
+ handleCandidateProvideDefinition(t, n, parent);
+ }
+ break;
+
+ case EXPR_RESULT:
+ handleStubDefinition(t, n);
+ break;
+
+ case CLASS:
+ if (t.inGlobalHoistScope() && !NodeUtil.isClassExpression(n)) {
+ String name = n.getFirstChild().getString();
+ ProvidedName pn = providedNames.get(name);
+ if (pn != null) {
+ compiler.report(t.makeError(n, CLASS_NAMESPACE_ERROR, name));
+ }
+ }
+ break;
+
+ case FUNCTION:
+ // If this is a declaration of a provided named function, this is an
+ // error. Hoisted functions will explode if they're provided.
+ if (t.inGlobalHoistScope() && NodeUtil.isFunctionDeclaration(n)) {
+ String name = n.getFirstChild().getString();
+ ProvidedName pn = providedNames.get(name);
+ if (pn != null) {
+ compiler.report(t.makeError(n, FUNCTION_NAMESPACE_ERROR, name));
+ }
+ }
+ break;
+
+ case GETPROP:
+ if (n.getFirstChild().isName()
+ && !parent.isCall()
+ && !parent.isAssign()
+ && n.matchesQualifiedName("goog.base")
+ && !n.getSourceFileName().endsWith("goog.js")) {
+ reportBadGoogBaseUse(t, n, "May only be called directly.");
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ /**
+ * Verifies that a) the call is in the global scope and b) the return value is unused
+ *
+ * <p>This method is for primitives that never return a value.
+ */
+ private boolean validateUnaliasablePrimitiveCall(NodeTraversal t, Node n, String methodName) {
+ return validatePrimitiveCallWithMessage(t, n, methodName, CLOSURE_CALL_CANNOT_BE_ALIASED_ERROR);
+ }
+
+ /**
+ * Verifies that a) the call is in the global scope and b) the return value is unused
+ *
+ * <p>This method is for primitives that do return a value in modules, but not in scripts/
+ * goog.provide files
+ */
+ private boolean validateAliasiablePrimitiveCall(NodeTraversal t, Node n, String methodName) {
+ return validatePrimitiveCallWithMessage(
+ t, n, methodName, CLOSURE_CALL_CANNOT_BE_ALIASED_OUTSIDE_MODULE_ERROR);
+ }
+
+ /**
+ * @param methodName list of primitve types classed together with this one
+ * @param invalidAliasingError which DiagnosticType to emit if this call is aliased. this depends
+ * on whether the primitive is sometimes aliasiable in a module or never aliasable.
+ */
+ private boolean validatePrimitiveCallWithMessage(
+ NodeTraversal t, Node n, String methodName, DiagnosticType invalidAliasingError) {
+ // Ignore invalid primitives if we didn't strip module sugar.
+ if (compiler.getOptions().shouldPreserveGoogModule()) {
+ return true;
+ }
+
+ if (!t.inGlobalHoistScope()) {
+ compiler.report(t.makeError(n, INVALID_CLOSURE_CALL_SCOPE_ERROR));
+ return false;
+ } else if (!n.getParent().isExprResult()) {
+ // If the call is in the global hoist scope, but the result is used
+ compiler.report(t.makeError(n, invalidAliasingError, GOOG + "." + methodName));
+ return false;
+ }
+ return true;
+ }
+
+ private void handleClosureDefinesValues(NodeTraversal t, Node n) {
+ // var CLOSURE_DEFINES = {};
+ if (NodeUtil.isNameDeclaration(n.getParent())
+ && n.hasOneChild()
+ && n.getFirstChild().isObjectLit()) {
+ HashMap<String, Node> builder = new HashMap<String, Node>();
+ builder.putAll(compiler.getDefaultDefineValues());
+ for (Node c : n.getFirstChild().children()) {
+ if (c.isStringKey()
+ && c.getFirstChild() != null // Shorthand assignment
+ && isValidDefineValue(c.getFirstChild())) {
+ builder.put(c.getString(), c.getFirstChild().cloneTree());
+ } else {
+ reportBadClosureCommonDefinesDefinition(t, c);
+ }
+ }
+ compiler.setDefaultDefineValues(ImmutableMap.copyOf(builder));
+ }
+ }
+
+ static boolean isValidDefineValue(Node val) {
+ switch (val.getToken()) {
+ case STRING:
+ case NUMBER:
+ case TRUE:
+ case FALSE:
+ return true;
+ case NEG:
+ return val.getFirstChild().isNumber();
+ default:
+ return false;
+ }
+ }
+
+ /** Handles a goog.require or goog.requireType call. */
+ private void processRequireCall(NodeTraversal t, Node n, Node parent) {
+ Node left = n.getFirstChild();
+ Node arg = left.getNext();
+ String method = left.getFirstChild().getNext().getString();
+ if (verifyLastArgumentIsString(t, left, arg)) {
+ String ns = arg.getString();
+ ProvidedName provided = providedNames.get(ns);
+ if (provided == null || !provided.isExplicitlyProvided()) {
+ unrecognizedRequires.add(new UnrecognizedRequire(n, ns, method.equals("requireType")));
+ } else {
+ JSModule providedModule = provided.explicitModule;
+
+ if (!provided.isFromExterns()) {
+ // TODO(tbreisacher): Report an error if there's a goog.provide in an @externs file.
+ checkNotNull(providedModule, n);
+
+ JSModule module = t.getModule();
+ // A cross-chunk goog.require must match a goog.provide in an earlier chunk. However, a
+ // cross-chunk goog.requireType is allowed to match a goog.provide in a later chunk.
+ if (module != providedModule
+ && !moduleGraph.dependsOn(module, providedModule)
+ && !method.equals("requireType")) {
+ compiler.report(
+ t.makeError(n, XMODULE_REQUIRE_ERROR, ns,
+ providedModule.getName(),
+ module.getName()));
+ }
+ }
+ }
+
+ maybeAddToSymbolTable(left);
+ maybeAddStringNodeToSymbolTable(arg);
+
+ // Requires should be removed before further processing.
+ // Some clients run closure pass multiple times, first with
+ // the checks for broken requires turned off. In these cases, we
+ // allow broken requires to be preserved by the first run to
+ // let them be caught in the subsequent run.
+ if (!preserveGoogProvidesAndRequires && (provided != null || requiresLevel.isOn())) {
+ requiresToBeRemoved.add(parent);
+ }
+ }
+ }
+
+ /**
+ * Handles a goog.provide call.
+ */
+ private void processProvideCall(NodeTraversal t, Node n, Node parent) {
+ checkState(n.isCall());
+ Node left = n.getFirstChild();
+ Node arg = left.getNext();
+ if (verifyProvide(t, left, arg)) {
+ String ns = arg.getString();
+
+ maybeAddToSymbolTable(left);
+ maybeAddStringNodeToSymbolTable(arg);
+
+ if (providedNames.containsKey(ns)) {
+ ProvidedName previouslyProvided = providedNames.get(ns);
+ if (!previouslyProvided.isExplicitlyProvided()) {
+ previouslyProvided.addProvide(parent, t.getModule(), true);
+ } else {
+ String explicitSourceName = previouslyProvided.explicitNode.getSourceFileName();
+ compiler.report(t.makeError(n, DUPLICATE_NAMESPACE_ERROR, ns, explicitSourceName));
+ }
+ } else {
+ registerAnyProvidedPrefixes(ns, parent, t.getModule());
+ providedNames.put(
+ ns, new ProvidedName(ns, parent, t.getModule(), true));
+ }
+ }
+ }
+
+ /**
+ * Handles a goog.define call.
+ */
+ private void processDefineCall(NodeTraversal t, Node n, Node parent) {
+ Node left = n.getFirstChild();
+ Node args = left.getNext();
+ if (verifyDefine(t, parent, left, args)) {
+ Node nameNode = args;
+
+ maybeAddToSymbolTable(left);
+ maybeAddStringNodeToSymbolTable(nameNode);
+
+ this.defineCalls.add(n);
+ }
+ }
+
+ /**
+ * Handles a stub definition for a goog.provided name
+ * (e.g. a @typedef or a definition from externs)
+ *
+ * @param n EXPR_RESULT node.
+ */
+ private void handleStubDefinition(NodeTraversal t, Node n) {
+ if (!t.inGlobalHoistScope()) {
+ return;
+ }
+ JSDocInfo info = n.getFirstChild().getJSDocInfo();
+ boolean hasStubDefinition = info != null && (n.isFromExterns() || info.hasTypedefType());
+ if (hasStubDefinition) {
+ if (n.getFirstChild().isQualifiedName()) {
+ String name = n.getFirstChild().getQualifiedName();
+ ProvidedName pn = providedNames.get(name);
+ if (pn != null) {
+ n.putBooleanProp(Node.WAS_PREVIOUSLY_PROVIDED, true);
+ pn.addDefinition(n, t.getModule());
+ } else if (n.getBooleanProp(Node.WAS_PREVIOUSLY_PROVIDED)) {
+ // We didn't find it in the providedNames, but it was previously marked as provided.
+ // This implies we're in hotswap pass and the current typedef is a provided namespace.
+ ProvidedName provided = new ProvidedName(name, n, t.getModule(), true);
+ providedNames.put(name, provided);
+ }
+ }
+ }
+ }
+
+ /**
+ * Handles a candidate definition for a goog.provided name.
+ */
+ private void handleCandidateProvideDefinition(
+ NodeTraversal t, Node n, Node parent) {
+ if (t.inGlobalHoistScope()) {
+ String name = null;
+ if (n.isName() && NodeUtil.isNameDeclaration(parent)) {
+ name = n.getString();
+ } else if (n.isAssign() && parent.isExprResult()) {
+ name = n.getFirstChild().getQualifiedName();
+ }
+
+ if (name != null) {
+ if (parent.getBooleanProp(Node.IS_NAMESPACE)) {
+ processProvideFromPreviousPass(t, name, parent);
+ } else {
+ ProvidedName pn = providedNames.get(name);
+ if (pn != null) {
+ pn.addDefinition(parent, t.getModule());
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes the base class call.
+ */
+ private void processBaseClassCall(NodeTraversal t, Node n) {
+ // Two things must hold for every goog.base call:
+ // 1) We must be calling it on "this".
+ // 2) We must be calling it on a prototype method of the same name as
+ // the one we're in, OR we must be calling it from a constructor.
+ // If both of those things are true, then we can rewrite:
+ // <pre>
+ // function Foo() {
+ // goog.base(this);
+ // }
+ // goog.inherits(Foo, BaseFoo);
+ // Foo.prototype.bar = function() {
+ // goog.base(this, 'bar', 1);
+ // };
+ // </pre>
+ // as the easy-to-optimize:
+ // <pre>
+ // function Foo() {
+ // BaseFoo.call(this);
+ // }
+ // goog.inherits(Foo, BaseFoo);
+ // Foo.prototype.bar = function() {
+ // Foo.superClass_.bar.call(this, 1);
+ // };
+ //
+ // Most of the logic here is just to make sure the AST's
+ // structure is what we expect it to be.
+
+ // If requested report uses of goog.base.
+ t.report(n, USE_OF_GOOG_BASE);
+
+ if (baseUsedInClass(n)){
+ reportBadGoogBaseUse(t, n, "goog.base in ES6 class is not allowed. Use super instead.");
+ return;
+ }
+
+ Node callee = n.getFirstChild();
+ Node thisArg = callee.getNext();
+ if (thisArg == null || !thisArg.isThis()) {
+ reportBadGoogBaseUse(t, n, "First argument must be 'this'.");
+ return;
+ }
+
+ Node enclosingFnNameNode = getEnclosingDeclNameNode(n);
+ if (enclosingFnNameNode == null) {
+ reportBadGoogBaseUse(t, n, "Could not find enclosing method.");
+ return;
+ }
+
+ String enclosingQname = enclosingFnNameNode.getQualifiedName();
+ if (!enclosingQname.contains(".prototype.")) {
+ // Handle constructors.
+ Node enclosingParent = enclosingFnNameNode.getParent();
+ Node maybeInheritsExpr =
+ (enclosingParent.isAssign() ? enclosingParent.getParent() : enclosingParent).getNext();
+ Node baseClassNode = null;
+ if (maybeInheritsExpr != null
+ && maybeInheritsExpr.isExprResult()
+ && maybeInheritsExpr.getFirstChild().isCall()) {
+ Node callNode = maybeInheritsExpr.getFirstChild();
+ if (callNode.getFirstChild().matchesQualifiedName("goog.inherits")
+ && callNode.getLastChild().isQualifiedName()) {
+ baseClassNode = callNode.getLastChild();
+ }
+ }
+
+ if (baseClassNode == null) {
+ reportBadGoogBaseUse(
+ t, n, "Could not find goog.inherits for base class");
+ return;
+ }
+
+ // We're good to go.
+ Node newCallee =
+ NodeUtil.newQName(
+ compiler, baseClassNode.getQualifiedName() + ".call", callee, "goog.base");
+ n.replaceChild(callee, newCallee);
+ compiler.reportChangeToEnclosingScope(newCallee);
+ } else {
+ // Handle methods.
+ Node methodNameNode = thisArg.getNext();
+ if (methodNameNode == null || !methodNameNode.isString()) {
+ reportBadGoogBaseUse(t, n, "Second argument must name a method.");
+ return;
+ }
+
+ String methodName = methodNameNode.getString();
+ String ending = ".prototype." + methodName;
+ if (enclosingQname == null || !enclosingQname.endsWith(ending)) {
+ reportBadGoogBaseUse(
+ t, n, "Enclosing method does not match " + methodName);
+ return;
+ }
+
+ // We're good to go.
+ Node className =
+ enclosingFnNameNode.getFirstFirstChild();
+ n.replaceChild(
+ callee,
+ NodeUtil.newQName(
+ compiler,
+ className.getQualifiedName() + ".superClass_." + methodName + ".call",
+ callee, "goog.base"));
+ n.removeChild(methodNameNode);
+ compiler.reportChangeToEnclosingScope(n);
+ }
+ }
+
+ private void maybeProcessClassBaseCall(NodeTraversal t, Node n) {
+ // Two things must hold for every base call:
+ // 1) We must be calling it on "this".
+ // 2) We must be calling it on a prototype method of the same name as
+ // the one we're in, OR we must be calling it from a constructor.
+ // If both of those things are true, then we can rewrite:
+ // <pre>
+ // function Foo() {
+ // Foo.base(this);
+ // }
+ // goog.inherits(Foo, BaseFoo);
+ // Foo.prototype.bar = function() {
+ // Foo.base(this, 'bar', 1);
+ // };
+ // </pre>
+ // as the easy-to-optimize:
+ // <pre>
+ // function Foo() {
+ // BaseFoo.call(this);
+ // }
+ // goog.inherits(Foo, BaseFoo);
+ // Foo.prototype.bar = function() {
+ // Foo.superClass_.bar.call(this, 1);
+ // };
+ //
+ // Most of the logic here is just to make sure the AST's
+ // structure is what we expect it to be.
+
+ Node callTarget = n.getFirstChild();
+ Node baseContainerNode = callTarget.getFirstChild();
+ if (!baseContainerNode.isUnscopedQualifiedName()) {
+ // Some unknown "base" method.
+ return;
+ }
+ String baseContainer = callTarget.getFirstChild().getQualifiedName();
+
+ Node enclosingFnNameNode = getEnclosingDeclNameNode(n);
+ if (enclosingFnNameNode == null || !enclosingFnNameNode.isUnscopedQualifiedName()) {
+ // some unknown container method.
+ if (knownClosureSubclasses.contains(baseContainer)) {
+ reportBadBaseMethodUse(t, n, baseContainer, "Could not find enclosing method.");
+ } else if (baseUsedInClass(n)) {
+ Node clazz = NodeUtil.getEnclosingClass(n);
+ if ((clazz.getFirstChild().isName()
+ && clazz.getFirstChild().getString().equals(baseContainer))
+ || (clazz.getSecondChild().isName()
+ && clazz.getSecondChild().getString().equals(baseContainer))) {
+ reportBadBaseMethodUse(t, n, clazz.getFirstChild().getString(),
+ "base method is not allowed in ES6 class. Use super instead.");
+ }
+ }
+ return;
+ }
+
+ if (baseUsedInClass(n)) {
+ reportBadGoogBaseUse(t, n, "goog.base in ES6 class is not allowed. Use super instead.");
+ return;
+ }
+
+ String enclosingQname = enclosingFnNameNode.getQualifiedName();
+ if (!enclosingQname.contains(".prototype.")) {
+ // Handle constructors.
+
+ // Check if this is some other "base" method.
+ if (!enclosingQname.equals(baseContainer)) {
+ // Report misuse of "base" methods from other known classes.
+ if (knownClosureSubclasses.contains(baseContainer)) {
+ reportBadBaseMethodUse(t, n, baseContainer, "Must be used within "
+ + baseContainer + " methods");
+ }
+ return;
+ }
+
+ // Determine if this is a class with a "base" method created by
+ // goog.inherits.
+ Node enclosingParent = enclosingFnNameNode.getParent();
+ Node maybeInheritsExpr =
+ (enclosingParent.isAssign() ? enclosingParent.getParent() : enclosingParent).getNext();
+ while (maybeInheritsExpr != null && maybeInheritsExpr.isEmpty()) {
+ maybeInheritsExpr = maybeInheritsExpr.getNext();
+ }
+ Node baseClassNode = null;
+ if (maybeInheritsExpr != null
+ && maybeInheritsExpr.isExprResult()
+ && maybeInheritsExpr.getFirstChild().isCall()) {
+ Node callNode = maybeInheritsExpr.getFirstChild();
+ if (callNode.getFirstChild().matchesQualifiedName("goog.inherits")
+ && callNode.getLastChild().isQualifiedName()) {
+ baseClassNode = callNode.getLastChild();
+ }
+ }
+
+ if (baseClassNode == null) {
+ // If there is no "goog.inherits", this might be some other "base"
+ // method.
+ return;
+ }
+
+ // This is the expected method, validate its parameters.
+ Node callee = n.getFirstChild();
+ Node thisArg = callee.getNext();
+ if (thisArg == null || !thisArg.isThis()) {
+ reportBadBaseMethodUse(t, n, baseContainer,
+ "First argument must be 'this'.");
+ return;
+ }
+
+ // Handle methods.
+ Node methodNameNode = thisArg.getNext();
+ if (methodNameNode == null
+ || !methodNameNode.isString()
+ || !methodNameNode.getString().equals("constructor")) {
+ reportBadBaseMethodUse(t, n, baseContainer,
+ "Second argument must be 'constructor'.");
+ return;
+ }
+
+ // We're good to go.
+ n.replaceChild(
+ callee,
+ NodeUtil.newQName(
+ compiler,
+ baseClassNode.getQualifiedName() + ".call",
+ callee, enclosingQname + ".base"));
+ n.removeChild(methodNameNode);
+ compiler.reportChangeToEnclosingScope(n);
+ } else {
+ if (!knownClosureSubclasses.contains(baseContainer)) {
+ // Can't determine if this is a known "class" that has a known "base"
+ // method.
+ return;
+ }
+
+ boolean misuseOfBase = !enclosingFnNameNode.
+ getFirstFirstChild().matchesQualifiedName(baseContainer);
+ if (misuseOfBase) {
+ // Report misuse of "base" methods from other known classes.
+ reportBadBaseMethodUse(t, n, baseContainer, "Must be used within "
+ + baseContainer + " methods");
+ return;
+ }
+
+ // The super class is known.
+ Node callee = n.getFirstChild();
+ Node thisArg = callee.getNext();
+ if (thisArg == null || !thisArg.isThis()) {
+ reportBadBaseMethodUse(t, n, baseContainer,
+ "First argument must be 'this'.");
+ return;
+ }
+
+ // Handle methods.
+ Node methodNameNode = thisArg.getNext();
+ if (methodNameNode == null || !methodNameNode.isString()) {
+ reportBadBaseMethodUse(t, n, baseContainer,
+ "Second argument must name a method.");
+ return;
+ }
+
+ String methodName = methodNameNode.getString();
+ String ending = ".prototype." + methodName;
+ if (enclosingQname == null || !enclosingQname.endsWith(ending)) {
+ reportBadBaseMethodUse(t, n, baseContainer,
+ "Enclosing method does not match " + methodName);
+ return;
+ }
+
+ // We're good to go.
+ Node className =
+ enclosingFnNameNode.getFirstFirstChild();
+ n.replaceChild(
+ callee,
+ NodeUtil.newQName(
+ compiler,
+ className.getQualifiedName() + ".superClass_." + methodName + ".call",
+ callee, enclosingQname + ".base"));
+ n.removeChild(methodNameNode);
+ compiler.reportChangeToEnclosingScope(n);
+ }
+ }
+
+ /**
+ * Processes the goog.inherits call.
+ */
+ private void processInheritsCall(Node n) {
+ if (n.getChildCount() == 3) {
+ Node subClass = n.getSecondChild();
+ Node superClass = subClass.getNext();
+ if (subClass.isUnscopedQualifiedName() && superClass.isUnscopedQualifiedName()) {
+ knownClosureSubclasses.add(subClass.getQualifiedName());
+ }
+ }
+ }
+
+ /**
+ * Returns the qualified name node of the function whose scope we're in,
+ * or null if it cannot be found.
+ */
+ private static Node getEnclosingDeclNameNode(Node n) {
+ Node fn = NodeUtil.getEnclosingFunction(n);
+ return fn == null ? null : NodeUtil.getNameNode(fn);
+ }
+
+ /** Verify if goog.base call is used in a class */
+ private boolean baseUsedInClass(Node n){
+ for (Node curr = n; curr != null; curr = curr.getParent()){
+ if (curr.isClassMembers()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /** Reports an incorrect use of super-method calling. */
+ private void reportBadGoogBaseUse(
+ NodeTraversal t, Node n, String extraMessage) {
+ compiler.report(t.makeError(n, GOOG_BASE_CLASS_ERROR, extraMessage));
+ }
+
+ /** Reports an incorrect use of super-method calling. */
+ private void reportBadBaseMethodUse(
+ NodeTraversal t, Node n, String className, String extraMessage) {
+ compiler.report(t.makeError(n, BASE_CLASS_ERROR, className, extraMessage));
+ }
+
+ /** Reports an incorrect CLOSURE_DEFINES definition. */
+ private void reportBadClosureCommonDefinesDefinition(
+ NodeTraversal t, Node n) {
+ compiler.report(t.makeError(n, CLOSURE_DEFINES_ERROR));
+ }
+
+ /**
+ * Processes the output of processed-provide from a previous pass. This will
+ * update our data structures in the same manner as if the provide had been
+ * processed in this pass.
+ */
+ private void processProvideFromPreviousPass(
+ NodeTraversal t, String name, Node parent) {
+ if (!providedNames.containsKey(name)) {
+ // Record this provide created on a previous pass, and create a dummy
+ // EXPR node as a placeholder to simulate an explicit provide.
+ Node expr = new Node(Token.EXPR_RESULT);
+ expr.useSourceInfoIfMissingFromForTree(parent);
+ parent.getParent().addChildBefore(expr, parent);
+ /**
+ * 'expr' has been newly added to the AST, but it might be removed again before this pass
+ * finishes. Keep it in a list for later change reporting if it doesn't get removed again
+ * before the end of the pass.
+ */
+ maybeTemporarilyLiveNodes.add(expr);
+
+ JSModule module = t.getModule();
+ registerAnyProvidedPrefixes(name, expr, module);
+
+ // If registerAnyProvidedPrefixes didn't add any children, add a no-op child so that
+ // the AST is valid.
+ if (!expr.hasChildren()) {
+ expr.addChildToBack(NodeUtil.newUndefinedNode(parent));
+ }
+
+ ProvidedName provided = new ProvidedName(name, expr, module, true);
+ providedNames.put(name, provided);
+ provided.addDefinition(parent, module);
+ } else {
+ // Remove this provide if it came from a previous pass since we have an
+ // replacement already.
+ if (isNamespacePlaceholder(parent)) {
+ compiler.reportChangeToEnclosingScope(parent);
+ parent.detach();
+ }
+ }
+ }
+
+ /**
+ * Processes a call to goog.setCssNameMapping(). Either the argument to
+ * goog.setCssNameMapping() is valid, in which case it will be used to create
+ * a CssRenamingMap for the compiler of this CompilerPass, or it is invalid
+ * and a JSCompiler error will be reported.
+ * @see #visit(NodeTraversal, Node, Node)
+ */
+ private void processSetCssNameMapping(NodeTraversal t, Node n, Node parent) {
+ Node left = n.getFirstChild();
+ Node arg = left.getNext();
+ if (verifySetCssNameMapping(t, left, arg)) {
+ // Translate OBJECTLIT into SubstitutionMap. All keys and
+ // values must be strings, or an error will be thrown.
+ final Map<String, String> cssNames = new HashMap<String, String>();
+
+ for (Node key = arg.getFirstChild(); key != null;
+ key = key.getNext()) {
+ Node value = key.getFirstChild();
+ if (!key.isStringKey()
+ || value == null
+ || !value.isString()) {
+ compiler.report(
+ t.makeError(n,
+ NON_STRING_PASSED_TO_SET_CSS_NAME_MAPPING_ERROR));
+ return;
+ }
+ cssNames.put(key.getString(), value.getString());
+ }
+
+ String styleStr = "BY_PART";
+ if (arg.getNext() != null) {
+ styleStr = arg.getNext().getString();
+ }
+
+ final CssRenamingMap.Style style;
+ try {
+ style = CssRenamingMap.Style.valueOf(styleStr);
+ } catch (IllegalArgumentException e) {
+ compiler.report(
+ t.makeError(n, INVALID_STYLE_ERROR, styleStr));
+ return;
+ }
+
+ if (style == CssRenamingMap.Style.BY_PART) {
+ // Make sure that no keys contain -'s
+ List<String> errors = new ArrayList<String>();
+ for (String key : cssNames.keySet()) {
+ if (key.contains("-")) {
+ errors.add(key);
+ }
+ }
+ if (!errors.isEmpty()) {
+ compiler.report(
+ t.makeError(n, INVALID_CSS_RENAMING_MAP, errors.toString()));
+ }
+ } else if (style == CssRenamingMap.Style.BY_WHOLE) {
+ // Verifying things is a lot trickier here. We just do a quick
+ // n^2 check over the map which makes sure that if "a-b" in
+ // the map, then map(a-b) = map(a)-map(b).
+ // To speed things up, only consider cases where len(b) <= 10
+ List<String> errors = new ArrayList<String>();
+ for (Map.Entry<String, String> b : cssNames.entrySet()) {
+ if (b.getKey().length() > 10) {
+ continue;
+ }
+ for (Map.Entry<String, String> a : cssNames.entrySet()) {
+ String combined = cssNames.get(a.getKey() + "-" + b.getKey());
+ if (combined != null && !combined.equals(a.getValue() + "-" + b.getValue())) {
+ errors.add("map(" + a.getKey() + "-" + b.getKey() + ") != map("
+ + a.getKey() + ")-map(" + b.getKey() + ")");
+ }
+ }
+ }
+ if (!errors.isEmpty()) {
+ compiler.report(
+ t.makeError(n, INVALID_CSS_RENAMING_MAP, errors.toString()));
+ }
+ }
+
+ @SuppressWarnings("serial")
+ CssRenamingMap cssRenamingMap = new CssRenamingMap() {
+ @Override
+ public String get(String value) {
+ if (cssNames.containsKey(value)) {
+ return cssNames.get(value);
+ } else {
+ return value;
+ }
+ }
+
+ @Override
+ public CssRenamingMap.Style getStyle() {
+ return style;
+ }
+ };
+ compiler.setCssRenamingMap(cssRenamingMap);
+ compiler.reportChangeToEnclosingScope(parent);
+ parent.detach();
+ }
+ }
+
+ /**
+ * Verifies that a provide method call has exactly one argument,
+ * and that it's a string literal and that the contents of the string are
+ * valid JS tokens. Reports a compile error if it doesn't.
+ *
+ * @return Whether the argument checked out okay
+ */
+ private boolean verifyProvide(NodeTraversal t, Node methodName, Node arg) {
+ if (!verifyLastArgumentIsString(t, methodName, arg)) {
+ return false;
+ }
+
+ if (!NodeUtil.isValidQualifiedName(
+ compiler.getOptions().getLanguageIn().toFeatureSet(), arg.getString())) {
+ compiler.report(t.makeError(arg, INVALID_PROVIDE_ERROR,
+ arg.getString(), compiler.getOptions().getLanguageIn().toString()));
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Verifies that a provide method call has exactly one argument,
+ * and that it's a string literal and that the contents of the string are
+ * valid JS tokens. Reports a compile error if it doesn't.
+ *
+ * @return Whether the argument checked out okay
+ */
+ private boolean verifyDefine(NodeTraversal t,
+ Node expr,
+ Node methodName, Node args) {
+
+ // Verify first arg
+ Node arg = args;
+ if (!verifyNotNull(t, methodName, arg) || !verifyOfType(t, methodName, arg, Token.STRING)) {
+ return false;
+ }
+
+ // Verify second arg
+ arg = arg.getNext();
+ if (!args.isFromExterns()
+ && (!verifyNotNull(t, methodName, arg) || !verifyIsLast(t, methodName, arg))) {
+ return false;
+ }
+
+ String name = args.getString();
+ if (!NodeUtil.isValidQualifiedName(
+ compiler.getOptions().getLanguageIn().toFeatureSet(), name)) {
+ compiler.report(t.makeError(args, INVALID_DEFINE_NAME_ERROR, name));
+ return false;
+ }
+
+ JSDocInfo info = expr.getFirstChild().getJSDocInfo();
+ if (info == null || !info.isDefine()) {
+ compiler.report(t.makeError(expr, MISSING_DEFINE_ANNOTATION));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Process a goog.addDependency() call and record any forward declarations.
+ */
+ private void processAddDependency(Node n, Node parent) {
+ CodingConvention convention = compiler.getCodingConvention();
+ List<String> typeDecls =
+ convention.identifyTypeDeclarationCall(n);
+
+ // TODO(nnaze): Use of addDependency() should someday cause a warning
+ // as we migrate users to explicit goog.forwardDeclare() calls.
+ if (typeDecls != null) {
+ for (String typeDecl : typeDecls) {
+ compiler.forwardDeclareType(typeDecl);
+ }
+ }
+
+ // We can't modify parent, so just create a node that will
+ // get compiled out.
+ Node emptyNode = IR.number(0);
+ parent.replaceChild(n, emptyNode);
+ compiler.reportChangeToEnclosingScope(emptyNode);
+ }
+
+ /**
+ * Process a goog.forwardDeclare() call and record the specified forward
+ * declaration.
+ */
+ private void processForwardDeclare(NodeTraversal t, Node n, Node parent) {
+ CodingConvention convention = compiler.getCodingConvention();
+
+ String typeDeclaration = null;
+ try {
+ typeDeclaration = Iterables.getOnlyElement(
+ convention.identifyTypeDeclarationCall(n));
+ } catch (Exception e) {
+ compiler.report(
+ t.makeError(
+ n,
+ INVALID_FORWARD_DECLARE,
+ "A single type could not identified for the goog.forwardDeclare statement"));
+ }
+
+ if (typeDeclaration != null) {
+ compiler.forwardDeclareType(typeDeclaration);
+ // Forward declaration was recorded and we can remove the call.
+ Node toRemove = parent.isExprResult() ? parent : parent.getParent();
+ NodeUtil.deleteNode(toRemove, compiler);
+ }
+ }
+
+ /**
+ * Verifies that a method call has exactly one argument, and that it's a
+ * string literal. Reports a compile error if it doesn't.
+ *
+ * @return Whether the argument checked out okay
+ */
+ private boolean verifyLastArgumentIsString(
+ NodeTraversal t, Node methodName, Node arg) {
+ return verifyNotNull(t, methodName, arg)
+ && verifyOfType(t, methodName, arg, Token.STRING)
+ && verifyIsLast(t, methodName, arg);
+ }
+
+ /**
+ * @return Whether the argument checked out okay
+ */
+ private boolean verifyNotNull(NodeTraversal t, Node methodName, Node arg) {
+ if (arg == null) {
+ compiler.report(
+ t.makeError(methodName,
+ NULL_ARGUMENT_ERROR, methodName.getQualifiedName()));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return Whether the argument checked out okay
+ */
+ private boolean verifyOfType(NodeTraversal t, Node methodName,
+ Node arg, Token desiredType) {
+ if (arg.getToken() != desiredType) {
+ compiler.report(
+ t.makeError(methodName,
+ INVALID_ARGUMENT_ERROR, methodName.getQualifiedName()));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return Whether the argument checked out okay
+ */
+ private boolean verifyIsLast(NodeTraversal t, Node methodName, Node arg) {
+ if (arg.getNext() != null) {
+ compiler.report(
+ t.makeError(methodName,
+ TOO_MANY_ARGUMENTS_ERROR, methodName.getQualifiedName()));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Verifies that setCssNameMapping is called with the correct methods.
+ *
+ * @return Whether the arguments checked out okay
+ */
+ private boolean verifySetCssNameMapping(NodeTraversal t, Node methodName,
+ Node firstArg) {
+ DiagnosticType diagnostic = null;
+ if (firstArg == null) {
+ diagnostic = NULL_ARGUMENT_ERROR;
+ } else if (!firstArg.isObjectLit()) {
+ diagnostic = EXPECTED_OBJECTLIT_ERROR;
+ } else if (firstArg.getNext() != null) {
+ Node secondArg = firstArg.getNext();
+ if (!secondArg.isString()) {
+ diagnostic = EXPECTED_STRING_ERROR;
+ } else if (secondArg.getNext() != null) {
+ diagnostic = TOO_MANY_ARGUMENTS_ERROR;
+ }
+ }
+ if (diagnostic != null) {
+ compiler.report(
+ t.makeError(methodName,
+ diagnostic, methodName.getQualifiedName()));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Build up the list of strings in the externs.
+ *
+ * @param en The extern name.
+ * @param externStrings The list of strings to add to.
+ */
+ private void addExternNameAndDescendants(Name en, ArrayList<String> externStrings) {
+ externStrings.add(en.getName());
+
+ if (en.props == null || en.isCollapsingExplicitlyDenied()) {
+ return;
+ }
+ for (Name p : en.props) {
+ addExternNameAndDescendants(p, externStrings);
+ }
+ }
+
+ /**
+ * Registers ProvidedNames for prefix namespaces if they haven't
+ * already been defined. The prefix namespaces must be registered in
+ * order from shortest to longest.
+ *
+ * @param ns The namespace whose prefixes may need to be provided.
+ * @param node The EXPR of the provide call.
+ * @param module The current module.
+ */
+ private void registerAnyProvidedPrefixes(
+ String ns, Node node, JSModule module) {
+ int pos = ns.indexOf('.');
+ while (pos != -1) {
+ String prefixNs = ns.substring(0, pos);
+ pos = ns.indexOf('.', pos + 1);
+ if (providedNames.containsKey(prefixNs)) {
+ providedNames.get(prefixNs).addProvide(
+ node, module, false /* implicit */);
+ } else {
+ providedNames.put(prefixNs,
+ new ProvidedName(prefixNs, node, module, false /* implicit */));
+ // if it was in externs, added to externAliases
+ if (externStrings.contains(prefixNs))
+ if (!externAliases.contains(prefixNs))
+ externAliases.add(prefixNs);
+ // if the namespace of any provided classes
+ if (!provideds.contains(prefixNs))
+ provideds.add(prefixNs);
+ }
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * Information required to replace a goog.provide call later in the traversal.
+ */
+ private class ProvidedName {
+ private final String namespace;
+
+ // The node and module where the call was explicitly or implicitly
+ // goog.provided.
+ private final Node firstNode;
+ private final JSModule firstModule;
+
+ // The node where the call was explicitly goog.provided. May be null
+ // if the namespace is always provided implicitly.
+ private Node explicitNode = null;
+ private JSModule explicitModule = null;
+
+ // There are child namespaces of this one.
+ private boolean hasAChildNamespace = false;
+
+ // The candidate definition.
+ private Node candidateDefinition = null;
+
+ // The minimum module where the provide must appear.
+ private JSModule minimumModule = null;
+
+ // The replacement declaration.
+ private Node replacementNode = null;
+
+ ProvidedName(String namespace, Node node, JSModule module,
+ boolean explicit) {
+ Preconditions.checkArgument(node == null /* The base case */ || node.isExprResult());
+ this.namespace = namespace;
+ this.firstNode = node;
+ this.firstModule = module;
+
+ addProvide(node, module, explicit);
+ }
+
+ /**
+ * Add an implicit or explicit provide.
+ */
+ void addProvide(Node node, JSModule module, boolean explicit) {
+ if (explicit) {
+ // goog.provide('name.space');
+ checkState(explicitNode == null);
+ checkArgument(node.isExprResult());
+ explicitNode = node;
+ explicitModule = module;
+ } else {
+ // goog.provide('name.space.some.child');
+ hasAChildNamespace = true;
+ }
+ updateMinimumModule(module);
+ }
+
+ boolean isExplicitlyProvided() {
+ return explicitNode != null;
+ }
+
+ boolean isFromExterns() {
+ return explicitNode.isFromExterns();
+ }
+
+ /**
+ * Record function declaration, variable declaration or assignment that
+ * refers to the same name as the provide statement. Give preference to
+ * declarations; if no declaration exists, record a reference to an
+ * assignment so it repurposed later.
+ */
+ void addDefinition(Node node, JSModule module) {
+ Preconditions.checkArgument(
+ node.isExprResult() // assign
+ || node.isFunction()
+ || NodeUtil.isNameDeclaration(node));
+ checkArgument(explicitNode != node);
+ if ((candidateDefinition == null) || !node.isExprResult()) {
+ candidateDefinition = node;
+ updateMinimumModule(module);
+ }
+ }
+
+ private void updateMinimumModule(JSModule newModule) {
+ if (minimumModule == null) {
+ minimumModule = newModule;
+ } else if (moduleGraph.getModuleCount() > 1) {
+ minimumModule = moduleGraph.getDeepestCommonDependencyInclusive(
+ minimumModule, newModule);
+ } else {
+ // If there is no module graph, then there must be exactly one
+ // module in the program.
+ checkState(newModule == minimumModule, "Missing module graph");
+ }
+ }
+
+ /**
+ * Replace the provide statement.
+ *
+ * If we're providing a name with no definition, then create one.
+ * If we're providing a name with a duplicate definition, then make sure
+ * that definition becomes a declaration.
+ */
+ void replace() {
+ if (firstNode == null) {
+ // Don't touch the base case ('goog').
+ replacementNode = candidateDefinition;
+ return;
+ }
+
+ // Handle the case where there is a duplicate definition for an explicitly
+ // provided symbol.
+ if (candidateDefinition != null && explicitNode != null) {
+ JSDocInfo info;
+ if (candidateDefinition.isExprResult()) {
+ info = candidateDefinition.getFirstChild().getJSDocInfo();
+ } else {
+ info = candidateDefinition.getJSDocInfo();
+ }
+
+ // Validate that the namespace is not declared as a generic object type.
+ if (info != null) {
+ JSTypeExpression expr = info.getType();
+ if (expr != null) {
+ Node n = expr.getRoot();
+ if (n.getToken() == Token.BANG) {
+ n = n.getFirstChild();
+ }
+ if (n.isString()
+ && !n.hasChildren() // templated object types are ok.
+ && n.getString().equals("Object")) {
+ compiler.report(
+ JSError.make(candidateDefinition, WEAK_NAMESPACE_TYPE));
+ }
+ }
+ }
+
+ // Does this need a VAR keyword?
+ replacementNode = candidateDefinition;
+ if (candidateDefinition.isExprResult()) {
+ Node exprNode = candidateDefinition.getOnlyChild();
+ if (exprNode.isAssign()) {
+ // namespace = value;
+ candidateDefinition.putBooleanProp(Node.IS_NAMESPACE, true);
+ Node nameNode = exprNode.getFirstChild();
+ if (nameNode.isName()) {
+ // Need to convert this assign to a var declaration.
+ Node valueNode = nameNode.getNext();
+ exprNode.removeChild(nameNode);
+ exprNode.removeChild(valueNode);
+ nameNode.addChildToFront(valueNode);
+ Node varNode = IR.var(nameNode);
+ varNode.useSourceInfoFrom(candidateDefinition);
+ candidateDefinition.replaceWith(varNode);
+ varNode.setJSDocInfo(exprNode.getJSDocInfo());
+ compiler.reportChangeToEnclosingScope(varNode);
+ replacementNode = varNode;
+ }
+ } else {
+ // /** @typedef {something} */ name.space.Type;
+ checkState(exprNode.isQualifiedName(), exprNode);
+ // If this namespace has child namespaces, we still need to add an object to hang them
+ // on to avoid creating broken code.
+ // We must cast the type of the literal to unknown, because the type checker doesn't
+ // expect the namespace to have a value.
+ if (hasAChildNamespace) {
+ replaceWith(createDeclarationNode(
+ IR.cast(IR.objectlit(), createUnknownTypeJsDocInfo())));
+ }
+ }
+ }
+ } else {
+ // Handle the case where there's not a duplicate definition.
+ replaceWith(createDeclarationNode(IR.objectlit()));
+ }
+ if (explicitNode != null) {
+ if (preserveGoogProvidesAndRequires && explicitNode.hasChildren()) {
+ return;
+ }
+ /*
+ * If 'explicitNode' was added earlier in this pass then don't bother to report its removal
+ * right here as a change (since the original AST state is being restored). Also remove
+ * 'explicitNode' from the list of "possibly live" nodes so that it does not get reported as
+ * a change at the end of the pass.
+ */
+ if (!maybeTemporarilyLiveNodes.remove(explicitNode)) {
+ compiler.reportChangeToEnclosingScope(explicitNode);
+ }
+ explicitNode.detach();
+ }
+ }
+
+ private void replaceWith(Node replacement) {
+ replacementNode = replacement;
+ if (firstModule == minimumModule) {
+ firstNode.getParent().addChildBefore(replacementNode, firstNode);
+ } else {
+ // In this case, the name was implicitly provided by two independent
+ // modules. We need to move this code up to a common module.
+ int indexOfDot = namespace.lastIndexOf('.');
+ if (indexOfDot == -1) {
+ // Any old place is fine.
+ compiler.getNodeForCodeInsertion(minimumModule)
+ .addChildToBack(replacementNode);
+ } else {
+ // Add it after the parent namespace.
+ ProvidedName parentName =
+ providedNames.get(namespace.substring(0, indexOfDot));
+ checkNotNull(parentName);
+ checkNotNull(parentName.replacementNode);
+ parentName.replacementNode.getParent().addChildAfter(
+ replacementNode, parentName.replacementNode);
+ }
+ }
+ compiler.reportChangeToEnclosingScope(replacementNode);
+ }
+
+ /**
+ * Create the declaration node for this name, without inserting it
+ * into the AST.
+ */
+ private Node createDeclarationNode(Node value) {
+ if (namespace.indexOf('.') == -1) {
+ return makeVarDeclNode(value);
+ } else {
+ return makeAssignmentExprNode(value);
+ }
+ }
+
+ /**
+ * Creates a simple namespace variable declaration
+ * (e.g. <code>var foo = {};</code>).
+ */
+ private Node makeVarDeclNode(Node value) {
+ Node name = IR.name(namespace);
+ name.addChildToFront(value);
+
+ Node decl = IR.var(name);
+ decl.putBooleanProp(Node.IS_NAMESPACE, true);
+
+ if (compiler.getCodingConvention().isConstant(namespace)) {
+ name.putBooleanProp(Node.IS_CONSTANT_NAME, true);
+ }
+ if (candidateDefinition == null) {
+ decl.setJSDocInfo(NodeUtil.createConstantJsDoc());
+ }
+
+ checkState(isNamespacePlaceholder(decl));
+ setSourceInfo(decl);
+ return decl;
+ }
+
+ /**
+ * Creates a dotted namespace assignment expression
+ * (e.g. <code>foo.bar = {};</code>).
+ */
+ private Node makeAssignmentExprNode(Node value) {
+ Node lhs =
+ NodeUtil.newQName(
+ compiler,
+ namespace,
+ firstNode /* real source info will be filled in below */,
+ namespace);
+ Node decl = IR.exprResult(IR.assign(lhs, value));
+ decl.putBooleanProp(Node.IS_NAMESPACE, true);
+ if (candidateDefinition == null) {
+ decl.getFirstChild().setJSDocInfo(NodeUtil.createConstantJsDoc());
+ }
+ checkState(isNamespacePlaceholder(decl));
+ setSourceInfo(decl);
+ // This function introduces artifical nodes and we don't need them for indexing.
+ // Marking all but the last one as non-indexable. So if this function adds:
+ // foo.bar.baz = {};
+ // then we mark foo and bar as non-indexable.
+ lhs.getFirstChild().makeNonIndexableRecursive();
+ return decl;
+ }
+
+ /**
+ * Copy source info to the new node.
+ */
+ private void setSourceInfo(Node newNode) {
+ Node provideStringNode = getProvideStringNode();
+ int offset = provideStringNode == null ? 0 : getSourceInfoOffset();
+ Node sourceInfoNode = provideStringNode == null ? firstNode : provideStringNode;
+ newNode.useSourceInfoIfMissingFromForTree(sourceInfoNode);
+ if (offset != 0) {
+ newNode.setSourceEncodedPositionForTree(
+ sourceInfoNode.getSourcePosition() + offset);
+ }
+ }
+
+ /**
+ * Get the offset into the provide node where the symbol appears.
+ */
+ private int getSourceInfoOffset() {
+ int indexOfLastDot = namespace.lastIndexOf('.');
+
+ // +1 for the opening quote
+ // +1 for the dot
+ // if there's no dot, then the -1 index cancels it out
+ // so elegant!
+ return 2 + indexOfLastDot;
+ }
+
+ private Node getProvideStringNode() {
+ return (firstNode.getFirstChild() != null && NodeUtil.isExprCall(firstNode))
+ ? firstNode.getFirstChild().getLastChild()
+ : null;
+ }
+ }
+
+ private JSDocInfo createUnknownTypeJsDocInfo() {
+ JSDocInfoBuilder castToUnknownBuilder = new JSDocInfoBuilder(true);
+ castToUnknownBuilder.recordType(
+ new JSTypeExpression(
+ JsDocInfoParser.parseTypeString("?"), "<ProcessClosurePrimitives.java>"));
+ return castToUnknownBuilder.build();
+ }
+
+ /**
+ * @return Whether the node is namespace placeholder.
+ */
+ private static boolean isNamespacePlaceholder(Node n) {
+ if (!n.getBooleanProp(Node.IS_NAMESPACE)) {
+ return false;
+ }
+
+ Node value = null;
+ if (n.isExprResult()) {
+ Node assign = n.getFirstChild();
+ value = assign.getLastChild();
+ } else if (n.isVar()) {
+ Node name = n.getFirstChild();
+ value = name.getFirstChild();
+ }
+
+ if (value == null) {
+ return false;
+ }
+ if (value.isCast()) {
+ // There may be a cast to unknown type wrapped around the value.
+ value = value.getOnlyChild();
+ }
+ return value.isObjectLit() && !value.hasChildren();
+ }
+
+ /**
+ * The string in {@code n} is a reference name. Create a synthetic
+ * node for it with all the proper source info, and add it to the symbol
+ * table.
+ */
+ private void maybeAddStringNodeToSymbolTable(Node n) {
+ if (preprocessorSymbolTable == null) {
+ return;
+ }
+
+ String name = n.getString();
+ Node syntheticRef = NodeUtil.newQName(
+ compiler, name,
+ n /* real source offsets will be filled in below */,
+ name);
+
+ // Offsets to add to source. Named for documentation purposes.
+ final int forQuote = 1;
+ final int forDot = 1;
+
+ Node current = null;
+ for (current = syntheticRef;
+ current.isGetProp();
+ current = current.getFirstChild()) {
+ int fullLen = current.getQualifiedName().length();
+ int namespaceLen = current.getFirstChild().getQualifiedName().length();
+
+ current.setSourceEncodedPosition(n.getSourcePosition() + forQuote);
+ current.setLength(fullLen);
+
+ current.getLastChild().setSourceEncodedPosition(
+ n.getSourcePosition() + namespaceLen + forQuote + forDot);
+ current.getLastChild().setLength(
+ current.getLastChild().getString().length());
+ }
+
+ current.setSourceEncodedPosition(n.getSourcePosition() + forQuote);
+ current.setLength(current.getString().length());
+
+ maybeAddToSymbolTable(syntheticRef);
+ }
+
+ /**
+ * Add the given qualified name node to the symbol table.
+ */
+ private void maybeAddToSymbolTable(Node n) {
+ if (preprocessorSymbolTable != null) {
+ preprocessorSymbolTable.addReference(n);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * Information required to create a {@code MISSING_PROVIDE_ERROR} warning.
+ */
+ private static class UnrecognizedRequire {
+ final Node requireNode;
+ final String namespace;
+ final boolean isRequireType;
+
+ UnrecognizedRequire(Node requireNode, String namespace, boolean isRequireType) {
+ this.requireNode = requireNode;
+ this.namespace = namespace;
+ this.isRequireType = isRequireType;
+ }
+ }
+}
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/RenamePropertiesWithModuleSupport.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/RenamePropertiesWithModuleSupport.java
new file mode 100644
index 0000000..89ba74a
--- /dev/null
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/RenamePropertiesWithModuleSupport.java
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2004 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.javascript.jscomp;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Sets;
+import com.google.javascript.jscomp.AbstractCompiler.LifeCycleStage;
+import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
+import com.google.javascript.rhino.IR;
+import com.google.javascript.rhino.Node;
+import com.google.javascript.rhino.TokenStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.annotation.Nullable;
+
+/**
+ * Apache Royale copied RenameProperties and modified it to handle
+ * Royale modules.
+ *
+ * RenameProperties renames properties (including methods) of all JavaScript
+ * objects. This includes prototypes, functions, object literals, etc.
+ *
+ * <p> If provided a VariableMap of previously used names, it tries to reuse
+ * those names.
+ *
+ * <p> To prevent a property from getting renamed you may extern it (add it to
+ * your externs file) or put it in quotes.
+ *
+ * <p> To avoid run-time JavaScript errors, use quotes when accessing properties
+ * that are defined using quotes.
+ *
+ * <pre>
+ * var a = {'myprop': 0}, b = a['myprop']; // correct
+ * var x = {'myprop': 0}, y = x.myprop; // incorrect
+ * </pre>
+ *
+ * This pass also recognizes and replaces special renaming functions. They supply
+ * a property name as the string literal for the first argument.
+ * This pass will replace them as though they were JS property
+ * references. Here are two examples:
+ * JSCompiler_renameProperty('propertyName') -> 'jYq'
+ * JSCompiler_renameProperty('myProp.nestedProp.innerProp') -> 'e4.sW.C$'
+ *
+ */
+class RenamePropertiesWithModuleSupport implements CompilerPass {
+ private static final Splitter DOT_SPLITTER = Splitter.on('.');
+
+ private final AbstractCompiler compiler;
+ private final boolean generatePseudoNames;
+
+ /** Property renaming map from a previous compilation. */
+ private final VariableMap prevUsedPropertyMap;
+
+ /** Original names of properties that were renamed */
+ private final List<String> prevUsedPropertyOldNames = new ArrayList<String>();
+
+ private final List<Node> toRemove = new ArrayList<Node>();
+ private final List<Node> stringNodesToRename = new ArrayList<Node>();
+ private final Map<Node, Node> callNodeToParentMap =
+ new LinkedHashMap<Node, Node>();
+ private final char[] reservedFirstCharacters;
+ private final char[] reservedNonFirstCharacters;
+
+ // Map from property name to Property object
+ private final Map<String, Property> propertyMap = new LinkedHashMap<String, Property>();
+
+ // Property names that don't get renamed
+ private final Set<String> externedNames = new LinkedHashSet<String>(
+ Arrays.asList("prototype"));
+
+ // Names to which properties shouldn't be renamed, to avoid name conflicts
+ private final Set<String> quotedNames = new LinkedHashSet<String>();
+
+ // Shared name generator
+ private final NameGenerator nameGenerator;
+
+ private static final Comparator<Property> FREQUENCY_COMPARATOR =
+ new Comparator<Property>() {
+ @Override
+ public int compare(Property p1, Property p2) {
+
+ /**
+ * First a frequently used names would always be picked first.
+ */
+ if (p1.numOccurrences != p2.numOccurrences) {
+ return p2.numOccurrences - p1.numOccurrences;
+ }
+
+ /**
+ * Finally, for determinism, we compare them based on the old name.
+ */
+ return p1.oldName.compareTo(p2.oldName);
+ }
+ };
+
+ static final DiagnosticType BAD_CALL = DiagnosticType.error(
+ "JSC_BAD_RENAME_PROPERTY_FUNCTION_NAME_CALL",
+ "Bad {0} call - the first argument must be a string literal");
+
+ static final DiagnosticType BAD_ARG = DiagnosticType.error(
+ "JSC_BAD_RENAME_PROPERTY_FUNCTION_NAME_ARG",
+ "Bad {0} argument - ''{1}'' is not a valid JavaScript identifier");
+
+ /**
+ * Creates an instance.
+ *
+ * @param compiler The JSCompiler
+ * @param generatePseudoNames Generate pseudo names. e.g foo -> $foo$ instead
+ * of compact obfuscated names. This is used for debugging.
+ * @param nameGenerator a shared NameGenerator that this instance can use;
+ * the instance may reset or reconfigure it, so the caller should
+ * not expect any state to be preserved
+ */
+ RenamePropertiesWithModuleSupport(AbstractCompiler compiler, boolean generatePseudoNames,
+ NameGenerator nameGenerator) {
+ this(compiler, generatePseudoNames, null, null, null, nameGenerator);
+ }
+
+ /**
+ * Creates an instance.
+ *
+ * @param compiler The JSCompiler.
+ * @param generatePseudoNames Generate pseudo names. e.g foo -> $foo$ instead
+ * of compact obfuscated names. This is used for debugging.
+ * @param prevUsedPropertyMap The property renaming map used in a previous
+ * compilation.
+ * @param nameGenerator a shared NameGenerator that this instance can use;
+ * the instance may reset or reconfigure it, so the caller should
+ * not expect any state to be preserved
+ */
+ RenamePropertiesWithModuleSupport(AbstractCompiler compiler,
+ boolean generatePseudoNames, VariableMap prevUsedPropertyMap,
+ NameGenerator nameGenerator) {
+ this(compiler, generatePseudoNames, prevUsedPropertyMap, null, null, nameGenerator);
+ }
+
+ /**
+ * Creates an instance.
+ *
+ * @param compiler The JSCompiler.
+ * @param generatePseudoNames Generate pseudo names. e.g foo -> $foo$ instead of compact
+ * obfuscated names. This is used for debugging.
+ * @param prevUsedPropertyMap The property renaming map used in a previous compilation.
+ * @param reservedFirstCharacters If specified these characters won't be used in generated names
+ * for the first character
+ * @param reservedNonFirstCharacters If specified these characters won't be used in generated
+ * names for characters after the first
+ * @param nameGenerator a shared NameGenerator that this instance can use; the instance may reset
+ * or reconfigure it, so the caller should not expect any state to be preserved
+ */
+ RenamePropertiesWithModuleSupport(
+ AbstractCompiler compiler,
+ boolean generatePseudoNames,
+ VariableMap prevUsedPropertyMap,
+ @Nullable char[] reservedFirstCharacters,
+ @Nullable char[] reservedNonFirstCharacters,
+ NameGenerator nameGenerator) {
+ this.compiler = compiler;
+ this.generatePseudoNames = generatePseudoNames;
+ this.prevUsedPropertyMap = prevUsedPropertyMap;
+ this.reservedFirstCharacters = reservedFirstCharacters;
+ this.reservedNonFirstCharacters = reservedNonFirstCharacters;
+ this.nameGenerator = nameGenerator;
+ externedNames.addAll(compiler.getExternProperties());
+ }
+
+ @Override
+ public void process(Node externs, Node root) {
+ checkState(compiler.getLifeCycleStage().isNormalized());
+
+ if (prevUsedPropertyMap != null) {
+ prevUsedPropertyOldNames.addAll(prevUsedPropertyMap.getOriginalNameToNewNameMap().keySet());
+ }
+
+ NodeTraversal.traverse(compiler, root, new ProcessProperties());
+
+ Set<String> reservedNames =
+ Sets.newHashSetWithExpectedSize(externedNames.size() + quotedNames.size());
+
+ // Assign names, sorted by descending frequency to minimize code size.
+ Set<Property> propsByFreq = new TreeSet<Property>(FREQUENCY_COMPARATOR);
+ propsByFreq.addAll(propertyMap.values());
+
+ // First, try and reuse as many property names from the previous compilation
+ // as possible.
+ if (prevUsedPropertyMap != null) {
+ reusePropertyNames(reservedNames, propsByFreq);
+ }
+
+ /* add externed and quoted names after previously renamed
+ * properties are told to re-use their renames from the main
+ * app. The original code added these names before
+ * trying to reuse previous renames because those
+ * externs are typically from 3rd-party libraries, but
+ * in modules, externs are from the main loading app
+ * and we want to reuse previous renames as much as possible
+ * because classes in the main loading app will make calls
+ * using the renames instead of the exported name so any
+ * override or implementations of interface methods must
+ * also have the same rename.
+ */
+ reservedNames.addAll(externedNames);
+ reservedNames.addAll(quotedNames);
+
+ generateNames(propsByFreq, reservedNames);
+
+ // Update the string nodes.
+ for (Node n : stringNodesToRename) {
+ String oldName = n.getString();
+ Property p = propertyMap.get(oldName);
+ if (p != null && p.newName != null) {
+ checkState(oldName.equals(p.oldName));
+ n.setString(p.newName);
+ if (!p.newName.equals(oldName)) {
+ compiler.reportChangeToEnclosingScope(n);
+ }
+ }
+ }
+
+ // Update the call nodes.
+ for (Map.Entry<Node, Node> nodeEntry : callNodeToParentMap.entrySet()) {
+ Node parent = nodeEntry.getValue();
+ Node firstArg = nodeEntry.getKey().getSecondChild();
+ StringBuilder sb = new StringBuilder();
+ for (String oldName : DOT_SPLITTER.split(firstArg.getString())) {
+ Property p = propertyMap.get(oldName);
+ String replacement;
+ if (p != null && p.newName != null) {
+ checkState(oldName.equals(p.oldName));
+ replacement = p.newName;
+ } else {
+ replacement = oldName;
+ }
+ if (sb.length() > 0) {
+ sb.append('.');
+ }
+ sb.append(replacement);
+ }
+ parent.replaceChild(nodeEntry.getKey(), IR.string(sb.toString()));
+ compiler.reportChangeToEnclosingScope(parent);
+ }
+
+ // Complete queued removals.
+ for (Node n : toRemove) {
+ Node parent = n.getParent();
+ compiler.reportChangeToEnclosingScope(n);
+ n.detach();
+ NodeUtil.markFunctionsDeleted(n, compiler);
+ if (!parent.hasChildren() && !parent.isScript()) {
+ parent.detach();
+ }
+ }
+
+ compiler.setLifeCycleStage(LifeCycleStage.NORMALIZED_OBFUSCATED);
+ // This pass may rename getter or setter properties
+ GatherGettersAndSetterProperties.update(compiler, externs, root);
+ }
+
+ /**
+ * Runs through the list of properties and renames as many as possible with
+ * names from the previous compilation. Also, updates reservedNames with the
+ * set of reused names.
+ * @param reservedNames Reserved names to use during renaming.
+ * @param allProps Properties to rename.
+ */
+ private void reusePropertyNames(Set<String> reservedNames,
+ Collection<Property> allProps) {
+ for (Property prop : allProps) {
+ // Check if this node can reuse a name from a previous compilation - if
+ // it can set the newName for the property too.
+ String prevName = prevUsedPropertyMap.lookupNewName(prop.oldName);
+ if (!generatePseudoNames && prevName != null) {
+ // We can reuse prevName if it's not reserved.
+ if (reservedNames.contains(prevName)) {
+ continue;
+ }
+
+ prop.newName = prevName;
+ reservedNames.add(prevName);
+ }
+ }
+ }
+
+ /**
+ * Generates new names for properties.
+ *
+ * @param props Properties to generate new names for
+ * @param reservedNames A set of names to which properties should not be
+ * renamed
+ */
+ private void generateNames(Set<Property> props, Set<String> reservedNames) {
+ nameGenerator.reset(reservedNames, "", reservedFirstCharacters, reservedNonFirstCharacters);
+ for (Property p : props) {
+ if (generatePseudoNames) {
+ p.newName = "$" + p.oldName + "$";
+ } else {
+ // If we haven't already given this property a reusable name.
+ if (p.newName == null) {
+ p.newName = nameGenerator.generateNextName();
+ }
+ }
+ reservedNames.add(p.newName);
+ }
+ }
+
+ /**
+ * Gets the property renaming map (the "answer key").
+ *
+ * @return A mapping from original names to new names
+ */
+ VariableMap getPropertyMap() {
+ ImmutableMap.Builder<String, String> map = ImmutableMap.builder();
+ for (Property p : propertyMap.values()) {
+ if (p.newName != null) {
+ map.put(p.oldName, p.newName);
+ }
+ }
+ return new VariableMap(map.build());
+ }
+
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * A traversal callback that collects property names and counts how
+ * frequently each property name occurs.
+ */
+ private class ProcessProperties extends AbstractPostOrderCallback {
+
+ @Override
+ public void visit(NodeTraversal t, Node n, Node parent) {
+ switch (n.getToken()) {
+ case COMPUTED_PROP:
+ break;
+ case GETPROP:
+ Node propNode = n.getSecondChild();
+ if (propNode.isString()) {
+ if (compiler.getCodingConvention().blockRenamingForProperty(
+ propNode.getString())) {
+ externedNames.add(propNode.getString());
+ break;
+ }
+ maybeMarkCandidate(propNode);
+ }
+ break;
+ case OBJECTLIT:
+ for (Node key = n.getFirstChild(); key != null; key = key.getNext()) {
+ if (key.isComputedProp()) {
+ // We don't want to rename computed properties
+ continue;
+ } else if (key.isQuotedString()) {
+ // Ensure that we never rename some other property in a way
+ // that could conflict with this quoted key.
+ quotedNames.add(key.getString());
+ } else if (compiler.getCodingConvention().blockRenamingForProperty(key.getString())) {
+ externedNames.add(key.getString());
+ } else {
+ maybeMarkCandidate(key);
+ }
+ }
+ break;
+ case OBJECT_PATTERN:
+ // Iterate through all the nodes in the object pattern
+ for (Node key = n.getFirstChild(); key != null; key = key.getNext()) {
+ if (key.isComputedProp()) {
+ // We don't want to rename computed properties
+ continue;
+ } else if (key.isQuotedString()) {
+ // Ensure that we never rename some other property in a way
+ // that could conflict with this quoted key.
+ quotedNames.add(key.getString());
+ } else if (compiler.getCodingConvention().blockRenamingForProperty(key.getString())) {
+ externedNames.add(key.getString());
+ } else {
+ maybeMarkCandidate(key);
+ }
+ }
+ break;
+ case GETELEM:
+ // If this is a quoted property access (e.g. x['myprop']), we need to
+ // ensure that we never rename some other property in a way that
+ // could conflict with this quoted name.
+ Node child = n.getLastChild();
+ if (child != null && child.isString()) {
+ quotedNames.add(child.getString());
+ }
+ break;
+ case CALL: {
+ // We replace property renaming function calls with a string
+ // containing the renamed property.
+ Node fnName = n.getFirstChild();
+ if (compiler
+ .getCodingConvention()
+ .isPropertyRenameFunction(fnName.getOriginalQualifiedName())) {
+ callNodeToParentMap.put(n, parent);
+ countCallCandidates(t, n);
+ }
+ break;
+ }
+ case CLASS_MEMBERS:
+ {
+ // Replace function names defined in a class scope
+ for (Node key = n.getFirstChild(); key != null; key = key.getNext()) {
+ if (key.isComputedProp()) {
+ // We don't want to rename computed properties.
+ continue;
+ } else {
+ Node member = key.getFirstChild();
+
+ String memberDefName = key.getString();
+ if (member.isFunction()) {
+ Node fnName = member.getFirstChild();
+ if (compiler.getCodingConvention().blockRenamingForProperty(memberDefName)) {
+ externedNames.add(fnName.getString());
+ } else if (memberDefName.equals("constructor")
+ || memberDefName.equals("superClass_")) {
+ // TODO (simarora) is there a better way to identify these externs?
+ externedNames.add(fnName.getString());
+ } else {
+ maybeMarkCandidate(key);
+ }
+ }
+ }
+ }
+ break;
+ }
+ case FUNCTION:
+ {
+ // We eliminate any stub implementations of JSCompiler_renameProperty
+ // that we encounter.
+ if (NodeUtil.isFunctionDeclaration(n)) {
+ String name = n.getFirstChild().getString();
+ if (NodeUtil.JSC_PROPERTY_NAME_FN.equals(name)) {
+ toRemove.add(n);
+ }
+ } else if (parent.isName()
+ && NodeUtil.JSC_PROPERTY_NAME_FN.equals(parent.getString())) {
+ Node varNode = parent.getParent();
+ if (varNode.isVar()) {
+ toRemove.add(parent);
+ }
+ } else if (NodeUtil.isFunctionExpression(n)
+ && parent.isAssign()
+ && parent.getFirstChild().isGetProp()
+ && compiler
+ .getCodingConvention()
+ .isPropertyRenameFunction(parent.getFirstChild().getOriginalQualifiedName())) {
+ Node exprResult = parent.getParent();
+ if (exprResult.isExprResult()
+ && NodeUtil.isStatementBlock(exprResult.getParent())
+ && exprResult.getFirstChild().isAssign()) {
+ toRemove.add(exprResult);
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ /**
+ * If a property node is eligible for renaming, stashes a reference to it
+ * and increments the property name's access count.
+ *
+ * @param n The STRING node for a property
+ */
+ private void maybeMarkCandidate(Node n) {
+ String name = n.getString();
+ if (!externedNames.contains(name) || prevUsedPropertyOldNames.contains(name)) {
+ stringNodesToRename.add(n);
+ countPropertyOccurrence(name);
+ }
+ }
+
+ /**
+ * Counts references to property names that occur in a special function
+ * call.
+ *
+ * @param callNode The CALL node for a property
+ * @param t The traversal
+ */
+ private void countCallCandidates(NodeTraversal t, Node callNode) {
+ String fnName = callNode.getFirstChild().getOriginalName();
+ if (fnName == null) {
+ fnName = callNode.getFirstChild().getString();
+ }
+ Node firstArg = callNode.getSecondChild();
+ if (!firstArg.isString()) {
+ t.report(callNode, BAD_CALL, fnName);
+ return;
+ }
+
+ for (String name : DOT_SPLITTER.split(firstArg.getString())) {
+ if (!TokenStream.isJSIdentifier(name)) {
+ t.report(callNode, BAD_ARG, fnName);
+ continue;
+ }
+ if (!externedNames.contains(name) || prevUsedPropertyOldNames.contains(name)) {
+ countPropertyOccurrence(name);
+ }
+ }
+ }
+
+ /**
+ * Increments the occurrence count for a property name.
+ *
+ * @param name The property name
+ */
+ private void countPropertyOccurrence(String name) {
+ Property prop = propertyMap.get(name);
+ if (prop == null) {
+ prop = new Property(name);
+ propertyMap.put(name, prop);
+ }
+ prop.numOccurrences++;
+ }
+ }
+
+ // -------------------------------------------------------------------------
+
+ /**
+ * Encapsulates the information needed for renaming a property.
+ */
+ private static class Property {
+ final String oldName;
+ String newName;
+ int numOccurrences;
+
+ Property(String name) {
+ this.oldName = name;
+ }
+ }
+}
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/RenameVarsWithModuleSupport.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/RenameVarsWithModuleSupport.java
new file mode 100644
index 0000000..c7b104b
--- /dev/null
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/RenameVarsWithModuleSupport.java
@@ -0,0 +1,647 @@
+/*
+ * Copyright 2004 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.javascript.jscomp;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Strings.nullToEmpty;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ListMultimap;
+import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
+import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
+import com.google.javascript.rhino.Node;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.annotation.Nullable;
+
+/**
+ * Apache Royale copied RenameVars and modified it to handle
+ * Royale modules.
+ *
+ * RenameVars renames all the variables names into short names, to reduce code
+ * size and also to obfuscate the code.
+ *
+ */
+final class RenameVarsWithModuleSupport implements CompilerPass {
+
+ /**
+ * Limit on number of locals in a scope for temporary local renaming
+ * when {@code preferStableNames} is true.
+ */
+ private static final int MAX_LOCALS_IN_SCOPE_TO_TEMP_RENAME = 1000;
+
+ private final AbstractCompiler compiler;
+
+ /** List of global NAME nodes */
+ private final ArrayList<Node> globalNameNodes = new ArrayList<Node>();
+
+ /** List of local NAME nodes */
+ private final ArrayList<Node> localNameNodes = new ArrayList<Node>();
+
+ /** Mapping of original names for change detection */
+ private final Map<Node, String> originalNameByNode = new HashMap<Node, String>();
+
+ /**
+ * Maps a name node to its pseudo name, null if we are not generating so
+ * there will be no overhead unless we are debugging.
+ */
+ private final Map<Node, String> pseudoNameMap;
+
+ /** Set of extern variable names */
+ private Set<String> externNames;
+
+ /** Set of reserved variable names */
+ private final Set<String> reservedNames;
+
+ /** The renaming map */
+ private final Map<String, String> renameMap = new HashMap<String, String>();
+
+ /** The previously used rename map. */
+ private final VariableMap prevUsedRenameMap;
+
+ /** The global name prefix */
+ private final String prefix;
+
+ /** Counter for each assignment */
+ private int assignmentCount = 0;
+
+ // Logic for bleeding functions, where the name leaks into the outer
+ // scope on IE but not on other browsers.
+ private final Set<Var> localBleedingFunctions = new HashSet<Var>();
+ private final ListMultimap<Scope, Var> localBleedingFunctionsPerScope =
+ ArrayListMultimap.create();
+
+ class Assignment {
+ final boolean isLocal;
+ final String oldName;
+ final int orderOfOccurrence;
+ String newName;
+ int count; // Number of times this is referenced
+
+ Assignment(String name) {
+ this.isLocal = name.startsWith(LOCAL_VAR_PREFIX);
+ this.oldName = name;
+ this.newName = null;
+ this.count = 0;
+
+ // Represents the order at which a symbol appears in the source.
+ this.orderOfOccurrence = assignmentCount++;
+ }
+
+ /**
+ * Assigns the new name.
+ */
+ void setNewName(String newName) {
+ checkState(this.newName == null);
+ this.newName = newName;
+ }
+ }
+
+ /** Maps an old name to a new name assignment */
+ private final Map<String, Assignment> assignments =
+ new HashMap<String, Assignment>();
+
+ /** Whether renaming should apply to local variables only. */
+ private final boolean localRenamingOnly;
+
+ /**
+ * Whether function expression names should be preserved. Typically, for
+ * debugging purposes.
+ *
+ * @see NameAnonymousFunctions
+ */
+ private final boolean preserveFunctionExpressionNames;
+
+ private final boolean shouldShadow;
+
+ private final boolean preferStableNames;
+
+ /** Characters that shouldn't be used in variable names. */
+ private final char[] reservedCharacters;
+
+ /** A prefix to distinguish temporary local names from global names */
+ private static final String LOCAL_VAR_PREFIX = "L ";
+
+ // Shared name generator
+ private final NameGenerator nameGenerator;
+
+ /* list of aliases from the externs */
+ private List<String> externAliases;
+
+ /*
+ * nameGenerator is a shared NameGenerator that this instance can use;
+ * the instance may reset or reconfigure it, so the caller should
+ * not expect any state to be preserved.
+ */
+ RenameVarsWithModuleSupport(AbstractCompiler compiler, String prefix,
+ boolean localRenamingOnly, boolean preserveFunctionExpressionNames,
+ boolean generatePseudoNames, boolean shouldShadow,
+ boolean preferStableNames, VariableMap prevUsedRenameMap,
+ @Nullable char[] reservedCharacters,
+ @Nullable Set<String> reservedNames,
+ NameGenerator nameGenerator) {
+ this.compiler = compiler;
+ this.prefix = nullToEmpty(prefix);
+ this.localRenamingOnly = localRenamingOnly;
+ this.preserveFunctionExpressionNames = preserveFunctionExpressionNames;
+ if (generatePseudoNames) {
+ this.pseudoNameMap = new HashMap<Node, String>();
+ } else {
+ this.pseudoNameMap = null;
+ }
+ this.prevUsedRenameMap = prevUsedRenameMap;
+ this.reservedCharacters = reservedCharacters;
+ this.shouldShadow = shouldShadow;
+ this.preferStableNames = preferStableNames;
+ if (reservedNames == null) {
+ this.reservedNames = new HashSet<String>();
+ } else {
+ this.reservedNames = new HashSet<String>(reservedNames);
+ }
+ this.nameGenerator = nameGenerator;
+ }
+
+ /**
+ * Iterate through the nodes, collect all the NAME nodes that need to be
+ * renamed, and count how many times each variable name is referenced.
+ *
+ * Keep track of all name references in globalNameNodes, and localNameNodes.
+ *
+ * To get shorter local variable renaming, we rename local variables to a
+ * temporary name "LOCAL_VAR_PREFIX + index" where index is the index of the
+ * variable declared in the local scope stack.
+ * e.g.
+ * Foo(fa, fb) {
+ * var c = function(d, e) { return fa; }
+ * }
+ * The indexes are: fa:0, fb:1, c:2, d:3, e:4
+ *
+ * In that way, local variable names are reused in each global function.
+ * e.g. the final code might look like
+ * function x(a,b) { ... }
+ * function y(a,b,c) { ... }
+ */
+ class ProcessVars extends AbstractPostOrderCallback implements ScopedCallback {
+
+ @Override
+ public void enterScope(NodeTraversal t) {
+ if (t.inGlobalHoistScope() || !shouldTemporarilyRenameLocalsInScope(t.getScope())) {
+ return;
+ }
+ Scope scope = t.getScope();
+ for (Var current : scope.getVarIterable()) {
+ if (current.isBleedingFunction()) {
+ localBleedingFunctions.add(current);
+ localBleedingFunctionsPerScope.put(
+ scope.getParent(), current);
+ }
+ }
+ }
+
+ @Override
+ public void exitScope(NodeTraversal t) {}
+
+ @Override
+ public void visit(NodeTraversal t, Node n, Node parent) {
+ if (!(n.isName() || n.isImportStar())) {
+ return;
+ }
+
+ String name = n.getString();
+
+ // Ignore anonymous functions and classes.
+ if (name.isEmpty()) {
+ return;
+ }
+
+ // "import {x as y} from 'm';"
+ // Skip x because it's not a variable in this scope.
+ if (parent.isImportSpec() && parent.hasTwoChildren() && parent.getFirstChild() == n) {
+ return;
+ }
+
+ // Is this local or Global?
+ // Bleeding functions should be treated as part of their outer
+ // scope, because IE has bugs in how it handles bleeding
+ // functions.
+ Var var = t.getScope().getVar(name);
+ boolean local =
+ var != null
+ && var.isLocal()
+ && (var.scope.getParent().isLocal() || !var.isBleedingFunction());
+
+ // Never rename references to the arguments array
+ if (var != null && var.isArguments()) {
+ reservedNames.add(name);
+ return;
+ }
+
+ // Are we renaming global variables?
+ if (!local && localRenamingOnly) {
+ reservedNames.add(name);
+ return;
+ }
+
+ // Are we renaming function expression names?
+ if (preserveFunctionExpressionNames && var != null
+ && NodeUtil.isFunctionExpression(var.getParentNode())) {
+ reservedNames.add(name);
+ return;
+ }
+
+ // Check if we can rename this.
+ if (!okToRenameVar(name, local)) {
+ if (local) {
+ // Blindly de-uniquify for the Prototype library for
+ // http://blickly.github.io/closure-compiler-issues/#103
+ String newName = MakeDeclaredNamesUnique.ContextualRenameInverter.getOriginalName(name);
+ if (!newName.equals(name)) {
+ n.setString(newName);
+ }
+ }
+ return;
+ }
+
+ if (pseudoNameMap != null) {
+ recordPseudoName(n);
+ }
+
+ if (local && shouldTemporarilyRenameLocalsInScope(var.getScope())) {
+ // Give local variables a temporary name based on the
+ // variable's index in the scope to enable name reuse across
+ // locals in independent scopes.
+ String tempName = LOCAL_VAR_PREFIX + getLocalVarIndex(var);
+ incCount(tempName);
+ localNameNodes.add(n);
+ // Remember the original string in a name before it's temporarily filled with an "L".
+ originalNameByNode.put(n, n.getString());
+ n.setString(tempName);
+ } else if (var != null) { // Not an extern
+ // If it's global, increment global count
+ incCount(name);
+ globalNameNodes.add(n);
+ }
+ }
+
+ // Increment count of an assignment
+ void incCount(String name) {
+ Assignment s = assignments.get(name);
+ if (s == null) {
+ s = new Assignment(name);
+ assignments.put(name, s);
+ }
+ s.count++;
+ }
+ }
+
+ /**
+ * Sorts Assignment objects by their count, breaking ties by their order of
+ * occurrence in the source to ensure a deterministic total ordering.
+ */
+ private static final Comparator<Assignment> FREQUENCY_COMPARATOR =
+ new Comparator<Assignment>() {
+ @Override
+ public int compare(Assignment a1, Assignment a2) {
+ if (a1.count != a2.count) {
+ return a2.count - a1.count;
+ }
+ // Break a tie using the order in which the variable first appears in
+ // the source.
+ return ORDER_OF_OCCURRENCE_COMPARATOR.compare(a1, a2);
+ }
+ };
+
+ /**
+ * Sorts Assignment objects by the order the variable name first appears in
+ * the source.
+ */
+ private static final Comparator<Assignment> ORDER_OF_OCCURRENCE_COMPARATOR =
+ new Comparator<Assignment>() {
+ @Override
+ public int compare(Assignment a1, Assignment a2) {
+ return a1.orderOfOccurrence - a2.orderOfOccurrence;
+ }
+ };
+
+ @Override
+ public void process(Node externs, Node root) {
+ externAliases = ProcessClosurePrimitivesWithModuleSupport.externedAliases.get(externs);
+ this.externNames = NodeUtil.collectExternVariableNames(this.compiler, externs);
+
+ originalNameByNode.clear();
+
+ // Do variable reference counting.
+ NodeTraversal.traverse(compiler, root, new ProcessVars());
+
+ // Make sure that new names don't overlap with extern names.
+ reservedNames.addAll(externNames);
+
+ // Rename vars, sorted by frequency of occurrence to minimize code size.
+ SortedSet<Assignment> varsByFrequency = new TreeSet<Assignment>(FREQUENCY_COMPARATOR);
+ varsByFrequency.addAll(assignments.values());
+
+ if (shouldShadow) {
+ new ShadowVariablesWithModuleSupport(
+ compiler, assignments, varsByFrequency, pseudoNameMap).process(
+ externs, root);
+ }
+
+ // First try to reuse names from an earlier compilation.
+ if (prevUsedRenameMap != null) {
+ reusePreviouslyUsedVariableMap(varsByFrequency);
+ }
+
+ // now that previous names have been assigned,
+ // add those previous renames to reserved names
+ // so those variable names don't get re-used in assignNames.
+ if (prevUsedRenameMap != null) {
+ reservedNames.addAll(prevUsedRenameMap.getNewNameToOriginalNameMap().keySet());
+ }
+
+ // Assign names, sorted by descending frequency to minimize code size.
+ assignNames(varsByFrequency);
+
+ // Rename the globals!
+ for (Node n : globalNameNodes) {
+ /* A module may have a reference to a class
+ * but no variable defining it since the class
+ * is defined in the main loading app. Closure
+ * expects every reference to have a var so in
+ * CollapseProperties, some vars are added so that
+ * they can be collapsed. However, we don't want those
+ * added vars in the output so here we move them
+ * to externs (if we added them to the externs in
+ * CollapseProperties they wouldn't get renamed).
+ */
+ boolean moveToExternsAfterRename = false;
+ String renamedVar = n.getString();
+ if (prevUsedRenameMap != null &&
+ externAliases.contains(renamedVar) &&
+ n.getParent().isVar())
+ moveToExternsAfterRename = true;
+ setNameAndReport(n, getNewGlobalName(n));
+ if (moveToExternsAfterRename) {
+ Node p = n.getParent();
+ p.detach();
+ Node externsInput = compiler.getSynthesizedExternsInput().getAstRoot(compiler);
+ externsInput.addChildToBack(p);
+ compiler.reportChangeToEnclosingScope(p);
+ }
+ }
+
+ // Rename the locals!
+ for (Node n : localNameNodes) {
+ setNameAndReport(n, getNewLocalName(n));
+ }
+ }
+
+ private void setNameAndReport(Node n, @Nullable String newName) {
+ // A null newName, indicates it should not be renamed.
+ if (newName != null && !newName.equals(n.getString())) {
+ n.setString(newName);
+
+ // Only mark changes if the final name change is different than it was original before being
+ // filled with the "L" temporary name.
+ if (!newName.equals(originalNameByNode.get(n))) {
+ compiler.reportChangeToEnclosingScope(n);
+ Node parent = n.getParent();
+ if (parent.isFunction() && NodeUtil.isFunctionDeclaration(parent)) {
+ // If we are renaming a function declaration, make sure the containing scope
+ // has the opportunity to act on the change.
+ compiler.reportChangeToEnclosingScope(parent);
+ }
+ }
+ }
+ }
+
+ @Nullable
+ private String getNewGlobalName(Node n) {
+ String oldName = n.getString();
+ Assignment a = assignments.get(oldName);
+ if (a.newName != null && !a.newName.equals(oldName)) {
+ if (pseudoNameMap != null) {
+ return pseudoNameMap.get(n);
+ }
+ return a.newName;
+ } else {
+ return null;
+ }
+ }
+
+ @Nullable
+ private String getNewLocalName(Node n) {
+ String oldTempName = n.getString();
+ Assignment a = assignments.get(oldTempName);
+ if (!a.newName.equals(oldTempName)) {
+ if (pseudoNameMap != null) {
+ return pseudoNameMap.get(n);
+ }
+ return a.newName;
+ }
+ return null;
+ }
+
+ private void recordPseudoName(Node n) {
+ // Variable names should be in a different name space than
+ // property pseudo names.
+ pseudoNameMap.put(n, '$' + n.getString() + "$$");
+ }
+
+ /**
+ * Runs through the assignments and reuses as many names as possible from the previously used
+ * variable map. Updates reservedNames with the set of names that were reused.
+ */
+ private void reusePreviouslyUsedVariableMap(SortedSet<Assignment> varsToRename) {
+ // If prevUsedRenameMap had duplicate values then this pass would be
+ // non-deterministic.
+ // In such a case, the following will throw an IllegalArgumentException.
+ checkNotNull(prevUsedRenameMap.getNewNameToOriginalNameMap());
+ for (Assignment a : varsToRename) {
+ String prevNewName = prevUsedRenameMap.lookupNewName(a.oldName);
+ if (prevNewName == null || reservedNames.contains(prevNewName)) {
+ continue;
+ }
+
+ if (a.isLocal
+ || (!externNames.contains(a.oldName)
+ && prevNewName.startsWith(prefix))) {
+ reservedNames.add(prevNewName);
+ finalizeNameAssignment(a, prevNewName);
+ }
+ }
+ }
+
+ /**
+ * Determines which new names to substitute for the original names.
+ */
+ private void assignNames(SortedSet<Assignment> varsToRename) {
+ NameGenerator globalNameGenerator = null;
+ NameGenerator localNameGenerator = null;
+
+ globalNameGenerator = nameGenerator;
+ nameGenerator.reset(reservedNames, prefix, reservedCharacters);
+
+ // Local variables never need a prefix.
+ // Also, we need to avoid conflicts between global and local variable
+ // names; we do this by having using the same generator (not two
+ // instances). The case where global variables have a prefix (and
+ // therefore we use two different generators) but a local variable name
+ // might nevertheless conflict with a global one is not handled.
+ localNameGenerator =
+ prefix.isEmpty()
+ ? globalNameGenerator
+ : nameGenerator.clone(reservedNames, "", reservedCharacters);
+
+ // Generated names and the assignments for non-local vars.
+ List<Assignment> pendingAssignments = new ArrayList<Assignment>();
+ List<String> generatedNamesForAssignments = new ArrayList<String>();
+
+ for (Assignment a : varsToRename) {
+ if (a.newName != null) {
+ continue;
+ }
+
+ if (externNames.contains(a.oldName)) {
+ continue;
+ }
+
+ String newName;
+ if (a.isLocal) {
+ // For local variable, we make the assignment right away.
+ newName = localNameGenerator.generateNextName();
+ finalizeNameAssignment(a, newName);
+ } else {
+ // For non-local variable, delay finalizing the name assignment
+ // until we know how many new names we'll have of length 2, 3, etc.
+ newName = globalNameGenerator.generateNextName();
+ pendingAssignments.add(a);
+ generatedNamesForAssignments.add(newName);
+ }
+ reservedNames.add(newName);
+ }
+
+ // Now that we have a list of generated names, and a list of variable
+ // Assignment objects, we assign the generated names to the vars as
+ // follows:
+ // 1) The most frequent vars get the shorter names.
+ // 2) If N number of vars are going to be assigned names of the same
+ // length, we assign the N names based on the order at which the vars
+ // first appear in the source. This makes the output somewhat less
+ // random, because symbols declared close together are assigned names
+ // that are quite similar. With this heuristic, the output is more
+ // compressible.
+ // For instance, the output may look like:
+ // var da = "..", ea = "..";
+ // function fa() { .. } function ga() { .. }
+
+ int numPendingAssignments = generatedNamesForAssignments.size();
+ for (int i = 0; i < numPendingAssignments;) {
+ SortedSet<Assignment> varsByOrderOfOccurrence =
+ new TreeSet<Assignment>(ORDER_OF_OCCURRENCE_COMPARATOR);
+
+ // Add k number of Assignment to the set, where k is the number of
+ // generated names of the same length.
+ int len = generatedNamesForAssignments.get(i).length();
+ for (int j = i; j < numPendingAssignments
+ && generatedNamesForAssignments.get(j).length() == len; j++) {
+ varsByOrderOfOccurrence.add(pendingAssignments.get(j));
+ }
+
+ // Now, make the assignments
+ for (Assignment a : varsByOrderOfOccurrence) {
+ finalizeNameAssignment(a, generatedNamesForAssignments.get(i));
+ ++i;
+ }
+ }
+ }
+
+ /**
+ * Makes a final name assignment.
+ */
+ private void finalizeNameAssignment(Assignment a, String newName) {
+ a.setNewName(newName);
+
+ // Keep track of the mapping
+ renameMap.put(a.oldName, newName);
+ }
+
+ /**
+ * Gets the variable map.
+ */
+ VariableMap getVariableMap() {
+ return new VariableMap(ImmutableMap.copyOf(renameMap));
+ }
+
+ /**
+ * Determines whether a variable name is okay to rename.
+ */
+ private boolean okToRenameVar(String name, boolean isLocal) {
+ return !compiler.getCodingConvention().isExported(name, isLocal);
+ }
+
+ /**
+ * Returns the index within the scope stack.
+ * e.g. function Foo(a) { var b; function c(d) { } }
+ * a = 0, b = 1, c = 2, d = 3
+ */
+ private int getLocalVarIndex(Var v) {
+ int num = v.index;
+ Scope s = v.scope.getParent();
+ if (s == null) {
+ throw new IllegalArgumentException("Var is not local");
+ }
+
+ boolean isBleedingIntoScope = s.getParent() != null && localBleedingFunctions.contains(v);
+
+ while (s.getParent() != null) {
+ if (isBleedingIntoScope) {
+ num += localBleedingFunctionsPerScope.get(s).indexOf(v) + 1;
+ isBleedingIntoScope = false;
+ } else {
+ num += localBleedingFunctionsPerScope.get(s).size();
+ }
+ if (shouldTemporarilyRenameLocalsInScope(s)) {
+ num += s.getVarCount();
+ }
+ s = s.getParent();
+ }
+ return num;
+ }
+
+ /**
+ * Returns true if the local variables in a scope should be given
+ * temporary names (eg, 'L 123') prior to renaming to allow reuse of
+ * names across scopes. With {@code preferStableNames}, temporary
+ * renaming is disabled if the number of locals in the scope is
+ * above a heuristic threshold to allow effective reuse of rename
+ * maps (see {@code prevUsedRenameMap}). In scopes with many
+ * variables the temporary name given to a variable is unlikely to
+ * be the same temporary name used when the rename map was created.
+ */
+ private boolean shouldTemporarilyRenameLocalsInScope(Scope s) {
+ return (!preferStableNames || s.getVarCount() <= MAX_LOCALS_IN_SCOPE_TO_TEMP_RENAME);
+ }
+}
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/RoyaleClosurePassConfig.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/RoyaleClosurePassConfig.java
new file mode 100644
index 0000000..84fae02
--- /dev/null
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/RoyaleClosurePassConfig.java
@@ -0,0 +1,3496 @@
+/*
+ * Copyright 2009 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.javascript.jscomp;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.javascript.jscomp.PassFactory.createEmptyPass;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.ES2018;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.ES5;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.ES6;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.ES8;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.ES8_MODULES;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.ES_NEXT;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.TYPESCRIPT;
+import static com.google.javascript.jscomp.parsing.parser.FeatureSet.TYPE_CHECK_SUPPORTED;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.javascript.jscomp.AbstractCompiler.LifeCycleStage;
+import com.google.javascript.jscomp.CompilerOptions.ExtractPrototypeMemberDeclarationsMode;
+import com.google.javascript.jscomp.CompilerOptions.Reach;
+import com.google.javascript.jscomp.CoverageInstrumentationPass.CoverageReach;
+import com.google.javascript.jscomp.CoverageInstrumentationPass.InstrumentOption;
+import com.google.javascript.jscomp.ExtractPrototypeMemberDeclarations.Pattern;
+import com.google.javascript.jscomp.NodeTraversal.Callback;
+import com.google.javascript.jscomp.PassFactory.HotSwapPassFactory;
+import com.google.javascript.jscomp.ijs.ConvertToTypedInterface;
+import com.google.javascript.jscomp.lint.CheckArrayWithGoogObject;
+import com.google.javascript.jscomp.lint.CheckDuplicateCase;
+import com.google.javascript.jscomp.lint.CheckEmptyStatements;
+import com.google.javascript.jscomp.lint.CheckEnums;
+import com.google.javascript.jscomp.lint.CheckEs6ModuleFileStructure;
+import com.google.javascript.jscomp.lint.CheckEs6Modules;
+import com.google.javascript.jscomp.lint.CheckInterfaces;
+import com.google.javascript.jscomp.lint.CheckJSDocStyle;
+import com.google.javascript.jscomp.lint.CheckMissingSemicolon;
+import com.google.javascript.jscomp.lint.CheckNoMutatedEs6Exports;
+import com.google.javascript.jscomp.lint.CheckNullabilityModifiers;
+import com.google.javascript.jscomp.lint.CheckNullableReturn;
+import com.google.javascript.jscomp.lint.CheckPrimitiveAsObject;
+import com.google.javascript.jscomp.lint.CheckPrototypeProperties;
+import com.google.javascript.jscomp.lint.CheckRequiresAndProvidesSorted;
+import com.google.javascript.jscomp.lint.CheckUnusedLabels;
+import com.google.javascript.jscomp.lint.CheckUselessBlocks;
+import com.google.javascript.jscomp.parsing.ParserRunner;
+import com.google.javascript.jscomp.parsing.parser.FeatureSet;
+import com.google.javascript.rhino.IR;
+import com.google.javascript.rhino.Node;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/**
+ * Pass factories and meta-data for native JSCompiler passes.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ *
+ * Apache Royale copied DefaultPassConfig and modified it to replace
+ * two passes with "WithModuleSupport" passes.
+ *
+ * NOTE(dimvar): this needs some non-trivial refactoring. The pass config should
+ * use as little state as possible. The recommended way for a pass to leave
+ * behind some state for a subsequent pass is through the compiler object.
+ * Any other state remaining here should only be used when the pass config is
+ * creating the list of checks and optimizations, not after passes have started
+ * executing. For example, the field namespaceForChecks should be in Compiler.
+ */
+public final class RoyaleClosurePassConfig extends PassConfig {
+
+ /* For the --mark-as-compiled pass */
+ private static final String COMPILED_CONSTANT_NAME = "COMPILED";
+
+ /* Constant name for Closure's locale */
+ private static final String CLOSURE_LOCALE_CONSTANT_NAME = "goog.LOCALE";
+
+ static final DiagnosticType CANNOT_USE_PROTOTYPE_AND_VAR =
+ DiagnosticType.error("JSC_CANNOT_USE_PROTOTYPE_AND_VAR",
+ "Rename prototypes and inline variables cannot be used together.");
+
+ // Miscellaneous errors.
+ private static final java.util.regex.Pattern GLOBAL_SYMBOL_NAMESPACE_PATTERN =
+ java.util.regex.Pattern.compile("^[a-zA-Z0-9$_]+$");
+
+ /**
+ * A global namespace to share across checking passes.
+ */
+ private transient GlobalNamespace namespaceForChecks = null;
+
+ /** A symbol table for registering references that get removed during preprocessing. */
+ private final transient PreprocessorSymbolTable.CachedInstanceFactory
+ preprocessorSymbolTableFactory;
+
+ /**
+ * Global state necessary for doing hotswap recompilation of files with references to
+ * processed goog.modules.
+ */
+ private transient ClosureRewriteModule.GlobalRewriteState moduleRewriteState = null;
+
+ /**
+ * Whether to protect "hidden" side-effects.
+ * @see CheckSideEffects
+ */
+ private final boolean protectHiddenSideEffects;
+
+ /** name of a source file we can use to inject other code */
+ private String sourceFileName;
+
+ /** file of already renamed vars */
+ private File varRenameMapFile;
+
+ public RoyaleClosurePassConfig(CompilerOptions options, String sourceFileName, File varRenameMapFile) {
+ super(options);
+
+ // The current approach to protecting "hidden" side-effects is to
+ // wrap them in a function call that is stripped later, this shouldn't
+ // be done in IDE mode where AST changes may be unexpected.
+ protectHiddenSideEffects = options != null && options.shouldProtectHiddenSideEffects();
+ preprocessorSymbolTableFactory = new PreprocessorSymbolTable.CachedInstanceFactory();
+ this.varRenameMapFile = varRenameMapFile;
+ this.sourceFileName = sourceFileName;
+ }
+
+ GlobalNamespace getGlobalNamespace() {
+ return namespaceForChecks;
+ }
+
+ @Nullable
+ PreprocessorSymbolTable getPreprocessorSymbolTable() {
+ return preprocessorSymbolTableFactory.getInstanceOrNull();
+ }
+
+ void maybeInitializeModuleRewriteState() {
+ if (options.allowsHotswapReplaceScript() && this.moduleRewriteState == null) {
+ this.moduleRewriteState = new ClosureRewriteModule.GlobalRewriteState();
+ }
+ }
+
+ @Override
+ protected List<PassFactory> getTranspileOnlyPasses() {
+ List<PassFactory> passes = new ArrayList<PassFactory>();
+
+ if (options.needsTranspilationFrom(TYPESCRIPT)) {
+ passes.add(convertEs6TypedToEs6);
+ }
+
+ passes.add(checkVariableReferencesForTranspileOnly);
+ passes.add(gatherModuleMetadataPass);
+
+ if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) {
+ passes.add(rewriteGoogJsImports);
+ switch (options.getEs6ModuleTranspilation()) {
+ case COMPILE:
+ TranspilationPasses.addEs6ModulePass(passes, preprocessorSymbolTableFactory);
+ break;
+ case TO_COMMON_JS_LIKE_MODULES:
+ TranspilationPasses.addEs6ModuleToCjsPass(passes);
+ break;
+ case RELATIVIZE_IMPORT_PATHS:
+ TranspilationPasses.addEs6RewriteImportPathPass(passes);
+ break;
+ case NONE:
+ // nothing
+ break;
+ }
+ }
+
+ passes.add(checkSuper);
+
+ // It's important that the Dart super accessors pass run *before* es6ConvertSuper,
+ // which is a "late" ES6 pass. This is enforced in the assertValidOrder method.
+ if (options.dartPass && options.needsTranspilationFrom(ES6)) {
+ passes.add(dartSuperAccessorsPass);
+ }
+
+ TranspilationPasses.addPreTypecheckTranspilationPasses(passes, options);
+
+ TranspilationPasses.addPostCheckTranspilationPasses(passes, options);
+
+ if (options.needsTranspilationFrom(ES6)) {
+ if (options.rewritePolyfills) {
+ TranspilationPasses.addRewritePolyfillPass(passes);
+ }
+ }
+
+ passes.add(injectRuntimeLibraries);
+
+ assertAllOneTimePasses(passes);
+ assertValidOrderForChecks(passes);
+ return passes;
+ }
+
+ @Override
+ protected List<PassFactory> getWhitespaceOnlyPasses() {
+ List<PassFactory> passes = new ArrayList<PassFactory>();
+
+ if (options.processCommonJSModules) {
+ passes.add(rewriteCommonJsModules);
+ } else if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) {
+ passes.add(rewriteScriptsToEs6Modules);
+ }
+
+ if (options.wrapGoogModulesForWhitespaceOnly) {
+ passes.add(whitespaceWrapGoogModules);
+ }
+ return passes;
+ }
+
+ private void addTypeCheckerPasses(List<PassFactory> checks, CompilerOptions options) {
+ if (!options.allowsHotswapReplaceScript()) {
+ checks.add(inlineTypeAliases);
+ }
+ if (options.checkTypes || options.inferTypes) {
+ checks.add(resolveTypes);
+ checks.add(inferTypes);
+ if (options.checkTypes) {
+ checks.add(checkTypes);
+ } else {
+ checks.add(inferJsDocInfo);
+ }
+
+ // We assume that only clients who are going to re-compile, or do in-depth static analysis,
+ // will need the typed scope creator after the compile job.
+ if (!options.preservesDetailedSourceInfo() && !options.allowsHotswapReplaceScript()) {
+ checks.add(clearTypedScopePass);
+ }
+ }
+ }
+
+ @Override
+ protected List<PassFactory> getChecks() {
+ List<PassFactory> checks = new ArrayList<PassFactory>();
+
+ checks.add(gatherGettersAndSetters);
+
+ if (options.shouldGenerateTypedExterns()) {
+ checks.add(closureGoogScopeAliases);
+ checks.add(closureRewriteClass);
+ checks.add(generateIjs);
+ checks.add(whitespaceWrapGoogModules);
+ return checks;
+ }
+
+ checks.add(createEmptyPass("beforeStandardChecks"));
+
+ if (options.processCommonJSModules) {
+ checks.add(rewriteCommonJsModules);
+ } else if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) {
+ checks.add(rewriteScriptsToEs6Modules);
+ }
+
+ // Note: ChromePass can rewrite invalid @type annotations into valid ones, so should run before
+ // JsDoc checks.
+ if (options.isChromePassEnabled()) {
+ checks.add(chromePass);
+ }
+
+ // Verify JsDoc annotations and check ES6 modules
+ checks.add(checkJsDocAndEs6Modules);
+
+ if (options.needsTranspilationFrom(TYPESCRIPT)) {
+ checks.add(convertEs6TypedToEs6);
+ }
+
+ checks.add(gatherModuleMetadataPass);
+
+ if (options.enables(DiagnosticGroups.LINT_CHECKS)) {
+ checks.add(lintChecks);
+ }
+
+ if (options.closurePass && options.enables(DiagnosticGroups.LINT_CHECKS)) {
+ checks.add(checkRequiresAndProvidesSorted);
+ }
+
+ if (options.enables(DiagnosticGroups.MISSING_REQUIRE)
+ || options.enables(DiagnosticGroups.STRICT_MISSING_REQUIRE)
+ || options.enables(DiagnosticGroups.EXTRA_REQUIRE)) {
+ checks.add(checkRequires);
+ }
+
+ checks.add(checkVariableReferences);
+
+ if (options.getLanguageIn().toFeatureSet().has(FeatureSet.Feature.MODULES)) {
+ checks.add(rewriteGoogJsImports);
+ TranspilationPasses.addEs6ModulePass(checks, preprocessorSymbolTableFactory);
+ }
+
+ checks.add(checkStrictMode);
+
+ if (options.closurePass) {
+ checks.add(closureCheckModule);
+ checks.add(closureRewriteModule);
+ }
+
+ if (options.declaredGlobalExternsOnWindow) {
+ checks.add(declaredGlobalExternsOnWindow);
+ }
+
+ checks.add(checkSuper);
+
+ if (options.closurePass) {
+ checks.add(closureGoogScopeAliases);
+ checks.add(closureRewriteClass);
+ }
+
+ checks.add(checkSideEffects);
+
+ if (options.enables(DiagnosticGroups.MISSING_PROVIDE)) {
+ checks.add(checkProvides);
+ }
+
+ if (options.angularPass) {
+ checks.add(angularPass);
+ }
+
+ if (!options.generateExportsAfterTypeChecking && options.generateExports) {
+ checks.add(generateExports);
+ }
+
+ if (options.exportTestFunctions) {
+ checks.add(exportTestFunctions);
+ }
+
+ if (options.closurePass) {
+ checks.add(closurePrimitives);
+ }
+
+ // It's important that the PolymerPass run *after* the ClosurePrimitives and ChromePass rewrites
+ // and *before* the suspicious code checks. This is enforced in the assertValidOrder method.
+ if (options.polymerVersion != null) {
+ checks.add(polymerPass);
+ }
+
+ if (options.checkSuspiciousCode
+ || options.enables(DiagnosticGroups.GLOBAL_THIS)
+ || options.enables(DiagnosticGroups.DEBUGGER_STATEMENT_PRESENT)) {
+ checks.add(suspiciousCode);
+ }
+
+ if (options.closurePass && options.checkMissingGetCssNameLevel.isOn()) {
+ checks.add(closureCheckGetCssName);
+ }
+
+ if (options.syntheticBlockStartMarker != null) {
+ // This pass must run before the first fold constants pass.
+ checks.add(createSyntheticBlocks);
+ }
+
+ checks.add(checkVars);
+
+ if (options.inferConsts) {
+ checks.add(inferConsts);
+ }
+
+ if (options.computeFunctionSideEffects) {
+ checks.add(checkRegExp);
+ }
+
+ // This pass should run before types are assigned.
+ if (options.processObjectPropertyString) {
+ checks.add(objectPropertyStringPreprocess);
+ }
+
+ // It's important that the Dart super accessors pass run *before* es6ConvertSuper,
+ // which is a "late" ES6 pass. This is enforced in the assertValidOrder method.
+ if (options.dartPass && !options.getOutputFeatureSet().contains(ES6)) {
+ checks.add(dartSuperAccessorsPass);
+ }
+
+ // Passes running before this point should expect to see language features up to ES_2017.
+ checks.add(createEmptyPass(PassNames.BEFORE_ES_2017_TRANSPILATION));
+
+ TranspilationPasses.addPreTypecheckTranspilationPasses(checks, options);
+
+ if (options.rewritePolyfills && !options.checksOnly) {
+ TranspilationPasses.addRewritePolyfillPass(checks);
+ }
+
+ checks.add(injectRuntimeLibraries);
+ checks.add(createEmptyPass(PassNames.BEFORE_TYPE_CHECKING));
+
+ addTypeCheckerPasses(checks, options);
+
+ if (options.j2clPassMode.shouldAddJ2clPasses()) {
+ checks.add(j2clSourceFileChecker);
+ }
+
+ if (!options.disables(DiagnosticGroups.CHECK_USELESS_CODE)
+ || !options.disables(DiagnosticGroups.MISSING_RETURN)) {
+ checks.add(checkControlFlow);
+ }
+
+ /* The AS compiler should have checked the same thing
+ * that CheckAccessControls checks. CheckAccessControls
+ * also outputs false positives when compiling modules.
+
+ // CheckAccessControls only works if check types is on.
+ if (options.isTypecheckingEnabled()
+ && (!options.disables(DiagnosticGroups.ACCESS_CONTROLS)
+ || options.enables(DiagnosticGroups.CONSTANT_PROPERTY))) {
+ checks.add(checkAccessControls);
+ }
+ */
+
+ /* The AS compiler should have checked the same thing
+ * that CheckConsts checks. CheckConsts
+ * also outputs false positives when compiling modules.
+ checks.add(checkConsts);
+ */
+
+ // Analyzer checks must be run after typechecking.
+ if (options.enables(DiagnosticGroups.ANALYZER_CHECKS) && options.isTypecheckingEnabled()) {
+ checks.add(analyzerChecks);
+ }
+
+ if (options.checkGlobalNamesLevel.isOn()) {
+ checks.add(checkGlobalNames);
+ }
+
+ if (!options.getConformanceConfigs().isEmpty()) {
+ checks.add(checkConformance);
+ }
+
+ // Replace 'goog.getCssName' before processing defines but after the
+ // other checks have been done.
+ if (options.closurePass && !options.shouldPreserveGoogLibraryPrimitives()) {
+ checks.add(closureReplaceGetCssName);
+ }
+
+ if (options.getTweakProcessing().isOn()) {
+ checks.add(processTweaks);
+ }
+
+ if (options.instrumentationTemplate != null || options.recordFunctionInformation) {
+ checks.add(computeFunctionNames);
+ }
+
+ if (options.checksOnly) {
+ // Run process defines here so that warnings/errors from that pass are emitted as part of
+ // checks.
+ // TODO(rluble): Split process defines into two stages, one that performs only checks to be
+ // run here, and the one that actually changes the AST that would run in the optimization
+ // phase.
+ checks.add(processDefines);
+ }
+
+ if (options.j2clPassMode.shouldAddJ2clPasses()) {
+ checks.add(j2clChecksPass);
+ }
+
+ if (options.shouldRunTypeSummaryChecksLate()) {
+ checks.add(generateIjs);
+ }
+
+ // When options.generateExportsAfterTypeChecking is true, run GenerateExports after
+ // both type checkers, not just after NTI.
+ if (options.generateExportsAfterTypeChecking && options.generateExports) {
+ checks.add(generateExports);
+ }
+
+ checks.add(createEmptyPass(PassNames.AFTER_STANDARD_CHECKS));
+
+ if (!options.checksOnly) {
+ // At this point all checks have been done.
+ // There's no need to complete transpilation if we're only running checks.
+ TranspilationPasses.addPostCheckTranspilationPasses(checks, options);
+
+ if (options.needsTranspilationFrom(ES6)) {
+ // This pass used to be necessary to make the typechecker happy with class-side inheritance.
+ // It's not necessary for typechecking now that class transpilation is post-typechecking,
+ // but it turned out to be necessary to avoid CollapseProperties breaking static inheritance
+ // TODO(b/116054203): try to only run this pass when property collapsing is enabled during
+ // the optimizations. Even better, find a way to get rid of this pass completely.
+ checks.add(convertStaticInheritance);
+ }
+ }
+
+ assertAllOneTimePasses(checks);
+ assertValidOrderForChecks(checks);
+
+ return checks;
+ }
+
+ @Override
+ protected List<PassFactory> getOptimizations() {
+ List<PassFactory> passes = new ArrayList<PassFactory>();
+
+ if (options.skipNonTranspilationPasses) {
+ return passes;
+ }
+
+ passes.add(removeWeakSources);
+
+ passes.add(garbageCollectChecks);
+
+ // i18n
+ // If you want to customize the compiler to use a different i18n pass,
+ // you can create a PassConfig that calls replacePassFactory
+ // to replace this.
+ if (options.replaceMessagesWithChromeI18n) {
+ passes.add(replaceMessagesForChrome);
+ } else if (options.messageBundle != null) {
+ passes.add(replaceMessages);
+ }
+
+ // Defines in code always need to be processed.
+ passes.add(processDefines);
+
+ if (options.getTweakProcessing().shouldStrip()
+ || !options.stripTypes.isEmpty()
+ || !options.stripNameSuffixes.isEmpty()
+ || !options.stripTypePrefixes.isEmpty()
+ || !options.stripNamePrefixes.isEmpty()) {
+ passes.add(stripCode);
+ }
+
+ passes.add(normalize);
+
+ // Create extern exports after the normalize because externExports depends on unique names.
+ if (options.isExternExportsEnabled() || options.externExportsPath != null) {
+ passes.add(externExports);
+ }
+
+ // Gather property names in externs so they can be queried by the
+ // optimizing passes.
+ passes.add(gatherExternProperties);
+
+ // Should be run before runtimeTypeCheck and instrumentForCoverage as they rewrite code that
+ // this pass expects to see.
+ if (options.j2clPassMode.shouldAddJ2clPasses()) {
+ passes.add(j2clPass);
+ passes.add(j2clUtilGetDefineRewriterPass);
+ }
+
+ if (options.instrumentForCoverage) {
+ passes.add(instrumentForCodeCoverage);
+ }
+
+ if (options.runtimeTypeCheck) {
+ passes.add(runtimeTypeCheck);
+ }
+
+ passes.add(createEmptyPass(PassNames.BEFORE_STANDARD_OPTIMIZATIONS));
+
+ if (options.replaceIdGenerators) {
+ passes.add(replaceIdGenerators);
+ }
+
+ // Optimizes references to the arguments variable.
+ if (options.optimizeArgumentsArray) {
+ passes.add(optimizeArgumentsArray);
+ }
+
+ // Abstract method removal works best on minimally modified code, and also
+ // only needs to run once.
+ if (options.closurePass && (options.removeAbstractMethods || options.removeClosureAsserts)) {
+ passes.add(closureCodeRemoval);
+ }
+
+ if (options.removeJ2clAsserts) {
+ passes.add(j2clAssertRemovalPass);
+ }
+
+ // Property disambiguation should only run once and needs to be done
+ // soon after type checking, both so that it can make use of type
+ // information and so that other passes can take advantage of the renamed
+ // properties.
+ if (options.disambiguatePrivateProperties) {
+ passes.add(disambiguatePrivateProperties);
+ }
+
+ assertAllOneTimePasses(passes);
+
+ // Inline aliases so that following optimizations don't have to understand alias chains.
+ if (options.shouldCollapseProperties()) {
+ passes.add(aggressiveInlineAliases);
+ }
+
+ // Inline getters/setters in J2CL classes so that Object.defineProperties() calls (resulting
+ // from desugaring) don't block class stripping.
+ if (options.j2clPassMode.shouldAddJ2clPasses() && options.shouldCollapseProperties()) {
+ // Relies on collapseProperties-triggered aggressive alias inlining.
+ passes.add(j2clPropertyInlinerPass);
+ }
+
+ // Collapsing properties can undo constant inlining, so we do this before
+ // the main optimization loop.
+ if (options.shouldCollapseProperties()) {
+ passes.add(collapseProperties);
+ }
+
+ if (options.inferConsts) {
+ passes.add(inferConsts);
+ }
+
+ // TODO(mlourenco): Ideally this would be in getChecks() instead of getOptimizations(). But
+ // for that it needs to understand constant properties as well. See b/31301233#10.
+ // Needs to happen after inferConsts and collapseProperties. Detects whether invocations of
+ // the method goog.string.Const.from are done with an argument which is a string literal.
+ passes.add(checkConstParams);
+
+ // Running RemoveUnusedCode before disambiguate properties allows disambiguate properties to be
+ // more effective if code that would prevent disambiguation can be removed.
+ // TODO(b/66971163): Rename options since we're not actually using smartNameRemoval here now.
+ if (options.extraSmartNameRemoval && options.smartNameRemoval) {
+
+ // These passes remove code that is dead because of define flags.
+ // If the dead code is weakly typed, running these passes before property
+ // disambiguation results in more code removal.
+ // The passes are one-time on purpose. (The later runs are loopable.)
+ if (options.foldConstants && (options.inlineVariables || options.inlineLocalVariables)) {
+ passes.add(earlyInlineVariables);
+ passes.add(earlyPeepholeOptimizations);
+ }
+
+ passes.add(removeUnusedCodeOnce);
+ }
+
+ // RewritePolyfills is overly generous in the polyfills it adds. After type
+ // checking and early smart name removal, we can use the new type information
+ // to figure out which polyfilled prototype methods are actually called, and
+ // which were "false alarms" (i.e. calling a method of the same name on a
+ // user-provided class). We also remove any polyfills added by code that
+ // was smart-name-removed. This is a one-time pass, since it does not work
+ // after inlining - we do not attempt to aggressively remove polyfills used
+ // by code that is only flow-sensitively dead.
+ if (options.rewritePolyfills) {
+ passes.add(removeUnusedPolyfills);
+ }
+
+ // Property disambiguation should only run once and needs to be done
+ // soon after type checking, both so that it can make use of type
+ // information and so that other passes can take advantage of the renamed
+ // properties.
+ if (options.shouldDisambiguateProperties() && options.isTypecheckingEnabled()) {
+ passes.add(disambiguateProperties);
+ }
+
+ if (options.computeFunctionSideEffects) {
+ passes.add(markPureFunctions);
+ } else if (options.markNoSideEffectCalls) {
+ // TODO(user) The properties that this pass adds to CALL and NEW
+ // AST nodes increase the AST's in-memory size. Given that we are
+ // already running close to our memory limits, we could run into
+ // trouble if we end up using the @nosideeffects annotation a lot
+ // or compute @nosideeffects annotations by looking at function
+ // bodies. It should be easy to propagate @nosideeffects
+ // annotations as part of passes that depend on this property and
+ // store the result outside the AST (which would allow garbage
+ // collection once the pass is done).
+ passes.add(markNoSideEffectCalls);
+ }
+
+ if (options.smartNameRemoval) {
+ passes.addAll(getCodeRemovingPasses());
+ // TODO(b/66971163): Remove this early loop or rename the option that enables it
+ // to something more appropriate.
+ }
+
+ // This needs to come after the inline constants pass, which is run within
+ // the code removing passes.
+ if (options.closurePass) {
+ passes.add(closureOptimizePrimitives);
+ }
+
+ // ReplaceStrings runs after CollapseProperties in order to simplify
+ // pulling in values of constants defined in enums structures. It also runs
+ // after disambiguate properties and smart name removal so that it can
+ // correctly identify logging types and can replace references to string
+ // expressions.
+ if (!options.replaceStringsFunctionDescriptions.isEmpty()) {
+ passes.add(replaceStrings);
+ }
+
+ // TODO(user): This forces a first crack at crossChunkCodeMotion
+ // before devirtualization. Once certain functions are devirtualized,
+ // it confuses crossChunkCodeMotion ability to recognized that
+ // it is recursive.
+
+ // TODO(user): This is meant for a temporary quick win.
+ // In the future, we might want to improve our analysis in
+ // CrossChunkCodeMotion so we don't need to do this.
+ if (options.shouldRunCrossChunkCodeMotion()) {
+ passes.add(crossModuleCodeMotion);
+ }
+
+ // Method devirtualization benefits from property disambiguation so
+ // it should run after that pass but before passes that do
+ // optimizations based on global names (like cross module code motion
+ // and inline functions). Smart Name Removal does better if run before
+ // this pass.
+ if (options.devirtualizePrototypeMethods) {
+ passes.add(devirtualizePrototypeMethods);
+ }
+
+ if (options.customPasses != null) {
+ passes.add(getCustomPasses(
+ CustomPassExecutionTime.BEFORE_OPTIMIZATION_LOOP));
+ }
+
+ passes.add(createEmptyPass(PassNames.BEFORE_MAIN_OPTIMIZATIONS));
+
+ // Because FlowSensitiveInlineVariables does not operate on the global scope due to compilation
+ // time, we need to run it once before InlineFunctions so that we don't miss inlining
+ // opportunities when a function will be inlined into the global scope.
+ if (options.inlineVariables || options.inlineLocalVariables) {
+ passes.add(flowSensitiveInlineVariables);
+ }
+
+ passes.addAll(getMainOptimizationLoop());
+ passes.add(createEmptyPass(PassNames.AFTER_MAIN_OPTIMIZATIONS));
+
+ passes.add(createEmptyPass("beforeModuleMotion"));
+
+ if (options.shouldRunCrossChunkCodeMotion()) {
+ passes.add(crossModuleCodeMotion);
+ }
+
+ if (options.shouldRunCrossChunkMethodMotion()) {
+ passes.add(crossModuleMethodMotion);
+ }
+
+ passes.add(createEmptyPass("afterModuleMotion"));
+
+ // Some optimizations belong outside the loop because running them more
+ // than once would either have no benefit or be incorrect.
+ if (options.customPasses != null) {
+ passes.add(getCustomPasses(
+ CustomPassExecutionTime.AFTER_OPTIMIZATION_LOOP));
+ }
+
+ if (options.inlineVariables || options.inlineLocalVariables) {
+ passes.add(flowSensitiveInlineVariables);
+
+ // After inlining some of the variable uses, some variables are unused.
+ // Re-run remove unused vars to clean it up.
+ if (shouldRunRemoveUnusedCode()) {
+ passes.add(removeUnusedCodeOnce);
+ }
+ }
+
+ if (options.collapseAnonymousFunctions) {
+ passes.add(collapseAnonymousFunctions);
+ }
+
+ // Move functions before extracting prototype member declarations.
+ if (options.moveFunctionDeclarations
+ // renamePrefixNamescape relies on moveFunctionDeclarations
+ // to preserve semantics.
+ || options.renamePrefixNamespace != null) {
+ passes.add(moveFunctionDeclarations);
+ }
+
+ if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.MAPPED) {
+ passes.add(nameMappedAnonymousFunctions);
+ }
+
+ // The mapped name anonymous function pass makes use of information that
+ // the extract prototype member declarations pass removes so the former
+ // happens before the latter.
+ if (options.extractPrototypeMemberDeclarations != ExtractPrototypeMemberDeclarationsMode.OFF) {
+ passes.add(extractPrototypeMemberDeclarations);
+ }
+
+ if (options.shouldAmbiguateProperties()
+ && options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED
+ && options.isTypecheckingEnabled()) {
+ passes.add(ambiguateProperties);
+ }
+
+ if (options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED) {
+ passes.add(renameProperties);
+ }
+
+ // Reserve global names added to the "windows" object.
+ if (options.reserveRawExports) {
+ passes.add(gatherRawExports);
+ }
+
+ // This comes after property renaming because quoted property names must
+ // not be renamed.
+ if (options.convertToDottedProperties) {
+ passes.add(convertToDottedProperties);
+ }
+
+ // Property renaming must happen before this pass runs since this
+ // pass may convert dotted properties into quoted properties. It
+ // is beneficial to run before alias strings, alias keywords and
+ // variable renaming.
+ if (options.rewriteFunctionExpressions) {
+ passes.add(rewriteFunctionExpressions);
+ }
+
+ // This comes after converting quoted property accesses to dotted property
+ // accesses in order to avoid aliasing property names.
+ if (!options.aliasableStrings.isEmpty() || options.aliasAllStrings) {
+ passes.add(aliasStrings);
+ }
+
+ if (options.coalesceVariableNames) {
+ // Passes after this point can no longer depend on normalized AST
+ // assumptions because the code is marked as un-normalized
+ passes.add(coalesceVariableNames);
+
+ // coalesceVariables creates identity assignments and more redundant code
+ // that can be removed, rerun the peephole optimizations to clean them
+ // up.
+ if (options.foldConstants) {
+ passes.add(peepholeOptimizationsOnce);
+ }
+ }
+
+ // Passes after this point can no longer depend on normalized AST assumptions.
+ passes.add(markUnnormalized);
+
+ if (options.collapseVariableDeclarations) {
+ passes.add(exploitAssign);
+ passes.add(collapseVariableDeclarations);
+ }
+
+ // This pass works best after collapseVariableDeclarations.
+ passes.add(denormalize);
+
+ if (options.instrumentationTemplate != null) {
+ passes.add(instrumentFunctions);
+ }
+
+ if (options.variableRenaming != VariableRenamingPolicy.ALL) {
+ // If we're leaving some (or all) variables with their old names,
+ // then we need to undo any of the markers we added for distinguishing
+ // local variables ("x" -> "x$jscomp$1").
+ passes.add(invertContextualRenaming);
+ }
+
+ if (options.variableRenaming != VariableRenamingPolicy.OFF) {
+ passes.add(renameVars);
+ }
+
+ // This pass should run after names stop changing.
+ if (options.processObjectPropertyString) {
+ passes.add(objectPropertyStringPostprocess);
+ }
+
+ if (options.labelRenaming) {
+ passes.add(renameLabels);
+ }
+
+ if (options.foldConstants) {
+ passes.add(latePeepholeOptimizations);
+ }
+
+ if (options.anonymousFunctionNaming == AnonymousFunctionNamingPolicy.UNMAPPED) {
+ passes.add(nameUnmappedAnonymousFunctions);
+ }
+
+ if (protectHiddenSideEffects) {
+ passes.add(stripSideEffectProtection);
+ }
+
+ if (options.renamePrefixNamespace != null) {
+ if (!GLOBAL_SYMBOL_NAMESPACE_PATTERN.matcher(
+ options.renamePrefixNamespace).matches()) {
+ throw new IllegalArgumentException(
+ "Illegal character in renamePrefixNamespace name: "
+ + options.renamePrefixNamespace);
+ }
+ passes.add(rescopeGlobalSymbols);
+ }
+
+ // Safety checks
+ passes.add(checkAstValidity);
+ passes.add(varCheckValidity);
+
+ // Raise to ES6, if allowed
+ if (options.getOutputFeatureSet().contains(ES6)) {
+ passes.add(optimizeToEs6);
+ }
+
+ assertValidOrderForOptimizations(passes);
+ return passes;
+ }
+
+ /** Creates the passes for the main optimization loop. */
+ private List<PassFactory> getMainOptimizationLoop() {
+ List<PassFactory> passes = new ArrayList<PassFactory>();
+ if (options.inlineGetters) {
+ passes.add(inlineSimpleMethods);
+ }
+
+ passes.addAll(getCodeRemovingPasses());
+
+ if (options.getInlineFunctionsLevel() != Reach.NONE) {
+ passes.add(inlineFunctions);
+ }
+
+ if (options.shouldInlineProperties() && options.isTypecheckingEnabled()) {
+ passes.add(inlineProperties);
+ }
+
+ if (options.removeUnusedVars || options.removeUnusedLocalVars) {
+ if (options.deadAssignmentElimination) {
+ passes.add(deadAssignmentsElimination);
+
+ // The Polymer source is usually not included in the compilation, but it creates
+ // getters/setters for many properties in compiled code. Dead property assignment
+ // elimination is only safe when it knows about getters/setters. Therefore, we skip
+ // it if the polymer pass is enabled.
+ if (options.polymerVersion == null) {
+ passes.add(deadPropertyAssignmentElimination);
+ }
+ }
+ }
+
+ if (options.optimizeCalls) {
+ passes.add(optimizeCalls);
+ }
+
+ if (options.j2clPassMode.shouldAddJ2clPasses()) {
+ passes.add(j2clConstantHoisterPass);
+ passes.add(j2clClinitPass);
+ }
+
+ assertAllLoopablePasses(passes);
+ return passes;
+ }
+
+ /** Creates several passes aimed at removing code. */
+ private List<PassFactory> getCodeRemovingPasses() {
+ List<PassFactory> passes = new ArrayList<PassFactory>();
+ if (options.collapseObjectLiterals) {
+ passes.add(collapseObjectLiterals);
+ }
+
+ if (options.inlineVariables || options.inlineLocalVariables) {
+ passes.add(inlineVariables);
+ } else if (options.inlineConstantVars) {
+ passes.add(inlineConstants);
+ }
+
+ if (options.foldConstants) {
+ passes.add(peepholeOptimizations);
+ }
+
+ if (options.removeDeadCode) {
+ passes.add(removeUnreachableCode);
+ }
+
+ if (shouldRunRemoveUnusedCode()) {
+ passes.add(removeUnusedCode);
+ }
+
+ assertAllLoopablePasses(passes);
+ return passes;
+ }
+
+ private boolean shouldRunRemoveUnusedCode() {
+ return options.removeUnusedVars
+ || options.removeUnusedLocalVars
+ || options.removeUnusedPrototypeProperties
+ || options.isRemoveUnusedClassProperties()
+ || options.isRemoveUnusedConstructorProperties();
+ }
+
+ private final HotSwapPassFactory checkSideEffects =
+ new HotSwapPassFactory("checkSideEffects") {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ return new CheckSideEffects(
+ compiler, options.checkSuspiciousCode, protectHiddenSideEffects);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Removes the "protector" functions that were added by CheckSideEffects. */
+ private final PassFactory stripSideEffectProtection =
+ new PassFactory(PassNames.STRIP_SIDE_EFFECT_PROTECTION, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CheckSideEffects.StripProtection(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ /** Checks for code that is probably wrong (such as stray expressions). */
+ private final HotSwapPassFactory suspiciousCode =
+ new HotSwapPassFactory("suspiciousCode") {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ List<Callback> sharedCallbacks = new ArrayList<Callback>();
+ if (options.checkSuspiciousCode) {
+ sharedCallbacks.add(new CheckSuspiciousCode());
+ sharedCallbacks.add(new CheckDuplicateCase(compiler));
+ }
+
+ if (options.enables(DiagnosticGroups.GLOBAL_THIS)) {
+ sharedCallbacks.add(new CheckGlobalThis(compiler));
+ }
+
+ if (options.enables(DiagnosticGroups.DEBUGGER_STATEMENT_PRESENT)) {
+ sharedCallbacks.add(new CheckDebuggerStatement(compiler));
+ }
+
+ return combineChecks(compiler, sharedCallbacks);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Verify that all the passes are one-time passes. */
+ private static void assertAllOneTimePasses(List<PassFactory> passes) {
+ for (PassFactory pass : passes) {
+ checkState(pass.isOneTimePass());
+ }
+ }
+
+ /** Verify that all the passes are multi-run passes. */
+ private static void assertAllLoopablePasses(List<PassFactory> passes) {
+ for (PassFactory pass : passes) {
+ checkState(!pass.isOneTimePass());
+ }
+ }
+
+ /**
+ * Checks that {@code pass1} comes before {@code pass2} in {@code passList}, if both are present.
+ */
+ private void assertPassOrder(
+ List<PassFactory> passList, PassFactory pass1, PassFactory pass2, String msg) {
+ int pass1Index = passList.indexOf(pass1);
+ int pass2Index = passList.indexOf(pass2);
+ if (pass1Index != -1 && pass2Index != -1) {
+ checkState(pass1Index < pass2Index, msg);
+ }
+ }
+
+ /**
+ * Certain checks need to run in a particular order. For example, the PolymerPass
+ * will not work correctly unless it runs after the goog.provide() processing.
+ * This enforces those constraints.
+ * @param checks The list of check passes
+ */
+ private void assertValidOrderForChecks(List<PassFactory> checks) {
+ assertPassOrder(
+ checks,
+ chromePass,
+ checkJsDocAndEs6Modules,
+ "The ChromePass must run before after JsDoc and Es6 module checking.");
+ assertPassOrder(
+ checks,
+ closureRewriteModule,
+ processDefines,
+ "Must rewrite goog.module before processing @define's, so that @defines in modules work.");
+ assertPassOrder(
+ checks,
+ closurePrimitives,
+ polymerPass,
+ "The Polymer pass must run after goog.provide processing.");
+ assertPassOrder(
+ checks,
+ chromePass,
+ polymerPass,
+ "The Polymer pass must run after ChromePass processing.");
+ assertPassOrder(
+ checks,
+ polymerPass,
+ suspiciousCode,
+ "The Polymer pass must run before suspiciousCode processing.");
+ assertPassOrder(
+ checks,
+ dartSuperAccessorsPass,
+ TranspilationPasses.es6ConvertSuper,
+ "The Dart super accessors pass must run before ES6->ES3 super lowering.");
+
+ if (checks.contains(closureGoogScopeAliases)) {
+ checkState(
+ checks.contains(checkVariableReferences),
+ "goog.scope processing requires variable checking");
+ }
+ assertPassOrder(
+ checks,
+ checkVariableReferences,
+ closureGoogScopeAliases,
+ "Variable checking must happen before goog.scope processing.");
+
+ assertPassOrder(
+ checks,
+ gatherModuleMetadataPass,
+ closureCheckModule,
+ "Need to gather module metadata before checking closure modules.");
+ }
+
+ /**
+ * Certain optimizations need to run in a particular order. For example, OptimizeCalls must run
+ * before RemoveSuperMethodsPass, because the former can invalidate assumptions in the latter.
+ * This enforces those constraints.
+ * @param optimizations The list of optimization passes
+ */
+ private void assertValidOrderForOptimizations(List<PassFactory> optimizations) {
+ assertPassOrder(
+ optimizations,
+ processDefines,
+ j2clUtilGetDefineRewriterPass,
+ "J2CL define re-writing should be done after processDefines since it relies on "
+ + "collectDefines which has side effects.");
+ }
+
+ /** Checks that all constructed classes are goog.require()d. */
+ private final HotSwapPassFactory checkRequires =
+ new HotSwapPassFactory("checkMissingAndExtraRequires") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new CheckMissingAndExtraRequires(
+ compiler, CheckMissingAndExtraRequires.Mode.FULL_COMPILE);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Makes sure @constructor is paired with goog.provides(). */
+ private final HotSwapPassFactory checkProvides =
+ new HotSwapPassFactory("checkProvides") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new CheckProvides(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private static final DiagnosticType GENERATE_EXPORTS_ERROR =
+ DiagnosticType.error(
+ "JSC_GENERATE_EXPORTS_ERROR",
+ "Exports can only be generated if export symbol/property functions are set.");
+
+ /** Verifies JSDoc annotations are used properly and checks for ES6 modules. */
+ private final HotSwapPassFactory checkJsDocAndEs6Modules =
+ new HotSwapPassFactory("checkJsDocAndEs6Modules") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ ImmutableList.Builder<Callback> callbacks =
+ ImmutableList.<Callback>builder()
+ .add(new CheckJSDoc(compiler))
+ .add(new Es6CheckModule(compiler));
+ return combineChecks(compiler, callbacks.build());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ /** Generates exports for @export annotations. */
+ private final PassFactory generateExports =
+ new PassFactory(PassNames.GENERATE_EXPORTS, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ CodingConvention convention = compiler.getCodingConvention();
+ if (convention.getExportSymbolFunction() != null
+ && convention.getExportPropertyFunction() != null) {
+ final GenerateExports pass =
+ new GenerateExports(
+ compiler,
+ options.exportLocalPropertyDefinitions,
+ convention.getExportSymbolFunction(),
+ convention.getExportPropertyFunction());
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ pass.process(externs, root);
+ compiler.addExportedNames(pass.getExportedVariableNames());
+ }
+ };
+ } else {
+ return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR);
+ }
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ private final PassFactory generateIjs =
+ new PassFactory("generateIjs", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ConvertToTypedInterface(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Generates exports for functions associated with JsUnit. */
+ private final PassFactory exportTestFunctions =
+ new PassFactory(PassNames.EXPORT_TEST_FUNCTIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ CodingConvention convention = compiler.getCodingConvention();
+ if (convention.getExportSymbolFunction() != null) {
+ return new ExportTestFunctions(
+ compiler,
+ convention.getExportSymbolFunction(),
+ convention.getExportPropertyFunction());
+ } else {
+ return new ErrorPass(compiler, GENERATE_EXPORTS_ERROR);
+ }
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Raw exports processing pass. */
+ private final PassFactory gatherRawExports =
+ new PassFactory(PassNames.GATHER_RAW_EXPORTS, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ final GatherRawExports pass = new GatherRawExports(compiler);
+
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ pass.process(externs, root);
+ compiler.addExportedNames(pass.getExportedVariableNames());
+ }
+ };
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ // Should be FeatureSet.latest() since it's a trivial pass, but must match "normalize"
+ // TODO(johnlenz): Update this and normalize to latest()
+ return ES8_MODULES;
+ }
+ };
+
+ /** Closure pre-processing pass. */
+ private final HotSwapPassFactory closurePrimitives =
+ new HotSwapPassFactory("closurePrimitives") {
+ @SuppressWarnings("deprecation")
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ preprocessorSymbolTableFactory.maybeInitialize(compiler);
+ final ProcessClosurePrimitivesWithModuleSupport pass =
+ new ProcessClosurePrimitivesWithModuleSupport(
+ compiler,
+ preprocessorSymbolTableFactory.getInstanceOrNull(),
+ options.brokenClosureRequiresLevel,
+ options.shouldPreservesGoogProvidesAndRequires());
+
+ return new HotSwapCompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ pass.process(externs, root);
+ compiler.addExportedNames(pass.getExportedVariableNames());
+ }
+
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ pass.hotSwapScript(scriptRoot, originalRoot);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Process AngularJS-specific annotations. */
+ private final HotSwapPassFactory angularPass =
+ new HotSwapPassFactory(PassNames.ANGULAR_PASS) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new AngularPass(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /**
+ * The default i18n pass. A lot of the options are not configurable, because ReplaceMessages has a
+ * lot of legacy logic.
+ */
+ private final PassFactory replaceMessages =
+ new PassFactory(PassNames.REPLACE_MESSAGES, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new ReplaceMessages(
+ compiler,
+ options.messageBundle,
+ /* warn about message dupes */
+ true,
+ /* allow messages with goog.getMsg */
+ JsMessage.Style.CLOSURE,
+ /* if we can't find a translation, don't worry about it. */
+ false);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory replaceMessagesForChrome =
+ new PassFactory(PassNames.REPLACE_MESSAGES, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new ReplaceMessagesForChrome(
+ compiler,
+ new GoogleJsMessageIdGenerator(options.tcProjectId),
+ /* warn about message dupes */
+ true,
+ /* allow messages with goog.getMsg */
+ JsMessage.Style.CLOSURE);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Applies aliases and inlines goog.scope. */
+ private final HotSwapPassFactory closureGoogScopeAliases =
+ new HotSwapPassFactory("closureGoogScopeAliases") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ preprocessorSymbolTableFactory.maybeInitialize(compiler);
+ return new ScopedAliases(
+ compiler,
+ preprocessorSymbolTableFactory.getInstanceOrNull(),
+ options.getAliasTransformationHandler());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final PassFactory injectRuntimeLibraries =
+ new PassFactory("InjectRuntimeLibraries", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new InjectRuntimeLibraries(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ /** Desugars ES6_TYPED features into ES6 code. */
+ final HotSwapPassFactory convertEs6TypedToEs6 =
+ new HotSwapPassFactory("convertEs6Typed") {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ return new Es6TypedToEs6Converter(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPESCRIPT;
+ }
+ };
+
+ private final PassFactory convertStaticInheritance =
+ new PassFactory("Es6StaticInheritance", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new Es6ToEs3ClassSideInheritance(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ private final PassFactory inlineTypeAliases =
+ new PassFactory(PassNames.INLINE_TYPE_ALIASES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InlineAliases(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ /** Inlines type aliases if they are explicitly or effectively const. */
+ private final PassFactory aggressiveInlineAliases =
+ new PassFactory("aggressiveInlineAliases", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new AggressiveInlineAliases(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory removeWeakSources =
+ new PassFactory("removeWeakSources", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new RemoveWeakSources(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ private final PassFactory declaredGlobalExternsOnWindow =
+ new PassFactory(PassNames.DECLARED_GLOBAL_EXTERNS_ON_WINDOW, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new DeclaredGlobalExternsOnWindow(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Rewrites goog.defineClass */
+ private final HotSwapPassFactory closureRewriteClass =
+ new HotSwapPassFactory(PassNames.CLOSURE_REWRITE_CLASS) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new ClosureRewriteClass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Checks of correct usage of goog.module */
+ private final HotSwapPassFactory closureCheckModule =
+ new HotSwapPassFactory("closureCheckModule") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new ClosureCheckModule(compiler, compiler.getModuleMetadataMap());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Rewrites goog.module */
+ private final HotSwapPassFactory closureRewriteModule =
+ new HotSwapPassFactory("closureRewriteModule") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ preprocessorSymbolTableFactory.maybeInitialize(compiler);
+ maybeInitializeModuleRewriteState();
+ return new ClosureRewriteModule(
+ compiler, preprocessorSymbolTableFactory.getInstanceOrNull(), moduleRewriteState);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Rewrite imports for Closure Library's goog.js file to global goog references. */
+ private final HotSwapPassFactory rewriteGoogJsImports =
+ new HotSwapPassFactory("rewriteGoogJsImports") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new RewriteGoogJsImports(compiler, RewriteGoogJsImports.Mode.LINT_AND_REWRITE);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Checks that CSS class names are wrapped in goog.getCssName */
+ private final PassFactory closureCheckGetCssName =
+ new PassFactory("closureCheckGetCssName", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CheckMissingGetCssName(
+ compiler,
+ options.checkMissingGetCssNameLevel,
+ options.checkMissingGetCssNameBlacklist);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /**
+ * Processes goog.getCssName. The cssRenamingMap is used to lookup replacement values for the
+ * classnames. If null, the raw class names are inlined.
+ */
+ private final PassFactory closureReplaceGetCssName =
+ new PassFactory("closureReplaceGetCssName", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node jsRoot) {
+ Map<String, Integer> newCssNames = null;
+ if (options.gatherCssNames) {
+ newCssNames = new HashMap<String, Integer>();
+ }
+ ReplaceCssNames pass =
+ new ReplaceCssNames(compiler, newCssNames, options.cssRenamingWhitelist);
+ pass.process(externs, jsRoot);
+ compiler.setCssNames(newCssNames);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ /**
+ * Creates synthetic blocks to prevent FoldConstants from moving code past markers in the source.
+ */
+ private final PassFactory createSyntheticBlocks =
+ new PassFactory("createSyntheticBlocks", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CreateSyntheticBlocks(
+ compiler, options.syntheticBlockStartMarker, options.syntheticBlockEndMarker);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final PassFactory earlyPeepholeOptimizations =
+ new PassFactory("earlyPeepholeOptimizations", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ List<AbstractPeepholeOptimization> peepholeOptimizations = new ArrayList<AbstractPeepholeOptimization>();
+ peepholeOptimizations.add(new PeepholeRemoveDeadCode());
+ if (compiler.getOptions().j2clPassMode.shouldAddJ2clPasses()) {
+ peepholeOptimizations.add(new J2clEqualitySameRewriterPass());
+ }
+ return new PeepholeOptimizationsPass(compiler, getName(), peepholeOptimizations);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory earlyInlineVariables =
+ new PassFactory("earlyInlineVariables", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ InlineVariables.Mode mode;
+ if (options.inlineVariables) {
+ mode = InlineVariables.Mode.ALL;
+ } else if (options.inlineLocalVariables) {
+ mode = InlineVariables.Mode.LOCALS_ONLY;
+ } else {
+ throw new IllegalStateException("No variable inlining option set.");
+ }
+ return new InlineVariables(compiler, mode, true);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Various peephole optimizations. */
+ private static CompilerPass createPeepholeOptimizationsPass(
+ AbstractCompiler compiler, String passName) {
+ final boolean late = false;
+ final boolean useTypesForOptimization = compiler.getOptions().useTypesForLocalOptimization;
+ List<AbstractPeepholeOptimization> optimizations = new ArrayList<AbstractPeepholeOptimization>();
+ optimizations.add(new MinimizeExitPoints());
+ optimizations.add(new PeepholeMinimizeConditions(late));
+ optimizations.add(new PeepholeSubstituteAlternateSyntax(late));
+ optimizations.add(new PeepholeReplaceKnownMethods(late, useTypesForOptimization));
+ optimizations.add(new PeepholeRemoveDeadCode());
+ if (compiler.getOptions().j2clPassMode.shouldAddJ2clPasses()) {
+ optimizations.add(new J2clEqualitySameRewriterPass());
+ optimizations.add(new J2clStringValueOfRewriterPass());
+ }
+ optimizations.add(new PeepholeFoldConstants(late, useTypesForOptimization));
+ optimizations.add(new PeepholeCollectPropertyAssignments());
+ return new PeepholeOptimizationsPass(compiler, passName, optimizations);
+ }
+
+ /** Various peephole optimizations. */
+ private final PassFactory peepholeOptimizations =
+ new PassFactory(PassNames.PEEPHOLE_OPTIMIZATIONS, false /* oneTimePass */) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return createPeepholeOptimizationsPass(compiler, getName());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Various peephole optimizations. */
+ private final PassFactory peepholeOptimizationsOnce =
+ new PassFactory(PassNames.PEEPHOLE_OPTIMIZATIONS, true /* oneTimePass */) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return createPeepholeOptimizationsPass(compiler, getName());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Same as peepholeOptimizations but aggressively merges code together */
+ private final PassFactory latePeepholeOptimizations =
+ new PassFactory("latePeepholeOptimizations", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ final boolean late = true;
+ final boolean useTypesForOptimization = options.useTypesForLocalOptimization;
+ return new PeepholeOptimizationsPass(
+ compiler,
+ getName(),
+ new StatementFusion(options.aggressiveFusion),
+ new PeepholeRemoveDeadCode(),
+ new PeepholeMinimizeConditions(late),
+ new PeepholeSubstituteAlternateSyntax(late),
+ new PeepholeReplaceKnownMethods(late, useTypesForOptimization),
+ new PeepholeFoldConstants(late, useTypesForOptimization),
+ new PeepholeReorderConstantExpression());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Checks that all variables are defined. */
+ private final HotSwapPassFactory checkVars =
+ new HotSwapPassFactory(PassNames.CHECK_VARS) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new VarCheck(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Infers constants. */
+ private final PassFactory inferConsts =
+ new PassFactory(PassNames.INFER_CONSTS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InferConsts(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Checks for RegExp references. */
+ private final PassFactory checkRegExp =
+ new PassFactory(PassNames.CHECK_REG_EXP, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ final CheckRegExp pass = new CheckRegExp(compiler);
+
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ pass.process(externs, root);
+ compiler.setHasRegExpGlobalReferences(pass.isGlobalRegExpPropertiesUsed());
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Checks that references to variables look reasonable. */
+ private final HotSwapPassFactory checkVariableReferencesForTranspileOnly =
+ new HotSwapPassFactory(PassNames.CHECK_VARIABLE_REFERENCES) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new VariableReferenceCheck(compiler, true);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Checks that references to variables look reasonable. */
+ private final HotSwapPassFactory checkVariableReferences =
+ new HotSwapPassFactory(PassNames.CHECK_VARIABLE_REFERENCES) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new VariableReferenceCheck(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Checks that references to variables look reasonable. */
+ private final HotSwapPassFactory checkSuper =
+ new HotSwapPassFactory("checkSuper") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new CheckSuper(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Pre-process goog.testing.ObjectPropertyString. */
+ private final PassFactory objectPropertyStringPreprocess =
+ new PassFactory("ObjectPropertyStringPreprocess", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ObjectPropertyStringPreprocess(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Creates a typed scope and adds types to the type registry. */
+ final HotSwapPassFactory resolveTypes =
+ new HotSwapPassFactory(PassNames.RESOLVE_TYPES) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new GlobalTypeResolver(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /** Clears the typed scope when we're done. */
+ private final PassFactory clearTypedScopePass =
+ new PassFactory("clearTypedScopePass", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ClearTypedScope();
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ /** Runs type inference. */
+ final HotSwapPassFactory inferTypes =
+ new HotSwapPassFactory(PassNames.INFER_TYPES) {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ return new HotSwapCompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ checkNotNull(topScope);
+ checkNotNull(getTypedScopeCreator());
+
+ makeTypeInference(compiler).process(externs, root);
+ }
+
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ makeTypeInference(compiler).inferAllScopes(scriptRoot);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ private final HotSwapPassFactory inferJsDocInfo =
+ new HotSwapPassFactory("inferJsDocInfo") {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ return new HotSwapCompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ checkNotNull(topScope);
+ checkNotNull(getTypedScopeCreator());
+
+ makeInferJsDocInfo(compiler).process(externs, root);
+ }
+
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ makeInferJsDocInfo(compiler).hotSwapScript(scriptRoot, originalRoot);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /** Checks type usage */
+ private final HotSwapPassFactory checkTypes =
+ new HotSwapPassFactory(PassNames.CHECK_TYPES) {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ return new HotSwapCompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ checkNotNull(topScope);
+ checkNotNull(getTypedScopeCreator());
+
+ TypeCheck check = makeTypeCheck(compiler);
+ check.process(externs, root);
+ compiler.getErrorManager().setTypedPercent(check.getTypedPercent());
+ }
+
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ makeTypeCheck(compiler).check(scriptRoot, false);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /**
+ * Checks possible execution paths of the program for problems: missing return statements and dead
+ * code.
+ */
+ private final HotSwapPassFactory checkControlFlow =
+ new HotSwapPassFactory("checkControlFlow") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ List<Callback> callbacks = new ArrayList<Callback>();
+ if (!options.disables(DiagnosticGroups.CHECK_USELESS_CODE)) {
+ callbacks.add(new CheckUnreachableCode(compiler));
+ }
+ if (!options.disables(DiagnosticGroups.MISSING_RETURN)) {
+ callbacks.add(new CheckMissingReturn(compiler));
+ }
+ return combineChecks(compiler, callbacks);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ /** Checks access controls. Depends on type-inference. */
+ /*
+ private final HotSwapPassFactory checkAccessControls =
+ new HotSwapPassFactory("checkAccessControls") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new CheckAccessControls(
+ compiler, options.enforceAccessControlCodingConventions);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };*/
+
+ private final HotSwapPassFactory lintChecks =
+ new HotSwapPassFactory(PassNames.LINT_CHECKS) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ ImmutableList.Builder<Callback> callbacks =
+ ImmutableList.<Callback>builder()
+ .add(new CheckEmptyStatements(compiler))
+ .add(new CheckEnums(compiler))
+ .add(new CheckEs6ModuleFileStructure(compiler))
+ .add(new CheckEs6Modules(compiler))
+ .add(new CheckNoMutatedEs6Exports(compiler))
+ .add(new CheckInterfaces(compiler))
+ .add(new CheckJSDocStyle(compiler))
+ .add(new CheckMissingSemicolon(compiler))
+ .add(new CheckNullabilityModifiers(compiler))
+ .add(new CheckPrimitiveAsObject(compiler))
+ .add(new CheckPrototypeProperties(compiler))
+ .add(new CheckUnusedLabels(compiler))
+ .add(new CheckUselessBlocks(compiler));
+ return combineChecks(compiler, callbacks.build());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final HotSwapPassFactory analyzerChecks =
+ new HotSwapPassFactory(PassNames.ANALYZER_CHECKS) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ ImmutableList.Builder<Callback> callbacks = ImmutableList.builder();
+ if (options.enables(DiagnosticGroups.ANALYZER_CHECKS_INTERNAL)) {
+ callbacks
+ .add(new CheckNullableReturn(compiler))
+ .add(new CheckArrayWithGoogObject(compiler))
+ .add(new ImplicitNullabilityCheck(compiler));
+ }
+ // These are grouped together for better execution efficiency.
+ if (options.enables(DiagnosticGroups.UNUSED_PRIVATE_PROPERTY)) {
+ callbacks.add(new CheckUnusedPrivateProperties(compiler));
+ }
+ if (options.enables(DiagnosticGroups.MISSING_CONST_PROPERTY)) {
+ callbacks.add(new CheckConstPrivateProperties(compiler));
+ }
+ return combineChecks(compiler, callbacks.build());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ private final HotSwapPassFactory checkRequiresAndProvidesSorted =
+ new HotSwapPassFactory("checkRequiresAndProvidesSorted") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new CheckRequiresAndProvidesSorted(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Executes the given callbacks with a {@link CombinedCompilerPass}. */
+ private static HotSwapCompilerPass combineChecks(AbstractCompiler compiler,
+ List<Callback> callbacks) {
+ checkArgument(!callbacks.isEmpty());
+ return new CombinedCompilerPass(compiler, callbacks);
+ }
+
+ /** A compiler pass that resolves types in the global scope. */
+ class GlobalTypeResolver implements HotSwapCompilerPass {
+ private final AbstractCompiler compiler;
+
+ GlobalTypeResolver(AbstractCompiler compiler) {
+ this.compiler = compiler;
+ }
+
+ @Override
+ public void process(Node externs, Node root) {
+ this.compiler.setTypeCheckingHasRun(true);
+ if (topScope == null) {
+ regenerateGlobalTypedScope(compiler, root.getParent());
+ } else {
+ compiler.getTypeRegistry().resolveTypes();
+ }
+ }
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ patchGlobalTypedScope(compiler, scriptRoot);
+ }
+ }
+
+ /** A compiler pass that clears the global scope. */
+ class ClearTypedScope implements CompilerPass {
+ @Override
+ public void process(Node externs, Node root) {
+ clearTypedScope();
+ }
+ }
+
+ /** Checks global name usage. */
+ private final PassFactory checkGlobalNames =
+ new PassFactory("checkGlobalNames", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node jsRoot) {
+ // Create a global namespace for analysis by check passes.
+ // Note that this class does all heavy computation lazily,
+ // so it's OK to create it here.
+ namespaceForChecks = new GlobalNamespace(compiler, externs, jsRoot);
+ new CheckGlobalNames(compiler, options.checkGlobalNamesLevel)
+ .injectNamespace(namespaceForChecks).process(externs, jsRoot);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /** Checks that the code is ES5 strict compliant. */
+ private final PassFactory checkStrictMode =
+ new PassFactory("checkStrictMode", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new StrictModeCheck(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Process goog.tweak.getTweak() calls. */
+ private final PassFactory processTweaks = new PassFactory("processTweaks", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node jsRoot) {
+ new ProcessTweaks(compiler,
+ options.getTweakProcessing().shouldStrip(),
+ options.getTweakReplacements()).process(externs, jsRoot);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /** Override @define-annotated constants. */
+ private final PassFactory processDefines =
+ new PassFactory("processDefines", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node jsRoot) {
+ HashMap<String, Node> replacements = new HashMap<String, Node>();
+ replacements.putAll(compiler.getDefaultDefineValues());
+ replacements.putAll(getAdditionalReplacements(options));
+ replacements.putAll(options.getDefineReplacements());
+ new ProcessDefines(compiler, ImmutableMap.copyOf(replacements), !options.checksOnly)
+ .injectNamespace(namespaceForChecks)
+ .process(externs, jsRoot);
+ }
+ };
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /**
+ * Strips code for smaller compiled code. This is useful for removing debug
+ * statements to prevent leaking them publicly.
+ */
+ private final PassFactory stripCode = new PassFactory("stripCode", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node jsRoot) {
+ CompilerOptions options = compiler.getOptions();
+ StripCode pass = new StripCode(compiler, options.stripTypes, options.stripNameSuffixes,
+ options.stripTypePrefixes, options.stripNamePrefixes);
+ if (options.getTweakProcessing().shouldStrip()) {
+ pass.enableTweakStripping();
+ }
+ pass.process(externs, jsRoot);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Release references to data that is only needed during checks. */
+ final PassFactory garbageCollectChecks =
+ new HotSwapPassFactory("garbageCollectChecks") {
+ @Override
+ protected HotSwapCompilerPass create(final AbstractCompiler compiler) {
+ return new HotSwapCompilerPass() {
+ @Override
+ public void process(Node externs, Node jsRoot) {
+ // Kill the global namespace so that it can be garbage collected
+ // after all passes are through with it.
+ namespaceForChecks = null;
+ }
+
+ @Override
+ public void hotSwapScript(Node scriptRoot, Node originalRoot) {
+ process(null, null);
+ }
+ };
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ /** Checks that all constants are not modified */
+ /*
+ private final PassFactory checkConsts =
+ new PassFactory("checkConsts", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ConstCheck(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES2018;
+ }
+ };*/
+
+ /** Checks that the arguments are constants */
+ private final PassFactory checkConstParams =
+ new PassFactory(PassNames.CHECK_CONST_PARAMS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ConstParamCheck(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Computes the names of functions for later analysis. */
+ private final PassFactory computeFunctionNames =
+ new PassFactory("computeFunctionNames", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ CollectFunctionNames pass = new CollectFunctionNames(compiler);
+ pass.process(externs, root);
+ compiler.setFunctionNames(pass.getFunctionNames());
+ }
+ };
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ /** Inserts run-time type assertions for debugging. */
+ private final PassFactory runtimeTypeCheck =
+ new PassFactory(PassNames.RUNTIME_TYPE_CHECK, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new RuntimeTypeCheck(compiler, options.runtimeTypeCheckLogFunction);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ /** Generates unique ids. */
+ private final PassFactory replaceIdGenerators =
+ new PassFactory(PassNames.REPLACE_ID_GENERATORS, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ ReplaceIdGenerators pass =
+ new ReplaceIdGenerators(
+ compiler,
+ options.idGenerators,
+ options.generatePseudoNames,
+ options.idGeneratorsMapSerialized,
+ options.xidHashFunction);
+ pass.process(externs, root);
+ compiler.setIdGeneratorMap(pass.getSerializedIdMappings());
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Replace strings. */
+ private final PassFactory replaceStrings =
+ new PassFactory("replaceStrings", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ ReplaceStrings pass =
+ new ReplaceStrings(
+ compiler,
+ options.replaceStringsPlaceholderToken,
+ options.replaceStringsFunctionDescriptions,
+ options.replaceStringsReservedStrings,
+ options.replaceStringsInputMap);
+ pass.process(externs, root);
+ compiler.setStringMap(pass.getStringMap());
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Optimizes the "arguments" array. */
+ private final PassFactory optimizeArgumentsArray =
+ new PassFactory(PassNames.OPTIMIZE_ARGUMENTS_ARRAY, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new OptimizeArgumentsArray(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Remove variables set to goog.abstractMethod. */
+ private final PassFactory closureCodeRemoval =
+ new PassFactory("closureCodeRemoval", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new ClosureCodeRemoval(compiler, options.removeAbstractMethods,
+ options.removeClosureAsserts);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Special case optimizations for closure functions. */
+ private final PassFactory closureOptimizePrimitives =
+ new PassFactory("closureOptimizePrimitives", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new ClosureOptimizePrimitives(
+ compiler,
+ compiler.getOptions().propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED,
+ compiler.getOptions().getOutputFeatureSet().contains(ES6));
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Puts global symbols into a single object. */
+ private final PassFactory rescopeGlobalSymbols =
+ new PassFactory("rescopeGlobalSymbols", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new RescopeGlobalSymbols(
+ compiler,
+ options.renamePrefixNamespace,
+ options.renamePrefixNamespaceAssumeCrossChunkNames);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Collapses names in the global scope. */
+ private final PassFactory collapseProperties =
+ new PassFactory(PassNames.COLLAPSE_PROPERTIES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CollapsePropertiesWithModuleSupport(compiler, options.getPropertyCollapseLevel(), sourceFileName, varRenameMapFile);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrite properties as variables. */
+ private final PassFactory collapseObjectLiterals =
+ new PassFactory(PassNames.COLLAPSE_OBJECT_LITERALS, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InlineObjectLiterals(compiler, compiler.getUniqueNameIdSupplier());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Disambiguate property names based on the coding convention. */
+ private final PassFactory disambiguatePrivateProperties =
+ new PassFactory(PassNames.DISAMBIGUATE_PRIVATE_PROPERTIES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new DisambiguatePrivateProperties(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Disambiguate property names based on type information. */
+ private final PassFactory disambiguateProperties =
+ new PassFactory(PassNames.DISAMBIGUATE_PROPERTIES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new DisambiguateProperties(compiler, options.propertyInvalidationErrors);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrite instance methods as static methods, to make them easier to inline. */
+ private final PassFactory devirtualizePrototypeMethods =
+ new PassFactory(PassNames.DEVIRTUALIZE_PROTOTYPE_METHODS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ OptimizeCalls passes = new OptimizeCalls(compiler);
+ passes.addPass(new DevirtualizePrototypeMethods(compiler));
+ return passes;
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ /**
+ * Optimizes unused function arguments, unused return values, and inlines constant parameters.
+ * Also runs RemoveUnusedCode.
+ */
+ private final PassFactory optimizeCalls =
+ new PassFactory(PassNames.OPTIMIZE_CALLS, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ OptimizeCalls passes = new OptimizeCalls(compiler);
+ // Remove unused return values.
+ passes.addPass(new OptimizeReturns(compiler));
+ // Remove all parameters that are constants or unused.
+ passes.addPass(new OptimizeParameters(compiler));
+ return passes;
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /**
+ * Look for function calls that are pure, and annotate them
+ * that way.
+ */
+ private final PassFactory markPureFunctions =
+ new PassFactory("markPureFunctions", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new PureFunctionIdentifier.Driver(
+ compiler, options.debugFunctionSideEffectsPath);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Look for function calls that have no side effects, and annotate them that way. */
+ private final PassFactory markNoSideEffectCalls =
+ new PassFactory(PassNames.MARK_NO_SIDE_EFFECT_CALLS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new MarkNoSideEffectCalls(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ /** Inlines variables heuristically. */
+ private final PassFactory inlineVariables =
+ new PassFactory(PassNames.INLINE_VARIABLES, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ InlineVariables.Mode mode;
+ if (options.inlineVariables) {
+ mode = InlineVariables.Mode.ALL;
+ } else if (options.inlineLocalVariables) {
+ mode = InlineVariables.Mode.LOCALS_ONLY;
+ } else {
+ throw new IllegalStateException("No variable inlining option set.");
+ }
+ return new InlineVariables(compiler, mode, true);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Inlines variables that are marked as constants. */
+ private final PassFactory inlineConstants =
+ new PassFactory("inlineConstants", false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InlineVariables(compiler, InlineVariables.Mode.CONSTANTS_ONLY, true);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Use data flow analysis to remove dead branches. */
+ private final PassFactory removeUnreachableCode =
+ new PassFactory(PassNames.REMOVE_UNREACHABLE_CODE, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new UnreachableCodeElimination(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8;
+ }
+ };
+
+ /**
+ * Use data flow analysis to remove dead branches.
+ */
+ private final PassFactory removeUnusedPolyfills =
+ new PassFactory("removeUnusedPolyfills", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new RemoveUnusedPolyfills(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Inlines simple methods, like getters */
+ private final PassFactory inlineSimpleMethods =
+ new PassFactory("inlineSimpleMethods", false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InlineSimpleMethods(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Kills dead assignments. */
+ private final PassFactory deadAssignmentsElimination =
+ new PassFactory(PassNames.DEAD_ASSIGNMENT_ELIMINATION, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new DeadAssignmentsElimination(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Kills dead property assignments. */
+ private final PassFactory deadPropertyAssignmentElimination =
+ new PassFactory("deadPropertyAssignmentElimination", false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new DeadPropertyAssignmentElimination(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Inlines function calls. */
+ private final PassFactory inlineFunctions =
+ new PassFactory(PassNames.INLINE_FUNCTIONS, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InlineFunctions(
+ compiler,
+ compiler.getUniqueNameIdSupplier(),
+ options.getInlineFunctionsLevel(),
+ options.assumeStrictThis() || options.expectStrictModeInput(),
+ options.assumeClosuresOnlyCaptureReferences,
+ options.maxFunctionSizeAfterInlining);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Inlines constant properties. */
+ private final PassFactory inlineProperties =
+ new PassFactory(PassNames.INLINE_PROPERTIES, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new InlineProperties(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ private final PassFactory removeUnusedCodeOnce = getRemoveUnusedCode(true /* isOneTimePass */);
+ private final PassFactory removeUnusedCode = getRemoveUnusedCode(false /* isOneTimePass */);
+
+ private PassFactory getRemoveUnusedCode(boolean isOneTimePass) {
+ /** Removes variables that are never used. */
+ return new PassFactory(PassNames.REMOVE_UNUSED_CODE, isOneTimePass) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ boolean preserveAnonymousFunctionNames =
+ options.anonymousFunctionNaming != AnonymousFunctionNamingPolicy.OFF;
+ return new RemoveUnusedCode.Builder(compiler)
+ .removeLocalVars(options.removeUnusedLocalVars)
+ .removeGlobals(options.removeUnusedVars)
+ .preserveFunctionExpressionNames(preserveAnonymousFunctionNames)
+ .removeUnusedPrototypeProperties(options.removeUnusedPrototypeProperties)
+ .allowRemovalOfExternProperties(options.removeUnusedPrototypePropertiesInExterns)
+ .removeUnusedThisProperties(options.isRemoveUnusedClassProperties())
+ .removeUnusedObjectDefinePropertiesDefinitions(options.isRemoveUnusedClassProperties())
+ .removeUnusedConstructorProperties(options.isRemoveUnusedConstructorProperties())
+ .build();
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ }
+
+ /** Move global symbols to a deeper common module */
+ private final PassFactory crossModuleCodeMotion =
+ new PassFactory(PassNames.CROSS_CHUNK_CODE_MOTION, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CrossChunkCodeMotion(
+ compiler,
+ compiler.getModuleGraph(),
+ options.parentChunkCanSeeSymbolsDeclaredInChildren);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Move methods to a deeper common module */
+ private final PassFactory crossModuleMethodMotion =
+ new PassFactory(PassNames.CROSS_CHUNK_METHOD_MOTION, false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CrossChunkMethodMotion(
+ compiler,
+ compiler.getCrossModuleIdGenerator(),
+ // Only move properties in externs if we're not treating
+ // them as exports.
+ options.removeUnusedPrototypePropertiesInExterns,
+ options.crossChunkCodeMotionNoStubMethods);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** A data-flow based variable inliner. */
+ private final PassFactory flowSensitiveInlineVariables =
+ new PassFactory(PassNames.FLOW_SENSITIVE_INLINE_VARIABLES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new FlowSensitiveInlineVariables(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Uses register-allocation algorithms to use fewer variables. */
+ private final PassFactory coalesceVariableNames =
+ new PassFactory(PassNames.COALESCE_VARIABLE_NAMES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CoalesceVariableNames(compiler, options.generatePseudoNames);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Some simple, local collapses (e.g., {@code var x; var y;} becomes {@code var x,y;}. */
+ private final PassFactory exploitAssign =
+ new PassFactory(PassNames.EXPLOIT_ASSIGN, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new PeepholeOptimizationsPass(compiler, getName(), new ExploitAssigns());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Some simple, local collapses (e.g., {@code var x; var y;} becomes {@code var x,y;}. */
+ private final PassFactory collapseVariableDeclarations =
+ new PassFactory(PassNames.COLLAPSE_VARIABLE_DECLARATIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CollapseVariableDeclarations(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Extracts common sub-expressions. */
+ private final PassFactory extractPrototypeMemberDeclarations =
+ new PassFactory(PassNames.EXTRACT_PROTOTYPE_MEMBER_DECLARATIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ Pattern pattern;
+ switch (options.extractPrototypeMemberDeclarations) {
+ case USE_GLOBAL_TEMP:
+ pattern = Pattern.USE_GLOBAL_TEMP;
+ break;
+ case USE_IIFE:
+ pattern = Pattern.USE_IIFE;
+ break;
+ default:
+ throw new IllegalStateException("unexpected");
+ }
+
+ return new ExtractPrototypeMemberDeclarations(compiler, pattern);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8;
+ }
+ };
+
+ /** Rewrites common function definitions to be more compact. */
+ private final PassFactory rewriteFunctionExpressions =
+ new PassFactory(PassNames.REWRITE_FUNCTION_EXPRESSIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new FunctionRewriter(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ /** Collapses functions to not use the VAR keyword. */
+ private final PassFactory collapseAnonymousFunctions =
+ new PassFactory(PassNames.COLLAPSE_ANONYMOUS_FUNCTIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new CollapseAnonymousFunctions(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Moves function declarations to the top, to simulate actual hoisting. */
+ private final PassFactory moveFunctionDeclarations =
+ new PassFactory(PassNames.MOVE_FUNCTION_DECLARATIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new MoveFunctionDeclarations(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8;
+ }
+ };
+
+ private final PassFactory nameUnmappedAnonymousFunctions =
+ new PassFactory(PassNames.NAME_ANONYMOUS_FUNCTIONS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new NameAnonymousFunctions(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory nameMappedAnonymousFunctions =
+ new PassFactory(PassNames.NAME_ANONYMOUS_FUNCTIONS, true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ NameAnonymousFunctionsMapped naf =
+ new NameAnonymousFunctionsMapped(
+ compiler, options.inputAnonymousFunctionNamingMap);
+ naf.process(externs, root);
+ compiler.setAnonymousFunctionNameMap(naf.getFunctionMap());
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /**
+ * Alias string literals with global variables, to avoid creating lots of
+ * transient objects.
+ */
+ private final PassFactory aliasStrings = new PassFactory("aliasStrings", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new AliasStrings(
+ compiler,
+ compiler.getModuleGraph(),
+ options.aliasAllStrings ? null : options.aliasableStrings,
+ options.aliasStringsBlacklist,
+ options.outputJsStringUsage);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Handling for the ObjectPropertyString primitive. */
+ private final PassFactory objectPropertyStringPostprocess =
+ new PassFactory("ObjectPropertyStringPostprocess", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ObjectPropertyStringPostprocess(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ /**
+ * Renames properties so that the two properties that never appear on the same object get the same
+ * name.
+ */
+ private final PassFactory ambiguateProperties =
+ new PassFactory(PassNames.AMBIGUATE_PROPERTIES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new AmbiguateProperties(
+ compiler,
+ options.getPropertyReservedNamingFirstChars(),
+ options.getPropertyReservedNamingNonFirstChars());
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Mark the point at which the normalized AST assumptions no longer hold. */
+ private final PassFactory markUnnormalized =
+ new PassFactory("markUnnormalized", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ compiler.setLifeCycleStage(LifeCycleStage.RAW);
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ private final PassFactory normalize =
+ new PassFactory(PassNames.NORMALIZE, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new Normalize(compiler, false);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ // TODO(johnlenz): Update this and gatherRawExports to latest()
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory externExports =
+ new PassFactory(PassNames.EXTERN_EXPORTS, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ExternExportsPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ /** Denormalize the AST for code generation. */
+ private final PassFactory denormalize = new PassFactory("denormalize", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new Denormalize(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Inverting name normalization. */
+ private final PassFactory invertContextualRenaming =
+ new PassFactory("invertContextualRenaming", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return MakeDeclaredNamesUnique.getContextualRenameInverter(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Renames properties. */
+ private final PassFactory renameProperties =
+ new PassFactory("renameProperties", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ checkState(options.propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED);
+ final VariableMap prevPropertyMap = options.inputPropertyMap;
+ return new CompilerPass() {
+ @Override
+ public void process(Node externs, Node root) {
+ RenamePropertiesWithModuleSupport rprop =
+ new RenamePropertiesWithModuleSupport(
+ compiler,
+ options.generatePseudoNames,
+ prevPropertyMap,
+ options.getPropertyReservedNamingFirstChars(),
+ options.getPropertyReservedNamingNonFirstChars(),
+ options.nameGenerator);
+ rprop.process(externs, root);
+ compiler.setPropertyMap(rprop.getPropertyMap());
+ }
+ };
+ }
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Renames variables. */
+ private final PassFactory renameVars = new PassFactory("renameVars", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ final VariableMap prevVariableMap = options.inputVariableMap;
+ return new CompilerPass() {
+ @Override public void process(Node externs, Node root) {
+ compiler.setVariableMap(runVariableRenaming(
+ compiler, prevVariableMap, externs, root));
+ }
+ };
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private VariableMap runVariableRenaming(
+ AbstractCompiler compiler, VariableMap prevVariableMap,
+ Node externs, Node root) {
+ char[] reservedChars =
+ options.anonymousFunctionNaming.getReservedCharacters();
+ boolean preserveAnonymousFunctionNames =
+ options.anonymousFunctionNaming != AnonymousFunctionNamingPolicy.OFF;
+ Set<String> reservedNames = new HashSet<String>();
+ if (options.renamePrefixNamespace != null) {
+ // don't use the prefix name as a global symbol.
+ reservedNames.add(options.renamePrefixNamespace);
+ }
+ reservedNames.addAll(compiler.getExportedNames());
+ reservedNames.addAll(ParserRunner.getReservedVars());
+ RenameVarsWithModuleSupport rn = new RenameVarsWithModuleSupport(
+ compiler,
+ options.renamePrefix,
+ options.variableRenaming == VariableRenamingPolicy.LOCAL,
+ preserveAnonymousFunctionNames,
+ options.generatePseudoNames,
+ options.shadowVariables,
+ options.preferStableNames,
+ prevVariableMap,
+ reservedChars,
+ reservedNames,
+ options.nameGenerator);
+ rn.process(externs, root);
+ return rn.getVariableMap();
+ }
+
+ /** Renames labels */
+ private final PassFactory renameLabels =
+ new PassFactory("renameLabels", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new RenameLabels(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Convert bracket access to dot access */
+ private final PassFactory convertToDottedProperties =
+ new PassFactory(PassNames.CONVERT_TO_DOTTED_PROPERTIES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ConvertToDottedProperties(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory checkAstValidity =
+ new PassFactory("checkAstValidity", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new AstValidator(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ /** Checks that all variables are defined. */
+ private final PassFactory varCheckValidity =
+ new PassFactory("varCheckValidity", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new VarCheck(compiler, true);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Adds instrumentations according to an instrumentation template. */
+ private final PassFactory instrumentFunctions =
+ new PassFactory("instrumentFunctions", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new InstrumentFunctions(
+ compiler, compiler.getFunctionNames(),
+ options.instrumentationTemplate, options.appNameStr);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ private final PassFactory instrumentForCodeCoverage =
+ new PassFactory("instrumentForCodeCoverage", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ // TODO(johnlenz): make global instrumentation an option
+ if (options.instrumentBranchCoverage) {
+ return new CoverageInstrumentationPass(
+ compiler, CoverageReach.CONDITIONAL, InstrumentOption.BRANCH_ONLY);
+ } else {
+ return new CoverageInstrumentationPass(compiler, CoverageReach.CONDITIONAL);
+ }
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+
+ /** Extern property names gathering pass. */
+ private final PassFactory gatherExternProperties =
+ new PassFactory("gatherExternProperties", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new GatherExternProperties(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /**
+ * Runs custom passes that are designated to run at a particular time.
+ */
+ private PassFactory getCustomPasses(
+ final CustomPassExecutionTime executionTime) {
+ return new PassFactory("runCustomPasses", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return runInSerial(options.customPasses.get(executionTime));
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES5;
+ }
+ };
+ }
+
+ /** Create a compiler pass that runs the given passes in serial. */
+ private static CompilerPass runInSerial(
+ final Collection<CompilerPass> passes) {
+ return new CompilerPass() {
+ @Override public void process(Node externs, Node root) {
+ for (CompilerPass pass : passes) {
+ pass.process(externs, root);
+ }
+ }
+ };
+ }
+
+ @VisibleForTesting
+ static Map<String, Node> getAdditionalReplacements(CompilerOptions options) {
+ Map<String, Node> additionalReplacements = new HashMap<String, Node>();
+
+ if (options.markAsCompiled || options.closurePass) {
+ additionalReplacements.put(COMPILED_CONSTANT_NAME, IR.trueNode());
+ }
+
+ if (options.closurePass && options.locale != null) {
+ additionalReplacements.put(CLOSURE_LOCALE_CONSTANT_NAME,
+ IR.string(options.locale));
+ }
+
+ return additionalReplacements;
+ }
+
+ /** Rewrites Polymer({}) */
+ private final HotSwapPassFactory polymerPass =
+ new HotSwapPassFactory("polymerPass") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new PolymerPass(
+ compiler,
+ compiler.getOptions().polymerVersion,
+ compiler.getOptions().polymerExportPolicy,
+ compiler.getOptions().propertyRenaming == PropertyRenamingPolicy.ALL_UNQUOTED);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final PassFactory chromePass = new PassFactory("chromePass", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ChromePass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrites the super accessors calls to support Dart Dev Compiler output. */
+ private final HotSwapPassFactory dartSuperAccessorsPass =
+ new HotSwapPassFactory("dartSuperAccessorsPass") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new DartSuperAccessorsPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ /** Rewrites J2CL constructs to be more optimizable. */
+ private final PassFactory j2clConstantHoisterPass =
+ new PassFactory("j2clConstantHoisterPass", false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new J2clConstantHoisterPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Optimizes J2CL clinit methods. */
+ private final PassFactory j2clClinitPass =
+ new PassFactory("j2clClinitPass", false) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ List<Node> changedScopeNodes = compiler.getChangedScopeNodesForPass(getName());
+ return new J2clClinitPrunerPass(compiler, changedScopeNodes);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrites J2CL constructs to be more optimizable. */
+ private final PassFactory j2clPropertyInlinerPass =
+ new PassFactory("j2clES6Pass", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new J2clPropertyInlinerPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrites J2CL constructs to be more optimizable. */
+ private final PassFactory j2clPass =
+ new PassFactory("j2clPass", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new J2clPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrites J2CL constructs to be more optimizable. */
+ private final PassFactory j2clUtilGetDefineRewriterPass =
+ new PassFactory("j2clUtilGetDefineRewriterPass", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new J2clUtilGetDefineRewriterPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory j2clAssertRemovalPass =
+ new PassFactory("j2clAssertRemovalPass", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new J2clAssertRemovalPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory j2clSourceFileChecker =
+ new PassFactory("j2clSourceFileChecker", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new J2clSourceFileChecker(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return FeatureSet.latest();
+ }
+ };
+
+ private final PassFactory j2clChecksPass =
+ new PassFactory("j2clChecksPass", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new J2clChecksPass(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES2018;
+ }
+ };
+
+ private final PassFactory checkConformance =
+ new PassFactory("checkConformance", true) {
+ @Override
+ protected CompilerPass create(final AbstractCompiler compiler) {
+ return new CheckConformance(
+ compiler, ImmutableList.copyOf(options.getConformanceConfigs()));
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return TYPE_CHECK_SUPPORTED;
+ }
+ };
+
+ /** Optimizations that output ES6 features. */
+ private final PassFactory optimizeToEs6 =
+ new PassFactory("optimizeToEs6", true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new SubstituteEs6Syntax(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ /** Rewrites goog.module in whitespace only mode */
+ private final HotSwapPassFactory whitespaceWrapGoogModules =
+ new HotSwapPassFactory("whitespaceWrapGoogModules") {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new WhitespaceWrapGoogModules(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES8_MODULES;
+ }
+ };
+
+ private final PassFactory rewriteCommonJsModules =
+ new PassFactory(PassNames.REWRITE_COMMON_JS_MODULES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new ProcessCommonJSModules(compiler);
+ }
+
+ @Override
+ public FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final PassFactory rewriteScriptsToEs6Modules =
+ new PassFactory(PassNames.REWRITE_SCRIPTS_TO_ES6_MODULES, true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new Es6RewriteScriptsToModules(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final HotSwapPassFactory gatherModuleMetadataPass =
+ new HotSwapPassFactory(PassNames.GATHER_MODULE_METADATA) {
+ @Override
+ protected HotSwapCompilerPass create(AbstractCompiler compiler) {
+ return new GatherModuleMetadata(
+ compiler, options.processCommonJSModules, options.moduleResolutionMode);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+
+ private final PassFactory gatherGettersAndSetters =
+ new PassFactory(PassNames.GATHER_GETTERS_AND_SETTERS, /* isOneTimePass= */ true) {
+ @Override
+ protected CompilerPass create(AbstractCompiler compiler) {
+ return new GatherGettersAndSetterProperties(compiler);
+ }
+
+ @Override
+ protected FeatureSet featureSet() {
+ return ES_NEXT;
+ }
+ };
+}
diff --git a/compiler-jx/src/main/java/com/google/javascript/jscomp/ShadowVariablesWithModuleSupport.java b/compiler-jx/src/main/java/com/google/javascript/jscomp/ShadowVariablesWithModuleSupport.java
new file mode 100644
index 0000000..83d74ed
--- /dev/null
+++ b/compiler-jx/src/main/java/com/google/javascript/jscomp/ShadowVariablesWithModuleSupport.java
@@ -0,0 +1,333 @@
+/*
+ * Copyright 2011 The Closure Compiler Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.javascript.jscomp;
+
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.Multimap;
+import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
+import com.google.javascript.jscomp.NodeTraversal.ScopedCallback;
+import com.google.javascript.jscomp.RenameVarsWithModuleSupport.Assignment;
+import com.google.javascript.rhino.Node;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.SortedSet;
+
+/**
+ * Apache Royale copied ShadowVariables and modified it to handle
+ * Royale modules. The only change is to uses classes from
+ * RenameVarsWithModuleSupport instead of RenameVars.
+ *
+ * Tries to compute a list of variables that can shadow a variable in the
+ * outer scope.
+ *
+ * For example:
+ *
+ * <code>
+ * var a = function() {
+ * var b = getB();
+ * b();
+ * return function(y) {};
+ * };
+ * </code>
+ *
+ * Normally, b would be mapped to variable L0, y would be L1.
+ *
+ * Instead we are going to make y shadows L0 in hope of using less variables
+ * and reusing frequently used local names.
+ *
+ */
+class ShadowVariablesWithModuleSupport implements CompilerPass {
+
+ // Keep a map of Upward Referencing name nodes of each scope.
+ // A name is upward referencing name of a scope if:
+ //
+ // 1) It refers to (or defines) a name that is defined in the current
+ // scope or any scope above the current scope that isn't the
+ // global scope.
+ //
+ // 2) It is a upward referencing name of a child scope of this scope.
+ //
+ // Example:
+ // var x; var y; function foo(a) { function bar(b) { x, a } }
+ // The upward referencing names in scope 'foo' is bar, b, x and a;
+ // The key to this map is the root node of the scope.
+ //
+ // We can see that for any variable x in the current scope, we can shadow
+ // a variable y in an outer scope given that y is not a upward referencing
+ // name of the current scope.
+
+ // TODO(user): Maps scope to string instead of Node to string.
+ // Make sure of scope memorization to minimize scope creation cost.
+ private final Multimap<Node, String> scopeUpRefMap = HashMultimap.create();
+
+ // Maps each local variable to all of its referencing NAME nodes in any scope.
+ private final Multimap<Var, Reference> varToNameUsage = HashMultimap.create();
+
+ private final AbstractCompiler compiler;
+
+ // All the information used for renaming.
+ private final SortedSet<Assignment> varsByFrequency;
+ private final Map<String, Assignment> assignments;
+ private final Map<Node, String> oldPseudoNameMap;
+ private final Map<Node, String> deltaPseudoNameMap;
+
+
+ /**
+ * @param assignments Map of old variable names to its assignment Objects.
+ * @param varsByFrequency Sorted variable assignments by Frequency.
+ * @param pseudoNameMap The current pseudo name map so this pass can update
+ * it accordingly.
+ */
+ ShadowVariablesWithModuleSupport(
+ AbstractCompiler compiler,
+ Map<String, Assignment> assignments,
+ SortedSet<Assignment> varsByFrequency,
+ Map<Node, String> pseudoNameMap) {
+ this.compiler = compiler;
+ this.assignments = assignments;
+ this.varsByFrequency = varsByFrequency;
+ this.oldPseudoNameMap = pseudoNameMap;
+ this.deltaPseudoNameMap = new LinkedHashMap<Node, String>();
+ }
+
+ @Override
+ public void process(Node externs, Node root) {
+ // The algorithm is divided into two stages:
+ //
+ // 1. Information gathering (variable usage, upward referencing)
+ //
+ // 2. Tries to find shadows for each variables, updates the
+ // variable usage frequency map.
+ //
+ // 3. Updates the pseudo naming map if needed.
+ NodeTraversal.traverse(compiler, root, new GatherReferenceInfo());
+ NodeTraversal.traverse(compiler, root, new DoShadowVariables());
+
+ if (oldPseudoNameMap != null) {
+ oldPseudoNameMap.putAll(deltaPseudoNameMap);
+ }
+ }
+
+ private class GatherReferenceInfo extends AbstractPostOrderCallback {
+ @Override
+ public void visit(NodeTraversal t, Node n, Node parent) {
+ // Skipping over non-name nodes and empty function names.
+ if (!NodeUtil.isReferenceName(n)) {
+ return;
+ }
+
+ // We focus on shadowing local variables as their name occurs much more
+ // than global names.
+ // TODO(user): Alternatively, we could experiment with using a local
+ // name to shadow a global variable.
+ if (t.inGlobalScope()) {
+ return;
+ }
+
+ Scope scope = t.getScope();
+ Var var = scope.getVar(n.getString());
+ if (var == null) {
+ // extern name or undefined name.
+ return;
+ }
+
+ if (var.getScope().isGlobal()) {
+ // We will not shadow a global variable name.
+ return;
+ }
+
+ // Using the definition of upward referencing, fill in the map.
+ if (var.getScope() != scope) {
+ for (Scope s = scope; s != var.getScope() && s.isLocal(); s = s.getParent()) {
+ scopeUpRefMap.put(s.getRootNode(), var.name);
+ }
+ } else {
+ scopeUpRefMap.put(t.getScopeRoot(), var.name);
+ }
+
+ // Make sure that we don't shadow function parameters or function names from a function block
+ // scope, eg.:
+ // function f(a) { ... var a; ... } // Unsafe
+ if (scope.isFunctionScope() && var.getScope() == scope) {
+ scopeUpRefMap.put(scope.getRootNode().getLastChild(), var.name);
+ }
+
+ // Find in the usage map that tracks a var and all of its usage.
+ varToNameUsage.put(var, new Reference(n, scope));
+ }
+ }
+
+ private class DoShadowVariables extends AbstractPostOrderCallback
+ implements ScopedCallback {
+
+ @Override
+ public void enterScope(NodeTraversal t) {
+ if (t.inGlobalScope()) {
+ return;
+ }
+
+ // Since we don't shadow global, there is nothing to be done in the
+ // first immediate local scope as well.
+ Node scopeRoot = t.getScopeRoot();
+ if ((scopeRoot.isFunction()
+ && NodeUtil.getEnclosingFunction(scopeRoot.getParent()) == null)
+ || (NodeUtil.isFunctionBlock(scopeRoot)
+ && NodeUtil.getEnclosingFunction(scopeRoot.getGrandparent()) == null)) {
+ return;
+ }
+
+ Scope s = t.getScope();
+ for (Var var : s.getVarIterable()) {
+ // Don't shadow variables that are bleed-out functions or caught exceptions to workaround
+ // IE8 bugs.
+ // TODO(moz): Gate this behind languageMode=ES3.
+ if (var.isBleedingFunction() || var.isCatch()) {
+ continue;
+ }
+
+ // Don't shadow an exported local.
+ if (compiler.getCodingConvention().isExported(var.name, s.isLocal())) {
+ continue;
+ }
+
+ // The name assignment being shadowed.
+ Assignment localAssignment = assignments.get(var.getName());
+ if (localAssignment == null) {
+ continue;
+ }
+ // Try to run this check last as it is more expensive than the above checks.
+
+ // Try to look for the best shadow for the current candidate.
+ Assignment bestShadow = findBestShadow(s, var);
+ if (bestShadow == null) {
+ continue;
+ }
+
+ // Only shadow if this increases the number of occurrences of the
+ // shadowed variable.
+ if (bestShadow.count < localAssignment.count) {
+ continue; // Hope the next local variable would have a smaller count.
+ }
+
+ doShadow(localAssignment, bestShadow, var);
+
+ if (oldPseudoNameMap != null) {
+ String targetPseudoName =
+ oldPseudoNameMap.get(s.getVar(bestShadow.oldName).nameNode);
+ for (Reference use : varToNameUsage.get(var)) {
+ deltaPseudoNameMap.put(use.nameNode, targetPseudoName);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void exitScope(NodeTraversal t) {}
+
+ @Override
+ public void visit(NodeTraversal t, Node n, Node parent) {}
+
+ /**
+ * @return An assignment that can be used as a shadow for a local variable
+ * in the scope defined by curScopeRoot.
+ */
+ private Assignment findBestShadow(Scope curScope, Var var) {
+ // Search for the candidate starting from the most used local.
+ for (Assignment assignment : varsByFrequency) {
+ if (assignment.isLocal) {
+ if (!scopeUpRefMap.containsEntry(curScope.getRootNode(), assignment.oldName)) {
+ if (curScope.hasSlot(assignment.oldName)) {
+ // Don't shadow if the scopes are the same eg.:
+ // function f() { var a = 1; { var a = 2; } } // Unsafe
+ Var toShadow = curScope.getVar(assignment.oldName);
+ if (var.getScope() != toShadow.getScope()) {
+ return assignment;
+ }
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private void doShadow(Assignment original, Assignment toShadow, Var var) {
+ Scope s = var.getScope();
+ // We are now shadowing 'bestShadow' with localAssignment.
+ // All of the reference NAME node of this variable.
+ Collection<Reference> references = varToNameUsage.get(var);
+
+ // First remove both assignments from the sorted list since they need
+ // to be re-sorted.
+ varsByFrequency.remove(original);
+ varsByFrequency.remove(toShadow);
+
+ // Adjust the count offset by the inner scope variable.
+ original.count -= references.size();
+ toShadow.count += references.size();
+
+ // Add it back to the sorted list after re-adjustment.
+ varsByFrequency.add(original);
+ varsByFrequency.add(toShadow);
+
+ // This is an important step. If variable L7 is going to be renamed to
+ // L1, by definition of upward referencing, The name L1 is now in the
+ // set of upward referencing names of the current scope up to the
+ // declaring scope of the best shadow variable.
+ Var shadowed = s.getVar(toShadow.oldName);
+ if (shadowed != null) {
+ if (s.isFunctionScope() && s.getRootNode().getLastChild().isBlock()) {
+ scopeUpRefMap.put(s.getRootNode().getLastChild(), toShadow.oldName);
+ scopeUpRefMap.remove(s.getRootNode().getLastChild(), original.oldName);
+ }
+ for (Scope curScope = s; curScope != shadowed.scope; curScope = curScope.getParent()) {
+ scopeUpRefMap.put(curScope.getRootNode(), toShadow.oldName);
+ scopeUpRefMap.remove(curScope.getRootNode(), original.oldName);
+ }
+ }
+
+ // Mark all the references as shadowed.
+ for (Reference ref : references) {
+ Node n = ref.nameNode;
+ n.setString(toShadow.oldName);
+ if (ref.scope.getRootNode() == s.getRootNode()) {
+ if (var.getNameNode() != ref.nameNode) {
+ scopeUpRefMap.put(s.getRootNode(), toShadow.oldName);
+ scopeUpRefMap.remove(s.getRootNode(), original.oldName);
+ }
+ } else {
+ for (Scope curScope = ref.scope;
+ curScope.getRootNode() != s.getRootNode();
+ curScope = curScope.getParent()) {
+ scopeUpRefMap.put(curScope.getRootNode(), toShadow.oldName);
+ scopeUpRefMap.remove(curScope.getRootNode(), original.oldName);
+ }
+ }
+ }
+ }
+ }
+
+ private static final class Reference {
+ private final Node nameNode;
+ private final Scope scope;
+
+ private Reference(Node nameNode, Scope scope) {
+ this.nameNode = nameNode;
+ this.scope = scope;
+ }
+ }
+}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/asdoc/royale/ASDocComment.java b/compiler-jx/src/main/java/org/apache/royale/compiler/asdoc/royale/ASDocComment.java
index a1006dc..54c3af6 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/asdoc/royale/ASDocComment.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/asdoc/royale/ASDocComment.java
@@ -121,6 +121,9 @@
tagMap = new HashMap<String, List<IASDocTag>>();
int after = line.indexOf(" ", at + 1);
+ int tabAfter = line.indexOf("\t", at + 1);
+ if (tabAfter != -1 && after != -1 && tabAfter < after)
+ after = tabAfter;
if (after == -1)
{
tagMap.put(line.substring(at + 1), null);
@@ -134,7 +137,7 @@
tags = new ArrayList<IASDocTag>();
tagMap.put(tagName, tags);
}
- tags.add(new ASDocTag(tagName, line.substring(after + 1)));
+ tags.add(new ASDocTag(tagName, line.substring(after + 1).trim()));
}
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/ASDOCJSC.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/ASDOCJSC.java
index d8c4601..133cfa0 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/ASDOCJSC.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/ASDOCJSC.java
@@ -249,7 +249,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSC.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSC.java
index f4201e2..23da56e 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSC.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSC.java
@@ -26,11 +26,14 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
+import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -46,7 +49,6 @@
import org.apache.royale.compiler.exceptions.ConfigurationException;
import org.apache.royale.compiler.exceptions.ConfigurationException.IOError;
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
-import org.apache.royale.compiler.internal.codegen.js.JSWriter;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogCompcConfiguration;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.targets.RoyaleSWCTarget;
@@ -167,7 +169,8 @@
* @param args command line arguments
* @return exit code
*/
- private int _mainNoExit(final String[] args,
+ @SuppressWarnings("incomplete-switch")
+ private int _mainNoExit(final String[] args,
List<ICompilerProblem> outProblems)
{
System.out.println("args:");
@@ -184,9 +187,9 @@
if (continueCompilation)
{
- List<String> targets = config.getCompilerTargets();
- for (String target : targets)
- System.out.println("target:" + target);
+ List<String> targets = config.getCompilerTargets();
+ for (String target : targets)
+ System.out.println("target:" + target);
targetloop:
for (String target : config.getCompilerTargets())
{
@@ -194,7 +197,7 @@
switch (JSTargetType.fromString(target))
{
case SWF:
- System.out.println("COMPC");
+ System.out.println("COMPC");
COMPC compc = new COMPC();
mxmlc = compc;
compc.configurationClass = JSGoogCompcConfiguration.class;
@@ -206,7 +209,7 @@
}
break;
case JS_ROYALE:
- System.out.println("COMPCJSCRoyale");
+ System.out.println("COMPCJSCRoyale");
COMPJSCRoyale royale = new COMPJSCRoyale();
lastCompiler = royale;
result = royale.mainNoExit(removeASArgs(args), problems.getProblems(), false);
@@ -340,9 +343,18 @@
if (!entry.getName().contains("js/out") &&
!entry.getName().contains(SWCReader.CATALOG_XML))
{
- System.out.println("Copy " + entry.getName());
+ if (config.isVerbose())
+ {
+ System.out.println("Copy " + entry.getName());
+ }
InputStream input = zipFile.getInputStream(entry);
- zipOutputStream.putNextEntry(new ZipEntry(entry.getName()));
+ ZipEntry ze = new ZipEntry(entry.getName());
+ ze.setMethod(ZipEntry.STORED);
+ ze.setTime(entry.getTime());
+ ze.setSize(entry.getSize());
+ ze.setCompressedSize(entry.getCompressedSize());
+ ze.setCrc(entry.getCrc());
+ zipOutputStream.putNextEntry(ze);
IOUtils.copy(input, zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
@@ -395,7 +407,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder, true);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
@@ -437,7 +452,10 @@
}
else
{
- System.out.println("Compiling file: " + cu.getQualifiedNames().get(0));
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + cu.getQualifiedNames().get(0));
+ }
ICompilationUnit unit = cu;
@@ -457,37 +475,107 @@
problems.addAll(errors);
ByteArrayOutputStream temp = new ByteArrayOutputStream();
ByteArrayOutputStream sourceMapTemp = null;
- if (project.config.getSourceMap())
+
+ boolean isExterns = false;
+ if(cu.getDefinitionPromises().size() > 0)
+ {
+ isExterns = project.isExterns(cu.getDefinitionPromises().get(0).getQualifiedName());
+ }
+
+ // if the file is @externs DON'T create source map file
+ if (project.config.getSourceMap() && !isExterns)
{
sourceMapTemp = new ByteArrayOutputStream();
}
writer.writeTo(temp, sourceMapTemp, null);
- boolean isExterns = false;
- if (writer instanceof JSWriter)
- isExterns = ((JSWriter)writer).isExterns();
String outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0),
isExterns ? externsOut : jsOut,
false).getPath();
- System.out.println("Writing file: " + outputClassFile);
- zipOutputStream.putNextEntry(new ZipEntry(outputClassFile));
- temp.writeTo(zipOutputStream);
+ outputClassFile = outputClassFile.replace('\\', '/');
+ if (config.isVerbose())
+ {
+ System.out.println("Writing file: " + outputClassFile);
+ }
+ long fileDate = System.currentTimeMillis();
+ long zipFileDate = fileDate;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ // strip off timezone. Zip format doesn't store timezone
+ // and the goal is to have the same date and time regardless
+ // of which timezone the build machine is using.
+ int c = metadataDate.lastIndexOf(" ");
+ metadataDate = metadataDate.substring(0, c);
+ c = metadataFormat.lastIndexOf(" ");
+ metadataFormat = metadataFormat.substring(0, c);
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ zipFileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
+ ZipEntry ze = new ZipEntry(outputClassFile);
+ ze.setTime(zipFileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ temp.writeTo(baos);
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+
+ zipOutputStream.putNextEntry(ze);
+ baos.writeTo(zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
- fileList.append(" <file path=\"" + outputClassFile + "\" mod=\"" + System.currentTimeMillis() + "\"/>\n");
+ fileList.append(" <file path=\"" + outputClassFile + "\" mod=\"" + fileDate + "\"/>\n");
if(sourceMapTemp != null)
{
String sourceMapFile = getOutputSourceMapFile(
cu.getQualifiedNames().get(0),
isExterns ? externsOut : jsOut,
false).getPath();
- System.out.println("Writing file: " + sourceMapFile);
- zipOutputStream.putNextEntry(new ZipEntry(sourceMapFile));
- sourceMapTemp.writeTo(zipOutputStream);
+ if (config.isVerbose())
+ {
+ System.out.println("Writing file: " + sourceMapFile);
+ }
+ ze = new ZipEntry(sourceMapFile);
+ ze.setTime(zipFileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ baos = new ByteArrayOutputStream();
+ sourceMapTemp.writeTo(baos);
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+
+ zipOutputStream.putNextEntry(ze);
+ baos.writeTo(zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
- fileList.append(" <file path=\"" + sourceMapFile + "\" mod=\"" + System.currentTimeMillis() + "\"/>\n");
+ fileList.append(" <file path=\"" + sourceMapFile + "\" mod=\"" + fileDate + "\"/>\n");
}
writer.close();
}
@@ -496,12 +584,57 @@
if (packingSWC)
{
zipFile.close();
+ long fileDate = System.currentTimeMillis();
+ long zipFileDate = fileDate;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ // strip off timezone. Zip format doesn't store timezone
+ // and the goal is to have the same date and time regardless
+ // of which timezone the build machine is using.
+ int c = metadataDate.lastIndexOf(" ");
+ metadataDate = metadataDate.substring(0, c);
+ c = metadataFormat.lastIndexOf(" ");
+ metadataFormat = metadataFormat.substring(0, c);
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ zipFileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
int libraryIndex = catalog.indexOf("</libraries>");
catalog = catalog.substring(0, libraryIndex + 13) +
" <files>\n" + fileList.toString() + " </files>" +
catalog.substring(libraryIndex + 13);
- zipOutputStream.putNextEntry(new ZipEntry(SWCReader.CATALOG_XML));
- zipOutputStream.write(catalog.getBytes());
+ ZipEntry ze = new ZipEntry(SWCReader.CATALOG_XML);
+ ze.setTime(zipFileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(catalog.getBytes());
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+
+ zipOutputStream.putNextEntry(ze);
+ baos.writeTo(zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
zipOutputStream.flush();
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCNative.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCNative.java
index 8a13875..57d2ead 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCNative.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCNative.java
@@ -45,7 +45,6 @@
import org.apache.royale.compiler.exceptions.ConfigurationException;
import org.apache.royale.compiler.exceptions.ConfigurationException.IOError;
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
-import org.apache.royale.compiler.internal.codegen.js.JSWriter;
import org.apache.royale.compiler.internal.driver.mxml.jsc.MXMLJSCJSSWCBackend;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
import org.apache.royale.compiler.internal.projects.CompilerProject;
@@ -203,7 +202,10 @@
if (!entry.getName().contains("js/out") &&
!entry.getName().contains(SWCReader.CATALOG_XML))
{
- System.out.println("Copy " + entry.getName());
+ if (config.isVerbose())
+ {
+ System.out.println("Copy " + entry.getName());
+ }
InputStream input = zipFile.getInputStream(entry);
zipOutputStream.putNextEntry(new ZipEntry(entry.getName()));
IOUtils.copy(input, zipOutputStream);
@@ -258,7 +260,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder, true);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
@@ -300,7 +305,10 @@
}
else
{
- System.out.println("Compiling file: " + cu.getQualifiedNames().get(0));
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + cu.getQualifiedNames().get(0));
+ }
ICompilationUnit unit = cu;
@@ -321,20 +329,28 @@
ByteArrayOutputStream temp = new ByteArrayOutputStream();
ByteArrayOutputStream sourceMapTemp = null;
- if (project.config.getSourceMap())
+
+ boolean isExterns = false;
+ if(cu.getDefinitionPromises().size() > 0)
+ {
+ isExterns = project.isExterns(cu.getDefinitionPromises().get(0).getQualifiedName());
+ }
+
+ // if the file is @externs DON'T create source map file
+ if (project.config.getSourceMap() && !isExterns)
{
sourceMapTemp = new ByteArrayOutputStream();
}
writer.writeTo(temp, sourceMapTemp, null);
- boolean isExterns = false;
- if (writer instanceof JSWriter)
- isExterns = ((JSWriter)writer).isExterns();
String outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0),
isExterns ? externsOut : jsOut,
false).getPath();
- System.out.println("Writing file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Writing file: " + outputClassFile);
+ }
zipOutputStream.putNextEntry(new ZipEntry(outputClassFile));
temp.writeTo(zipOutputStream);
zipOutputStream.flush();
@@ -346,7 +362,10 @@
cu.getQualifiedNames().get(0),
isExterns ? externsOut : jsOut,
false).getPath();
- System.out.println("Writing file: " + sourceMapFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Writing file: " + sourceMapFile);
+ }
zipOutputStream.putNextEntry(new ZipEntry(sourceMapFile));
sourceMapTemp.writeTo(zipOutputStream);
zipOutputStream.flush();
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCRoyale.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCRoyale.java
index 481ec55..1ca37df 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCRoyale.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/COMPJSCRoyale.java
@@ -26,11 +26,14 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.List;
import java.util.Set;
+import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -45,7 +48,6 @@
import org.apache.royale.compiler.exceptions.ConfigurationException;
import org.apache.royale.compiler.exceptions.ConfigurationException.IOError;
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
-import org.apache.royale.compiler.internal.codegen.js.JSWriter;
import org.apache.royale.compiler.internal.driver.mxml.royale.MXMLRoyaleSWCBackend;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
import org.apache.royale.compiler.internal.projects.CompilerProject;
@@ -204,9 +206,50 @@
if (!entry.getName().contains("js/out") &&
!entry.getName().contains(SWCReader.CATALOG_XML))
{
- System.out.println("Copy " + entry.getName());
+ if (config.isVerbose())
+ {
+ System.out.println("Copy " + entry.getName());
+ }
InputStream input = zipFile.getInputStream(entry);
- zipOutputStream.putNextEntry(new ZipEntry(entry.getName()));
+ ZipEntry ze = new ZipEntry(entry.getName());
+ ze.setMethod(ZipEntry.STORED);
+ ze.setSize(entry.getSize());
+ ze.setCompressedSize(entry.getCompressedSize());
+ ze.setCrc(entry.getCrc());
+ long fileDate = System.currentTimeMillis();
+ long zipFileDate = fileDate;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ // strip off timezone. Zip format doesn't store timezone
+ // and the goal is to have the same date and time regardless
+ // of which timezone the build machine is using.
+ int c = metadataDate.lastIndexOf(" ");
+ metadataDate = metadataDate.substring(0, c);
+ c = metadataFormat.lastIndexOf(" ");
+ metadataFormat = metadataFormat.substring(0, c);
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ zipFileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
+ ze.setTime(zipFileDate);
+ zipOutputStream.putNextEntry(ze);
IOUtils.copy(input, zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
@@ -259,7 +302,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder, true);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
@@ -300,7 +346,10 @@
}
else
{
- System.out.println("Compiling file: " + cu.getQualifiedNames().get(0));
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + cu.getQualifiedNames().get(0));
+ }
ICompilationUnit unit = cu;
@@ -320,37 +369,108 @@
ByteArrayOutputStream temp = new ByteArrayOutputStream();
ByteArrayOutputStream sourceMapTemp = null;
- if (project.config.getSourceMap())
+
+ boolean isExterns = false;
+ if(cu.getDefinitionPromises().size() > 0)
+ {
+ isExterns = project.isExterns(cu.getDefinitionPromises().get(0).getQualifiedName());
+ }
+
+ // if the file is @externs DON'T create source map file
+ if (project.config.getSourceMap() && !isExterns)
{
sourceMapTemp = new ByteArrayOutputStream();
}
writer.writeTo(temp, sourceMapTemp, null);
- boolean isExterns = false;
- if (writer instanceof JSWriter)
- isExterns = ((JSWriter)writer).isExterns();
String outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0),
isExterns ? externsOut : jsOut,
false).getPath();
- System.out.println("Writing file: " + outputClassFile);
- zipOutputStream.putNextEntry(new ZipEntry(outputClassFile));
- temp.writeTo(zipOutputStream);
+ outputClassFile = outputClassFile.replace('\\', '/');
+ if (config.isVerbose())
+ {
+ System.out.println("Writing file: " + outputClassFile);
+ }
+ long fileDate = System.currentTimeMillis();
+ long zipFileDate = fileDate;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ // strip off timezone. Zip format doesn't store timezone
+ // and the goal is to have the same date and time regardless
+ // of which timezone the build machine is using.
+ int c = metadataDate.lastIndexOf(" ");
+ metadataDate = metadataDate.substring(0, c);
+ c = metadataFormat.lastIndexOf(" ");
+ metadataFormat = metadataFormat.substring(0, c);
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ zipFileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
+ ZipEntry ze = new ZipEntry(outputClassFile);
+ ze.setTime(zipFileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ temp.writeTo(baos);
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+
+ zipOutputStream.putNextEntry(ze);
+ baos.writeTo(zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
- fileList.append(" <file path=\"" + outputClassFile + "\" mod=\"" + System.currentTimeMillis() + "\"/>\n");
+ fileList.append(" <file path=\"" + outputClassFile + "\" mod=\"" + fileDate + "\"/>\n");
+
if(sourceMapTemp != null)
{
String sourceMapFile = getOutputSourceMapFile(
- cu.getQualifiedNames().get(0),
- isExterns ? externsOut : jsOut,
- false).getPath();
- System.out.println("Writing file: " + sourceMapFile);
- zipOutputStream.putNextEntry(new ZipEntry(sourceMapFile));
- sourceMapTemp.writeTo(zipOutputStream);
+ cu.getQualifiedNames().get(0),
+ isExterns ? externsOut : jsOut,
+ false).getPath();
+ if (config.isVerbose())
+ {
+ System.out.println("Writing file: " + sourceMapFile);
+ }
+ ze = new ZipEntry(sourceMapFile);
+ ze.setTime(zipFileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ baos = new ByteArrayOutputStream();
+ sourceMapTemp.writeTo(baos);
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+
+ zipOutputStream.putNextEntry(ze);
+ baos.writeTo(zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
- fileList.append(" <file path=\"" + sourceMapFile + "\" mod=\"" + System.currentTimeMillis() + "\"/>\n");
+ fileList.append(" <file path=\"" + sourceMapFile + "\" mod=\"" + fileDate + "\"/>\n");
}
writer.close();
}
@@ -367,12 +487,57 @@
if (packingSWC)
{
zipFile.close();
+ long fileDate = System.currentTimeMillis();
+ long zipFileDate = fileDate;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ // strip off timezone. Zip format doesn't store timezone
+ // and the goal is to have the same date and time regardless
+ // of which timezone the build machine is using.
+ int c = metadataDate.lastIndexOf(" ");
+ metadataDate = metadataDate.substring(0, c);
+ c = metadataFormat.lastIndexOf(" ");
+ metadataFormat = metadataFormat.substring(0, c);
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ zipFileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
int libraryIndex = catalog.indexOf("</libraries>");
catalog = catalog.substring(0, libraryIndex + 13) +
" <files>\n" + fileList.toString() + " </files>" +
catalog.substring(libraryIndex + 13);
- zipOutputStream.putNextEntry(new ZipEntry(SWCReader.CATALOG_XML));
- zipOutputStream.write(catalog.getBytes());
+ ZipEntry ze = new ZipEntry(SWCReader.CATALOG_XML);
+ ze.setTime(zipFileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ baos.write(catalog.getBytes());
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+
+ zipOutputStream.putNextEntry(ze);
+ baos.writeTo(zipOutputStream);
zipOutputStream.flush();
zipOutputStream.closeEntry();
zipOutputStream.flush();
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
index 22854f4..eda4012 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/JSConfiguration.java
@@ -49,13 +49,16 @@
* configure() method of {@link MXMLJSC}.
* <p>
* This class inherits all compiler arguments from the MXMLC compiler.
- *
+ *
* @author Michael Schmalle
*/
public class JSConfiguration extends Configuration
{
public JSConfiguration()
{
+ setCompilerAllowAbstractClasses(null, true);
+ setCompilerAllowPrivateConstructors(null, true);
+ setCompilerAllowImportAliases(null, true);
}
//
@@ -123,7 +126,7 @@
// 'js-default-initializers'
//
- private boolean jsDefaultInitializers = false;
+ private boolean jsDefaultInitializers = true;
public boolean getJsDefaultInitializers()
{
@@ -153,7 +156,7 @@
* If the definition of a member cannot be resolved, emit dynamic access
* instead of normal member access. Ensures that dynamic members aren't
* renamed.
- *
+ *
* <code>myObject.memberAccess</code> becomes <code>myObject["memberAccess"]</code>
*/
@Config
@@ -222,7 +225,7 @@
* Example: <code>-define=CONFIG::debugging,true</code>
*
* In <code>royale-config.xml</code>:<br/>
- *
+ *
* <pre>
* <royale-config>
* <compiler>
@@ -251,7 +254,7 @@
* <code>"\"foo\""</code> or <code>"\'foo\'"</code>) or single-quoted (<code>"'foo'"</code>).
*
* String values in configuration files need only be single- or double- quoted:<br/>
- *
+ *
* <pre>
* <royale-config>
* <compiler>
@@ -270,18 +273,18 @@
*
* Empty strings <i>must</i> be passed as <code>"''"</code> on the command-line, and <code>''</code> or
* <code>""</code> in configuration files.
- *
+ *
* Finally, if you have existing definitions in a configuration file, and you would like to add to them with the
* command-line (let's say most of your build setCompilertings are in the configuration, and that you are adding one
* temporarily using the command-line), you use the following syntax: <code>-define+=TEST::temporary,false</code>
* (noting the plus sign)
- *
+ *
* Note that definitions can be overridden/redefined if you use the append ("+=") syntax (on the commandline or in a
* user config file, for instance) with the same namespace and name, and a new value.
- *
+ *
* Definitions cannot be removed/undefined. You can undefine ALL existing definitions from (e.g. from
* royale-config.xml) if you do not use append syntax ("=" or append="false").
- *
+ *
* IMPORTANT FOR FLASH BUILDER If you are using "Additional commandline arguments" to "-define", don't use the
* following syntax though I suggest it above: -define+=CONFIG::foo,"'value'" The trouble is that FB parses the
* double quotes incorrectly as <"'value'> -- the trailing double-quote is dropped. The solution is to avoid inner
@@ -382,7 +385,7 @@
@Arguments("filename")
public void setJsLoadConfig(ConfigurationValue cv, String filename) throws ConfigurationException
{
-
+
}
//////////////////////////////////////////////////////////////////////////
@@ -400,7 +403,7 @@
* Configures a list of many manifests mapped to a single namespace URI.
* <namespace> <uri>library:adobe/flex/something</uri> <manifest>something-manifest.xml</manifest>
* <manifest>something-else-manifest.xml</manifest> ... </namespace>
- *
+ *
* @param cfgval The configuration value context.
* @param args A List of values for the namespace element, with the first item expected to be the uri and the
* remaining are manifest paths.
@@ -442,4 +445,140 @@
}
}
+ //
+ // 'js-vector-emulation-class' option
+ //
+
+ private String jsVectorEmulationClass = null;
+
+ public String getJsVectorEmulationClass()
+ {
+ return jsVectorEmulationClass;
+ }
+
+ /**
+ * The class to use instead of default Vector implementation for handling Vector.
+ */
+ @Config(advanced = true)
+ public void setJsVectorEmulationClass(ConfigurationValue cv, String b)
+ {
+ jsVectorEmulationClass = b;
+ }
+
+
+ //
+ // 'js-complex-implicit-coercions'
+ //
+
+ private boolean jsComplexImplicitCoercions = true;
+
+ public boolean getJsComplexImplicitCoercions()
+ {
+ return jsComplexImplicitCoercions;
+ }
+
+ /**
+ * Support for including/avoiding more complex implicit assignment coercions
+ * example
+ * var array:Array = [new MyClass()];
+ * var myOtherClass:MyOtherClass = array[0];
+ *
+ * In the above example, the compiler will (by default) output an implicit coercion
+ * that is equivalent in actionscript to:
+ * var myOtherClass:MyOtherClass = MyOtherClass(array[0]);
+ *
+ * By setting this configuration option to false, the implicit coercion code in situations similar to the above
+ * is not generated (other primitive implicit coercions, such as int/uint/Number/String and Boolean coercions remain)
+ * This is a global setting for the current source code being compiled, it is possible to leave it on and specifically avoid it via doc
+ * settings. The doc comment compiler directive for that is: @royalesuppresscompleximplicitcoercion
+ * Another option is to add the explicit coercions in code and then avoid their output
+ * via specific @royaleignorecoercion doc comment directives. Doing so however may add extra unwanted output
+ * in other compiler targets (for example, swf bytecode) if the same source code is shared between targets.
+ */
+ @Config(advanced = true)
+ @Mapping("js-complex-implicit-coercions")
+ public void setJsComplexImplicitCoercions(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ jsComplexImplicitCoercions = value;
+ }
+
+ //
+ // 'js-resolve-uncertain'
+ //
+
+ private boolean jsResolveUncertain = true;
+
+ public boolean getJsResolveUncertain()
+ {
+ return jsResolveUncertain;
+ }
+
+ /**
+ * Support for avoiding more overhead of resolving instantiations from
+ * unknown constructors
+ * example
+ * var myClass:Class = String;
+ * var myString:* = new myClass("test");
+ *
+ * In the above example, the compiler will (by default) output
+ * a call to a Language.resolveUncertain method which wraps the 'new myClass("test")'
+ *
+ *
+ * This normalizes the return value for some primitive constructors, so that (for example)
+ * strict equality and inequality operators provide the same results between compiler
+ * targets.
+ * In situations where it is certain that the resolveUncertain method is not needed,
+ * this option provides a way to switch it off 'globally' for the current source code being compiled.
+ * It can also be switched off or on locally using the '@royalesuppressresolveuncertain'
+ * doc comment compiler directive.
+ */
+ @Config(advanced = true)
+ @Mapping("js-resolve-uncertain")
+ public void setJsResolveUncertain(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ jsResolveUncertain = value;
+ }
+
+ //
+ // 'js-vector-index-checks'
+ //
+
+ private boolean jsVectorIndexChecks = true;
+
+ public boolean getJsVectorIndexChecks()
+ {
+ return jsVectorIndexChecks;
+ }
+
+ /**
+ * Support for avoiding more overhead of adding checks into
+ * assignments via Vector index access
+ * example
+ * var myVector:Vector.<int> = new Vector.<int>();
+ * myVector[0] = 42;
+ *
+ * In the above example, the compiler will (by default) wrap
+ * the '0' inside myVector[0] with a method call on the vector instance
+ * that checks to see if the index is valid for the Vector it is being used against
+ *
+ * This check will throw an error if the index is out of range, and the
+ * range checking differs if the Vector is 'fixed' or non-'fixed'
+ *
+ * In situations where it is certain that the index will always be valid for Vector instance
+ * being targeted, or where all cases in a given codebase are certain to be valid, it is possible
+ * to avoid the overhead of this check. This is especially important in loops.
+ * This config setting affects the global setting for the current source code being compiled.
+ * It can be adjusted locally within code, using the '@royalesuppressvectorindexcheck'
+ * doc comment compiler directive.
+ */
+ @Config(advanced = true)
+ @Mapping("js-vector-index-checks")
+ public void setJsVectorIndexChecks(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ jsVectorIndexChecks = value;
+ }
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSC.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSC.java
index 8129274..b8cb3fb 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSC.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSC.java
@@ -25,6 +25,8 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -58,6 +60,7 @@
import org.apache.royale.compiler.exceptions.ConfigurationException.OnlyOneSource;
import org.apache.royale.compiler.internal.config.FlashBuilderConfigurator;
import org.apache.royale.compiler.internal.config.localization.LocalizationManager;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
import org.apache.royale.compiler.internal.projects.CompilerProject;
@@ -188,7 +191,7 @@
{
SUCCESS(0),
PRINT_HELP(1),
- FAILED_WITH_PROBLEMS(2),
+ FAILED_WITH_PROBLEMS(0),
FAILED_WITH_ERRORS(3),
FAILED_WITH_EXCEPTIONS(4),
FAILED_WITH_CONFIG_PROBLEMS(5);
@@ -285,6 +288,7 @@
public MXMLJSC()
{
+ DefinitionBase.setPerformanceCachingEnabled(true);
workspace = new Workspace();
workspace.setASDocDelegate(new RoyaleASDocDelegate());
project = new RoyaleJSProject(workspace, null);
@@ -464,8 +468,11 @@
arg.startsWith("-compiler.js-library-path") ||
arg.startsWith("-compiler.js-define") ||
arg.startsWith("-js-output") ||
+ arg.startsWith("-js-vector-emulation-class") ||
+ arg.startsWith("-externs-report") ||
arg.startsWith("-js-load-config") ||
arg.startsWith("-warn-public-vars") ||
+ arg.startsWith("-export-protected-symbols") ||
arg.startsWith("-source-map")))
list.add(arg);
}
@@ -558,7 +565,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
@@ -596,6 +606,22 @@
sourceMapOut.close();
}
writer.close();
+ long fileDate = 0;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ outputClassFile.setLastModified(fileDate);
+ }
}
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNative.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNative.java
index 6bae88f..1c4474f 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNative.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNative.java
@@ -49,6 +49,7 @@
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
import org.apache.royale.compiler.exceptions.ConfigurationException.OnlyOneSource;
import org.apache.royale.compiler.internal.config.FlashBuilderConfigurator;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.driver.js.jsc.JSCBackend;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
@@ -99,7 +100,7 @@
{
SUCCESS(0),
PRINT_HELP(1),
- FAILED_WITH_PROBLEMS(2),
+ FAILED_WITH_PROBLEMS(0),
FAILED_WITH_ERRORS(3),
FAILED_WITH_EXCEPTIONS(4),
FAILED_WITH_CONFIG_PROBLEMS(5);
@@ -174,6 +175,7 @@
{
IBackend backend = new JSCBackend();
+ DefinitionBase.setPerformanceCachingEnabled(true);
workspace = new Workspace();
workspace.setASDocDelegate(new RoyaleASDocDelegate());
project = new RoyaleJSProject(workspace, backend);
@@ -337,7 +339,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNode.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNode.java
index ed98d56..bb83228 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNode.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCNode.java
@@ -49,6 +49,7 @@
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
import org.apache.royale.compiler.exceptions.ConfigurationException.OnlyOneSource;
import org.apache.royale.compiler.internal.config.FlashBuilderConfigurator;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.driver.js.node.NodeBackend;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
@@ -98,7 +99,7 @@
{
SUCCESS(0),
PRINT_HELP(1),
- FAILED_WITH_PROBLEMS(2),
+ FAILED_WITH_PROBLEMS(0),
FAILED_WITH_ERRORS(3),
FAILED_WITH_EXCEPTIONS(4),
FAILED_WITH_CONFIG_PROBLEMS(5);
@@ -176,6 +177,7 @@
protected MXMLJSCNode(IBackend backend)
{
+ DefinitionBase.setPerformanceCachingEnabled(true);
workspace = new Workspace();
workspace.setASDocDelegate(new RoyaleASDocDelegate());
project = new RoyaleJSProject(workspace, backend);
@@ -339,7 +341,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyale.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyale.java
index 66a2989..fe7c209 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyale.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyale.java
@@ -22,12 +22,15 @@
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -44,24 +47,34 @@
import org.apache.royale.compiler.clients.problems.WorkspaceProblemFormatter;
import org.apache.royale.compiler.codegen.js.IJSPublisher;
import org.apache.royale.compiler.codegen.js.IJSWriter;
-import org.apache.royale.compiler.config.CompilerDiagnosticsConstants;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.config.ConfigurationBuffer;
import org.apache.royale.compiler.config.Configurator;
import org.apache.royale.compiler.config.ICompilerSettingsConstants;
+import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.driver.js.IJSApplication;
import org.apache.royale.compiler.exceptions.ConfigurationException;
import org.apache.royale.compiler.exceptions.ConfigurationException.IOError;
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
import org.apache.royale.compiler.exceptions.ConfigurationException.OnlyOneSource;
+import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitter;
import org.apache.royale.compiler.internal.config.FlashBuilderConfigurator;
+import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
+import org.apache.royale.compiler.internal.definitions.ClassDefinition;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
+import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
+import org.apache.royale.compiler.internal.definitions.InterfaceDefinition;
+import org.apache.royale.compiler.internal.definitions.ParameterDefinition;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.driver.mxml.royale.MXMLRoyaleBackend;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.projects.ISourceFileHandler;
+import org.apache.royale.compiler.internal.scopes.ASProjectScope.DefinitionPromise;
+import org.apache.royale.compiler.internal.scopes.ASScope;
import org.apache.royale.compiler.internal.targets.RoyaleJSTarget;
import org.apache.royale.compiler.internal.targets.JSTarget;
import org.apache.royale.compiler.internal.units.ResourceBundleCompilationUnit;
@@ -74,6 +87,7 @@
import org.apache.royale.compiler.problems.UnableToBuildSWFProblem;
import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.scopes.IDefinitionSet;
import org.apache.royale.compiler.targets.ITarget;
import org.apache.royale.compiler.targets.ITarget.TargetType;
import org.apache.royale.compiler.targets.ITargetSettings;
@@ -110,7 +124,7 @@
{
SUCCESS(0),
PRINT_HELP(1),
- FAILED_WITH_PROBLEMS(2),
+ FAILED_WITH_PROBLEMS(0),
FAILED_WITH_ERRORS(3),
FAILED_WITH_EXCEPTIONS(4),
FAILED_WITH_CONFIG_PROBLEMS(5);
@@ -190,6 +204,7 @@
public MXMLJSCRoyale(IBackend backend)
{
+ DefinitionBase.setPerformanceCachingEnabled(true);
workspace = new Workspace();
workspace.setASDocDelegate(new RoyaleASDocDelegate());
project = new RoyaleJSProject(workspace, backend);
@@ -363,8 +378,11 @@
{
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder);
-
- System.out.println("Compiling file: " + outputClassFile);
+
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
@@ -404,6 +422,9 @@
writer.close();
}
}
+ File externsReportFile = googConfiguration.getExternsReport();
+ if (externsReportFile != null)
+ generateExternsReport(externsReportFile, reachableCompilationUnits, problems);
}
if (!config.getCreateTargetWithErrors())
@@ -437,99 +458,374 @@
return compilationSuccess && (errs.size() == 0);
}
- private void outputResourceBundle(ResourceBundleCompilationUnit cu, File outputFolder) {
+ private void generateExternsReport(File externsReportFile,
+ List<ICompilationUnit> reachableCompilationUnits,
+ ProblemQuery problems) {
+
+ if (config.isVerbose())
+ {
+ System.out.println("Generating externs report: " + externsReportFile.getAbsolutePath());
+ }
+
+ ArrayList<String> packageNames = new ArrayList<String>();
+ ArrayList<String> partNames = new ArrayList<String>();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("/**\n");
+ sb.append(" * Generated by Apache Royale Compiler\n");
+ sb.append(" *\n");
+ sb.append(" * @fileoverview\n");
+ sb.append(" * @externs\n");
+ sb.append(" *\n");
+ // need to suppress access controls so access to protected/private from defineProperties
+ // doesn't generate warnings.
+ sb.append(" * @suppress {checkTypes|accessControls}\n");
+ sb.append(" */\n");
+
+ for (ICompilationUnit cu : reachableCompilationUnits)
+ {
+ if (project.isExternalLinkage(cu)) continue;
+
+ List<IDefinition> dp = cu.getDefinitionPromises();
+
+ if (dp.size() == 0)
+ return;
+
+ IDefinition def = dp.get(0);
+ IDefinition actualDef = ((DefinitionPromise) def).getActualDefinition();
+ if (actualDef.getPackageName().contains("goog")) continue;
+ if (actualDef instanceof ClassDefinition)
+ {
+ sb.append("\n\n");
+ ClassDefinition cdef = (ClassDefinition)actualDef;
+ String pkgName = cdef.getPackageName();
+ if (pkgName.length() > 0 && !packageNames.contains(pkgName))
+ {
+ packageNames.add(pkgName);
+ String[] parts = pkgName.split("\\.");
+ String current = "";
+ boolean firstOne = true;
+ for (String part : parts)
+ {
+ current += part;
+ if (partNames.contains(current))
+ {
+ firstOne = false;
+ current += ".";
+ continue;
+ }
+ partNames.add(current);
+ sb.append("/**\n * @suppress {duplicate}\n * @const\n */\n");
+ if (firstOne)
+ {
+ sb.append("var ");
+ firstOne = false;
+ }
+ sb.append(current);
+ sb.append(" = {}");
+ sb.append(ASEmitterTokens.SEMICOLON.getToken() + "\n");
+ current += ".";
+ }
+ }
+ sb.append("\n\n");
+ sb.append("/**\n");
+ sb.append(" * @constructor\n");
+ String baseString = cdef.getBaseClassAsDisplayString();
+ if (baseString.length() > 0)
+ sb.append(" * @extends {" + baseString + "}\n");
+ String[] ifaces = cdef.getImplementedInterfacesAsDisplayStrings();
+ for (String iface : ifaces)
+ sb.append(" * @implements {" + iface + "}\n");
+ sb.append(" */\n");
+ if (pkgName.length() == 0)
+ sb.append("function " + cdef.getQualifiedName() + "() {}\n");
+ else
+ sb.append(cdef.getQualifiedName() + " = function() {}\n");
+
+ ASScope cscope = cdef.getContainedScope();
+ Collection<IDefinitionSet> defSets = cscope.getAllLocalDefinitionSets();
+ IDefinitionSet[] arrayOfDefSets = new IDefinitionSet[defSets.size()];
+ defSets.toArray(arrayOfDefSets);
+ for (IDefinitionSet defSet : arrayOfDefSets)
+ {
+ int n = defSet.getSize();
+ for (int i = 0; i < n; i++)
+ {
+ IDefinition api = defSet.getDefinition(i);
+ String apiName = api.getBaseName();
+ if (apiName.startsWith("#")) continue; // invalid in externs
+ if (!api.isOverride() && (api.isProtected() || api.isPublic()))
+ {
+ if (!(api instanceof FunctionDefinition) ||
+ api instanceof AccessorDefinition)
+ {
+ sb.append("\n\n");
+ sb.append("/**\n");
+ sb.append(" * @type {" + getJSType(api.getTypeAsDisplayString()) + "}\n");
+ sb.append(" */\n");
+ sb.append(cdef.getQualifiedName() + ".");
+ if (!api.isStatic())
+ sb.append("prototype.");
+ sb.append(api.getBaseName() + ";\n");
+ }
+ else
+ {
+ FunctionDefinition method = (FunctionDefinition)api;
+ ParameterDefinition[] params = method.getParameters();
+ sb.append("\n\n");
+ sb.append("/**\n");
+ for (ParameterDefinition param : params)
+ {
+ if (param.getBaseName().isEmpty())
+ sb.append(" * @param {*=} opt_rest\n");
+ else
+ sb.append(" * @param {" + getJSType(param.getTypeAsDisplayString()) + "} " + param.getBaseName() + "\n");
+ }
+ String ret = getJSType(method.getReturnTypeAsDisplayString());
+ if (!ret.equals("void"))
+ sb.append(" * @returns {" + ret + "}\n");
+ sb.append(" */\n");
+ sb.append(cdef.getQualifiedName() + ".");
+ if (!api.isStatic())
+ sb.append("prototype.");
+ sb.append(api.getBaseName());
+ sb.append(" = function(");
+ int m = params.length;
+ for (int j = 0; j < m; j++)
+ {
+ if (j > 0)
+ sb.append(",");
+ if (params[j].getBaseName().isEmpty())
+ sb.append("opt_rest");
+ else
+ sb.append(params[j].getBaseName());
+ }
+ sb.append(") {");
+ if (!ret.equals("void"))
+ {
+ if (ret.equals("number"))
+ sb.append(" return 0; ");
+ else if (ret.equals("boolean"))
+ sb.append(" return false; ");
+ else
+ sb.append(" return null; ");
+ }
+ sb.append("};\n");
+ }
+ }
+ }
+ }
+ }
+ else if (actualDef instanceof InterfaceDefinition)
+ {
+ sb.append("\n\n");
+ InterfaceDefinition cdef = (InterfaceDefinition)actualDef;
+ String pkgName = cdef.getPackageName();
+ if (pkgName.length() > 0 && !packageNames.contains(pkgName))
+ {
+ packageNames.add(pkgName);
+ String[] parts = pkgName.split("\\.");
+ String current = "";
+ boolean firstOne = true;
+ for (String part : parts)
+ {
+ current += part;
+ if (partNames.contains(current))
+ {
+ firstOne = false;
+ current += ".";
+ continue;
+ }
+ partNames.add(current);
+ sb.append("/**\n * @suppress {duplicate}\n * @const\n */\n");
+ if (firstOne)
+ {
+ sb.append("var ");
+ firstOne = false;
+ }
+ sb.append(current);
+ sb.append(" = {}");
+ sb.append(ASEmitterTokens.SEMICOLON.getToken() + "\n");
+ current += ".";
+ }
+ }
+ sb.append("\n\n");
+ sb.append("/**\n");
+ sb.append(" * @interface\n");
+ String[] ifaces = cdef.getExtendedInterfacesAsDisplayStrings();
+ for (String iface : ifaces)
+ sb.append(" * @extends {" + iface + "}\n");
+ sb.append(" */\n");
+ sb.append(cdef.getQualifiedName() + " = function() {}\n");
+ }
+ }
+ if (config.isVerbose())
+ {
+ System.out.println("Writing externs report: " + externsReportFile.getAbsolutePath());
+ }
+ FileWriter fw;
+ try {
+ fw = new FileWriter(externsReportFile, false);
+ fw.write(sb.toString());
+ fw.close();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ private String getJSType(String s)
+ {
+ if (s.contains("__AS3__.vec.Vector"))
+ return "Array";
+ return JSGoogDocEmitter.convertASTypeToJSType(s, "");
+ }
+
+ private void outputResourceBundle(ResourceBundleCompilationUnit cu, File outputFolder) {
// TODO Auto-generated method stub
final ISWCManager swcManager = project.getWorkspace().getSWCManager();
// find the SWC
final ISWC swc = swcManager.get(new File(cu.getAbsoluteFilename()));
if (swc != null)
{
- String bundleName = cu.getBundleNameInColonSyntax();
- String propFileName = "locale/" + cu.getLocale() + "/" + bundleName + ".properties";
- String bundleClassName = cu.getLocale() + "$" + bundleName + "_properties";
- Map<String, ISWCFileEntry> files = swc.getFiles();
- for (String key : files.keySet())
+ if (swc.getSWCFile().getAbsolutePath().endsWith(".swc"))
{
- if (key.equals(propFileName))
- {
- if (!project.compiledResourceBundleNames.contains(bundleName))
- project.compiledResourceBundleNames.add(bundleName);
- project.compiledResourceBundleClasses.add(bundleClassName);
- StringBuilder sb = new StringBuilder();
- ISWCFileEntry fileEntry = swc.getFile(key);
- if (fileEntry != null)
- {
- try {
- InputStream is = fileEntry.createInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- String line;
- while ((line = br.readLine()) != null)
- {
- if (line.contains("="))
- {
- if (sb.length() == 0)
- {
- sb.append("/**\n");
- sb.append(" * Generated by Apache Royale Compiler from " + bundleClassName + ".properties\n");
- sb.append(" * " + bundleClassName + "\n");
- sb.append(" *\n");
- sb.append(" * @fileoverview\n");
- sb.append(" *\n");
- sb.append(" * @suppress {checkTypes|accessControls}\n");
- sb.append(" */\n\n");
- sb.append("goog.provide('" + bundleClassName + "');\n\n");
- sb.append("goog.require('mx.resources.IResourceBundle');\n");
- sb.append("goog.require('mx.resources.ResourceBundle');\n\n\n");
- sb.append("/**\n");
- sb.append(" * @constructor\n");
- sb.append(" * @extends {mx.resources.ResourceBundle}\n");
- sb.append(" * @implements {mx.resources.IResourceBundle}\n");
- sb.append(" */\n");
- sb.append(bundleClassName + " = function() {\n");
- sb.append(" " + bundleClassName + ".base(this, 'constructor');\n");
- sb.append("};\n");
- sb.append("goog.inherits(" + bundleClassName + ", mx.resources.ResourceBundle);\n\n");
- sb.append("/**\n");
- sb.append(" * Prevent renaming of class. Needed for reflection.\n");
- sb.append(" */\n");
- sb.append("goog.exportSymbol('" + bundleClassName + "', " + bundleClassName + ");\n\n");
- sb.append(bundleClassName + ".prototype.getContent = function() { return {\n");
- }
- int c = line.indexOf("=");
- String propName = line.substring(0, c);
- String value = line.substring(c + 1);
- while (value.endsWith("/"))
- {
- value = value.substring(0, value.length() - 1);
- value += br.readLine();
- }
- sb.append(propName + ": \"" + value + "\",\n");
- }
+ String bundleName = cu.getBundleNameInColonSyntax();
+ String propFileName = "locale/" + cu.getLocale() + "/" + bundleName + ".properties";
+ String bundleClassName = cu.getLocale() + "$" + bundleName + "_properties";
+ Map<String, ISWCFileEntry> files = swc.getFiles();
+ for (String key : files.keySet())
+ {
+ if (key.equals(propFileName))
+ {
+ if (!project.compiledResourceBundleNames.contains(bundleName))
+ project.compiledResourceBundleNames.add(bundleName);
+ project.compiledResourceBundleClasses.add(bundleClassName);
+ ISWCFileEntry fileEntry = swc.getFile(key);
+ if (fileEntry != null)
+ {
+ InputStream is;
+ try {
+ is = fileEntry.createInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ writeResourceBundle(br, bundleClassName, outputFolder);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
}
- sb.append("__end_of_bundle__: 0\n};};\n");
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- final File outputClassFile = getOutputClassFile(
- bundleClassName, outputFolder);
- System.out.println("Generating resource file: " + outputClassFile);
- FileWriter fw;
- try {
- fw = new FileWriter(outputClassFile, false);
- fw.write(sb.toString());
- fw.close();
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
+ }
+ }
+ }
+ }
+ else
+ {
+ // it isn't a bundle from a SWC, it is a bundle in the source path
+ String bundleName = cu.getBundleNameInColonSyntax();
+ String bundleClassName = cu.getLocale() + "$" + bundleName + "_properties";
+ if (!project.compiledResourceBundleNames.contains(bundleName))
+ project.compiledResourceBundleNames.add(bundleName);
+ project.compiledResourceBundleClasses.add(bundleClassName);
+ InputStream is;
+ try {
+ is = new FileInputStream(swc.getSWCFile());
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ writeResourceBundle(br, bundleClassName, outputFolder);
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
}
}
-
}
+ private void writeResourceBundle(BufferedReader br, String bundleClassName, File outputFolder)
+ {
+ StringBuilder sb = new StringBuilder();
+ try {
+ String line;
+ while ((line = br.readLine()) != null)
+ {
+ if (line.contains("="))
+ {
+ if (sb.length() == 0)
+ {
+ sb.append("/**\n");
+ sb.append(" * Generated by Apache Royale Compiler from " + bundleClassName + ".properties\n");
+ sb.append(" * " + bundleClassName + "\n");
+ sb.append(" *\n");
+ sb.append(" * @fileoverview\n");
+ sb.append(" *\n");
+ sb.append(" * @suppress {checkTypes|accessControls}\n");
+ sb.append(" */\n\n");
+ sb.append("goog.provide('" + bundleClassName + "');\n\n");
+ sb.append("goog.require('mx.resources.IResourceBundle');\n");
+ sb.append("goog.require('mx.resources.ResourceBundle');\n\n\n");
+ sb.append("/**\n");
+ sb.append(" * @constructor\n");
+ sb.append(" * @extends {mx.resources.ResourceBundle}\n");
+ sb.append(" * @implements {mx.resources.IResourceBundle}\n");
+ sb.append(" */\n");
+ sb.append(bundleClassName + " = function() {\n");
+ sb.append(" " + bundleClassName + ".base(this, 'constructor');\n");
+ sb.append("};\n");
+ sb.append("goog.inherits(" + bundleClassName + ", mx.resources.ResourceBundle);\n\n");
+ sb.append("/**\n");
+ sb.append(" * Prevent renaming of class. Needed for reflection.\n");
+ sb.append(" */\n");
+ sb.append("goog.exportSymbol('" + bundleClassName + "', " + bundleClassName + ");\n\n");
+ sb.append(bundleClassName + ".prototype.getContent = function() { return {\n");
+ }
+ int c = line.indexOf("=");
+ String propName = line.substring(0, c);
+ String value = line.substring(c + 1);
+ while (value.endsWith("/"))
+ {
+ value = value.substring(0, value.length() - 1);
+ value += br.readLine();
+ }
+ sb.append(propName + ": \"" + value + "\",\n");
+ }
+ }
+ sb.append("__end_of_bundle__: 0\n};};\n");
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ final File outputClassFile = getOutputClassFile(
+ bundleClassName, outputFolder);
+ if (config.isVerbose())
+ {
+ System.out.println("Generating resource file: " + outputClassFile);
+ }
+ FileWriter fw;
+ try {
+ fw = new FileWriter(outputClassFile, false);
+ fw.write(sb.toString());
+ fw.close();
+ long fileDate = 0;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ outputClassFile.setLastModified(fileDate);
+ }
+
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ }
+
/**
* Build target artifact.
*
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyaleCordova.java b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyaleCordova.java
index 6e91ea0..378339c 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyaleCordova.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/clients/MXMLJSCRoyaleCordova.java
@@ -49,6 +49,7 @@
import org.apache.royale.compiler.exceptions.ConfigurationException.MustSpecifyTarget;
import org.apache.royale.compiler.exceptions.ConfigurationException.OnlyOneSource;
import org.apache.royale.compiler.internal.config.FlashBuilderConfigurator;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.driver.mxml.royale.MXMLRoyaleCordovaBackend;
import org.apache.royale.compiler.internal.parsing.as.RoyaleASDocDelegate;
@@ -99,7 +100,7 @@
{
SUCCESS(0),
PRINT_HELP(1),
- FAILED_WITH_PROBLEMS(2),
+ FAILED_WITH_PROBLEMS(0),
FAILED_WITH_ERRORS(3),
FAILED_WITH_EXCEPTIONS(4),
FAILED_WITH_CONFIG_PROBLEMS(5);
@@ -179,6 +180,7 @@
public MXMLJSCRoyaleCordova(IBackend backend)
{
+ DefinitionBase.setPerformanceCachingEnabled(true);
workspace = new Workspace();
workspace.setASDocDelegate(new RoyaleASDocDelegate());
project = new RoyaleJSProject(workspace, backend);
@@ -342,7 +344,10 @@
final File outputClassFile = getOutputClassFile(
cu.getQualifiedNames().get(0), outputFolder);
- System.out.println("Compiling file: " + outputClassFile);
+ if (config.isVerbose())
+ {
+ System.out.println("Compiling file: " + outputClassFile);
+ }
ICompilationUnit unit = cu;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java
index 5dffb4d..b68f9f0 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/IJSEmitter.java
@@ -25,6 +25,7 @@
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
import org.apache.royale.compiler.tree.as.IASNode;
+import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.ITypeNode;
import org.apache.royale.compiler.visitor.IASNodeStrategy;
@@ -45,4 +46,6 @@
void emitClosureStart();
void emitClosureEnd(IASNode node, IDefinition nodeDef);
+
+ void emitAssignmentCoercion(IExpressionNode assignedNode, IDefinition definition);
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/goog/IJSGoogDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/goog/IJSGoogDocEmitter.java
index 112f3a0..6c99459 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/goog/IJSGoogDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/js/goog/IJSGoogDocEmitter.java
@@ -134,7 +134,7 @@
void emitThis(ITypeDefinition node, String packageName);
- void emitType(IASNode node, String packageName);
+ void emitType(IASNode node, String packageName, ICompilerProject project);
void emitType(String type, String packageName);
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java
index f80c674..d04b4ee 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java
@@ -864,6 +864,18 @@
public void emitMethodScope(IScopedNode node)
{
write(ASEmitterTokens.SPACE);
+ if (node instanceof IContainerNode)
+ {
+ IContainerNode container = (IContainerNode) node;
+ //native or abstract methods may have a synthesized scope block
+ if (container.getContainerType().equals(ContainerType.SYNTHESIZED))
+ {
+ write(ASEmitterTokens.BLOCK_OPEN);
+ writeNewline();
+ write(ASEmitterTokens.BLOCK_CLOSE);
+ return;
+ }
+ }
getWalker().walk(node);
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASWriter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASWriter.java
index 1384a9d..62ef771 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASWriter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASWriter.java
@@ -77,7 +77,7 @@
try
{
- out.write(writer.toString().getBytes());
+ out.write(writer.toString().getBytes("utf8"));
}
catch (IOException e)
{
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSDocEmitter.java
index de44564..8840e5b 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSDocEmitter.java
@@ -29,7 +29,8 @@
public class JSDocEmitter implements IDocEmitter, IEmitter
{
- private int currentIndent = 0;
+ @SuppressWarnings("unused")
+ private int currentIndent = 0;
protected IEmitter emitter;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
index ae8768a..d6a9745 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSEmitter.java
@@ -23,12 +23,21 @@
import java.util.ArrayList;
import java.util.List;
+import org.apache.royale.compiler.codegen.IASGlobalFunctionConstants;
+import org.apache.royale.compiler.codegen.IDocEmitter;
import org.apache.royale.compiler.codegen.IEmitter;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.codegen.js.IMappingEmitter;
import org.apache.royale.compiler.common.ISourceLocation;
+import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.IMetaAttributeConstants;
+import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
+import org.apache.royale.compiler.definitions.IAppliedVectorDefinition;
+import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.metadata.IMetaTag;
+import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.internal.codegen.as.ASEmitter;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.jx.BlockCloseEmitter;
@@ -57,12 +66,18 @@
import org.apache.royale.compiler.internal.codegen.js.jx.UnaryOperatorEmitter;
import org.apache.royale.compiler.internal.codegen.js.jx.WhileLoopEmitter;
import org.apache.royale.compiler.internal.codegen.js.jx.WithEmitter;
-import org.apache.royale.compiler.internal.tree.as.FunctionNode;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.internal.semantics.SemanticUtils;
+import org.apache.royale.compiler.internal.tree.as.*;
+import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.ICatchNode;
import org.apache.royale.compiler.tree.as.IContainerNode;
import org.apache.royale.compiler.tree.as.IDefinitionNode;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
+import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IForLoopNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IFunctionObjectNode;
@@ -87,6 +102,9 @@
import com.google.debugging.sourcemap.FilePosition;
+import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
+import org.apache.royale.compiler.utils.NativeUtils;
+
/**
* @author Michael Schmalle
*/
@@ -196,6 +214,13 @@
startMapping(node);
FunctionNode fnode = node.getFunctionNode();
write(ASEmitterTokens.FUNCTION);
+ String name = fnode.getName();
+ //may have a name, or may be anonymous
+ if(name.length() > 0)
+ {
+ write(ASEmitterTokens.SPACE);
+ write(name);
+ }
endMapping(node);
emitParameters(fnode.getParametersContainerNode());
emitFunctionScope(fnode.getScopedNode());
@@ -203,16 +228,17 @@
public void emitClosureStart()
{
-
+
}
public void emitClosureEnd(IASNode node, IDefinition nodeDef)
{
-
+
}
public void emitSourceMapDirective(ITypeNode node)
{
+ sourceMapDirectiveEmitter.isExterns = getModel().isExterns;
sourceMapDirectiveEmitter.emit(node);
}
@@ -422,6 +448,9 @@
}
}
+ //prefer forward slash
+ sourcePath = sourcePath.replace('\\', '/');
+
SourceMapMapping mapping = new SourceMapMapping();
mapping.sourcePath = sourcePath;
mapping.sourceStartPosition = new FilePosition(line, column);
@@ -481,7 +510,7 @@
/**
* Adjusts the line numbers saved in the source map when a line should be
* removed during post processing.
- *
+ *
* @param lineIndex
*/
protected void removeLineFromMappings(int lineIndex)
@@ -505,4 +534,390 @@
return className.replace(".", "_") + "_" + name;
}
+ public void emitAssignmentCoercion(IExpressionNode assignedNode, IDefinition definition)
+ {
+ IDefinition assignedDef = null;
+ IDefinition assignedTypeDef = null;
+ ICompilerProject project = getWalker().getProject();
+ if (assignedNode != null)
+ {
+ assignedDef = assignedNode.resolve(project);
+ assignedTypeDef = assignedNode.resolveType(project);
+ if (project.getBuiltinType(BuiltinType.ANY_TYPE).equals(assignedTypeDef))
+ {
+ IDefinition resolvedXMLDef = SemanticUtils.resolveXML(assignedNode, project);
+ if (resolvedXMLDef != null)
+ {
+ assignedDef = resolvedXMLDef;
+ assignedTypeDef = SemanticUtils.resolveTypeXML(assignedNode, project);
+ }
+ }
+ }
+ String coercionStart = null;
+ String coercionEnd = null;
+ boolean avoidCoercion = false;
+ if (project.getBuiltinType(BuiltinType.INT).equals(definition))
+ {
+ boolean needsCoercion = false;
+ if (assignedNode instanceof INumericLiteralNode)
+ {
+ INumericLiteralNode numericLiteral = (INumericLiteralNode) assignedNode;
+ INumericLiteralNode.INumericValue numericValue = numericLiteral.getNumericValue();
+ startMapping(assignedNode);
+ if(numericValue.toString().startsWith("0x"))
+ {
+ //for readability, keep the same formatting
+ write("0x" + Integer.toHexString(numericValue.toInt32()));
+ }
+ else
+ {
+ write(Integer.toString(numericValue.toInt32()));
+ }
+ endMapping(assignedNode);
+ return;
+ }
+ else if(assignedNode instanceof BinaryOperatorAsNode)
+ {
+ needsCoercion = true;
+ }
+ else if(!project.getBuiltinType(BuiltinType.INT).equals(assignedTypeDef))
+ {
+ needsCoercion = true;
+ }
+ if (needsCoercion)
+ {
+ coercionStart = "(";
+ coercionEnd = ") >> 0";
+ }
+ }
+ else if (project.getBuiltinType(BuiltinType.UINT).equals(definition))
+ {
+ boolean needsCoercion = false;
+ if (assignedNode instanceof INumericLiteralNode)
+ {
+ INumericLiteralNode numericLiteral = (INumericLiteralNode) assignedNode;
+ INumericLiteralNode.INumericValue numericValue = numericLiteral.getNumericValue();
+ startMapping(assignedNode);
+ if(numericValue.toString().startsWith("0x"))
+ {
+ //for readability, keep the same formatting
+ write("0x" + Long.toHexString(numericValue.toUint32()));
+ }
+ else
+ {
+ write(Long.toString(numericValue.toUint32()));
+ }
+ endMapping(assignedNode);
+ return;
+ }
+ else if(assignedNode instanceof BinaryOperatorAsNode)
+ {
+ needsCoercion = true;
+ }
+ else if(!project.getBuiltinType(BuiltinType.UINT).equals(assignedTypeDef))
+ {
+ needsCoercion = true;
+ }
+ if (needsCoercion)
+ {
+ coercionStart = "(";
+ coercionEnd = ") >>> 0";
+ }
+ }
+ else if (project.getBuiltinType(BuiltinType.NUMBER).equals(definition)
+ && !project.getBuiltinType(BuiltinType.NUMBER).equals(assignedTypeDef)
+ && !project.getBuiltinType(BuiltinType.INT).equals(assignedTypeDef)
+ && !project.getBuiltinType(BuiltinType.UINT).equals(assignedTypeDef))
+ {
+ boolean needsCoercion = true;
+ if (assignedNode instanceof IDynamicAccessNode)
+ {
+ IDynamicAccessNode dynamicAccess = (IDynamicAccessNode) assignedNode;
+ IDefinition dynamicAccessIndexDef = dynamicAccess.getRightOperandNode().resolveType(project);
+ if (project.getBuiltinType(BuiltinType.NUMBER).equals(dynamicAccessIndexDef))
+ {
+ IDefinition leftDef = dynamicAccess.getLeftOperandNode().resolveType(project);
+ IMetaTag[] metas = leftDef.getAllMetaTags();
+ for (IMetaTag meta : metas)
+ {
+ if (meta.getTagName().equals(IMetaAttributeConstants.ATTRIBUTE_ARRAYELEMENTTYPE))
+ {
+ IMetaTagAttribute[] attrs = meta.getAllAttributes();
+ for (IMetaTagAttribute attr : attrs)
+ {
+ String t = attr.getValue();
+ if (t.equals(IASLanguageConstants.Number))
+ {
+ needsCoercion = false;
+ //explicitly prevent other coercion detection rules from picking this up
+ avoidCoercion = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (needsCoercion)
+ {
+ coercionStart = "Number(";
+ }
+ }
+ else if (project.getBuiltinType(BuiltinType.BOOLEAN).equals(definition)
+ && !project.getBuiltinType(BuiltinType.BOOLEAN).equals(assignedTypeDef))
+ {
+ if (project.getBuiltinType(BuiltinType.NULL).equals(assignedTypeDef)
+ || (assignedDef != null && assignedDef.getQualifiedName().equals(IASLanguageConstants.UNDEFINED)))
+ {
+ //null and undefined are coerced to false
+ startMapping(assignedNode);
+ write(IASLanguageConstants.FALSE);
+ endMapping(assignedNode);
+ return;
+ }
+ if (assignedNode instanceof INumericLiteralNode)
+ {
+ INumericLiteralNode numericLiteral = (INumericLiteralNode) assignedNode;
+ INumericLiteralNode.INumericValue numericValue = numericLiteral.getNumericValue();
+ //zero is coerced to false, and everything else is true
+ String booleanValue = numericValue.toNumber() == 0.0
+ ? IASLanguageConstants.FALSE
+ : IASLanguageConstants.TRUE;
+ startMapping(assignedNode);
+ write(booleanValue);
+ endMapping(assignedNode);
+ return;
+ }
+ coercionStart = "!!(";
+ }
+ else if (project.getBuiltinType(BuiltinType.STRING).equals(definition)
+ && !project.getBuiltinType(BuiltinType.STRING).equals(assignedTypeDef)
+ && !project.getBuiltinType(BuiltinType.NULL).equals(assignedTypeDef)
+ && !(project.getBuiltinType(BuiltinType.ANY_TYPE).equals(assignedTypeDef)
+ && SemanticUtils.isToStringFunctionCall(assignedNode, project)))
+ {
+ if(assignedDef != null && assignedDef.getQualifiedName().equals(IASLanguageConstants.UNDEFINED))
+ {
+ //undefined is coerced to null
+ startMapping(assignedNode);
+ write(IASLanguageConstants.NULL);
+ endMapping(assignedNode);
+ return;
+ }
+ boolean emitStringCoercion = true;
+ IDocEmitter docEmitter = getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ emitStringCoercion = royaleDocEmitter.emitStringConversions;
+ }
+ if (emitStringCoercion)
+ {
+ coercionStart = "org.apache.royale.utils.Language.string(";
+ }
+ }
+ if ( assignedDef != null
+ && assignedDef instanceof IAppliedVectorDefinition
+ && assignedNode instanceof TypedExpressionNode) {
+ //assign a Vector class as the assigned value, e.g. var c:Class = Vector.<int>
+ if (project instanceof RoyaleJSProject
+ && ((RoyaleJSProject)project).config.getJsVectorEmulationClass() != null) {
+ startMapping(assignedNode);
+ write(((RoyaleJSProject)project).config.getJsVectorEmulationClass());
+ endMapping(assignedNode);
+ } else {
+ startMapping(assignedNode);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(formatQualifiedName(((TypedExpressionNode)assignedNode).getTypeNode().resolve(project).getQualifiedName()));
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ endMapping(assignedNode);
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getModel().needLanguage = true;
+ }
+ return;
+ }
+ if (assignedDef instanceof IClassDefinition
+ && assignedNode instanceof IdentifierNode
+ && ((IdentifierNode)assignedNode).getName().equals(IASGlobalFunctionConstants.Vector)
+ && project instanceof RoyaleJSProject
+ && ((RoyaleJSProject)project).config.getJsVectorEmulationClass() == null ){
+ startMapping(assignedNode);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ //null to signify not a valid constructor
+ write(ASEmitterTokens.NULL);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ endMapping(assignedNode);
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getModel().needLanguage = true;
+ return;
+ }
+ if (coercionStart == null
+ && !avoidCoercion
+ && assignedTypeDef !=null
+ && definition !=null
+ && (project.getBuiltinType(BuiltinType.ANY_TYPE).equals(assignedTypeDef)
+ || project.getBuiltinType(BuiltinType.OBJECT).equals(assignedTypeDef))
+ && !(project.getBuiltinType(BuiltinType.ANY_TYPE).equals(definition)
+ || project.getBuiltinType(BuiltinType.OBJECT).equals(definition))) {
+ //catch leftovers: remaining implicit coercion of loosely typed assigned values to strongly typed context
+ //assignment to Class definitions is excluded because there is no 'Class' type in JS
+ //Possibility: 'Class' could be implemented as a synthType
+ boolean needsCoercion = ((RoyaleJSProject)project).config.getJsComplexImplicitCoercions();
+
+ IDocEmitter docEmitter = getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ //check for local toggle
+ if (needsCoercion) needsCoercion = !(royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION, false));
+ else {
+ if (royaleDocEmitter.hasLocalSetting(JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION.getToken())) {
+ needsCoercion = !(royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION, false));
+ }
+ }
+ if (needsCoercion) {
+ //check for individual specified suppression
+
+ String definitionName = definition.getQualifiedName();
+ //for Vectors, use the unqualified name to match the source code
+ if (NativeUtils.isVector(definitionName)) {
+ definitionName = definition.getBaseName();
+ }
+
+ if (royaleDocEmitter.getLocalSettingIncludesString(
+ JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION,
+ definitionName))
+ {
+ needsCoercion = false;
+ }
+
+ }
+ }
+
+ //Avoid specific compile-time 'fake' class(es)
+ if (needsCoercion && definition.getQualifiedName().equals("org.apache.royale.core.WrappedHTMLElement")) {
+ //*actual* coercion fails here, because this is not actually instantiated, it is
+ //simply a type definition representing the 'wrapped' (or tagged) HTMLElement
+ needsCoercion = false;
+ }
+
+ //Avoid XML/XMLList:
+ if (needsCoercion && project.getBuiltinType(BuiltinType.XML) != null) {
+ if (project.getBuiltinType(BuiltinType.XML).equals(definition)
+ || project.getBuiltinType(BuiltinType.XMLLIST).equals(definition)) {
+ //XML/XMLList has complex output and would need more work
+ needsCoercion = false;
+ }
+ }
+
+ //avoid scenario with ArrayElementType specified as metadata definition type - assume it is 'typed'
+ if (needsCoercion && assignedNode instanceof IDynamicAccessNode)
+ {
+ IDynamicAccessNode dynamicAccess = (IDynamicAccessNode) assignedNode;
+ IDefinition dynamicAccessIndexDef = dynamicAccess.getRightOperandNode().resolveType(project);
+ if (project.getBuiltinType(BuiltinType.NUMBER).equals(dynamicAccessIndexDef))
+ {
+ IDefinition leftDef = dynamicAccess.getLeftOperandNode().resolveType(project);
+ if (leftDef != null) {
+ IMetaTag[] metas = leftDef.getAllMetaTags();
+ for (IMetaTag meta : metas)
+ {
+ if (meta.getTagName().equals(IMetaAttributeConstants.ATTRIBUTE_ARRAYELEMENTTYPE))
+ {
+ IMetaTagAttribute[] attrs = meta.getAllAttributes();
+ for (IMetaTagAttribute attr : attrs)
+ {
+ String t = attr.getValue();
+ if (t.equals(definition.getQualifiedName()))
+ {
+ needsCoercion = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (needsCoercion && project.getBuiltinType(BuiltinType.STRING).equals(definition)) {
+ //explicit suppression of String coercion
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ needsCoercion = royaleDocEmitter.emitStringConversions;
+ }
+ if (needsCoercion
+ && assignedNode instanceof FunctionCallNode
+ && ((FunctionCallNode) assignedNode).getNameNode() instanceof MemberAccessExpressionNode
+ && ((MemberAccessExpressionNode)((FunctionCallNode) assignedNode).getNameNode()).getRightOperandNode() instanceof IdentifierNode
+ && ((IdentifierNode)(((MemberAccessExpressionNode)((FunctionCallNode) assignedNode).getNameNode()).getRightOperandNode())).getName().equals("toString")) {
+ //even if toString() is called in an untyped way, assume a call to a method named 'toString' is actually providing a String
+ needsCoercion = false;
+ }
+ }
+
+ if (needsCoercion) {
+ //add a comment tag leader, so implicit casts are identifiable in the output
+ coercionStart = "/* implicit cast */ "
+ + JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken()
+ + ASEmitterTokens.MEMBER_ACCESS.getToken()
+ + ASEmitterTokens.AS.getToken()
+ + ASEmitterTokens.PAREN_OPEN.getToken();
+ String coercionTypeString = formatQualifiedName(definition.getQualifiedName());
+ if (NativeUtils.isSyntheticJSType(coercionTypeString)) {
+ String synthCall;
+ String synthethicType;
+ if (NativeUtils.isVector(coercionTypeString)) {
+ synthCall = JSRoyaleEmitterTokens.SYNTH_VECTOR.getToken();
+ synthethicType = formatQualifiedName(coercionTypeString.substring(8, coercionTypeString.length() -1));
+ } else {
+ synthCall = JSRoyaleEmitterTokens.SYNTH_TYPE.getToken();
+ synthethicType = coercionTypeString;
+ }
+ coercionTypeString = synthCall
+ + ASEmitterTokens.PAREN_OPEN.getToken()
+ + ASEmitterTokens.SINGLE_QUOTE.getToken()
+ + synthethicType
+ + ASEmitterTokens.SINGLE_QUOTE.getToken()
+ + ASEmitterTokens.PAREN_CLOSE.getToken();
+ }
+
+ coercionEnd = ASEmitterTokens.COMMA.getToken()
+ + ASEmitterTokens.SPACE.getToken()
+ + coercionTypeString
+ + ASEmitterTokens.COMMA.getToken()
+ + ASEmitterTokens.SPACE.getToken()
+ + ASEmitterTokens.TRUE.getToken()
+ + ASEmitterTokens.PAREN_CLOSE.getToken();
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getModel().needLanguage = true;
+ }
+ }
+
+ if (coercionStart != null)
+ {
+ write(coercionStart);
+ }
+ emitAssignedValue(assignedNode);
+ if (coercionStart != null)
+ {
+ if (coercionEnd != null)
+ {
+ write(coercionEnd);
+ }
+ else
+ {
+ write(")");
+ }
+ }
+ }
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSSessionModel.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSSessionModel.java
index 6d24b66..55eb732 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSSessionModel.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSSessionModel.java
@@ -76,7 +76,14 @@
public ArrayList<IFunctionNode> methods;
public IClassDefinition classDefinition;
public ImplicitBindableImplementation bindableImplementation;
+ public Boolean suppressExports;
}
+
+ public JSSessionModel()
+ {
+
+ }
+
private Stack<Context> stack = new Stack<Context>();
public boolean needLanguage = false;
@@ -87,6 +94,8 @@
public boolean inStaticInitializer = false;
+ public boolean suppressExports = false;
+
private LinkedHashMap<String, PropertyNodes> propertyMap = new LinkedHashMap<String, PropertyNodes>();
private List<String> interfacePropertyMap = new ArrayList<String>();
@@ -107,6 +116,8 @@
private ImplicitBindableImplementation implicitBindableImplementation = ImplicitBindableImplementation.NONE;
+ public String primaryDefinitionQName;
+
public IClassDefinition getCurrentClass()
{
return currentClass;
@@ -142,7 +153,9 @@
context.vars = vars;
context.methods = methods;
context.bindableImplementation = implicitBindableImplementation;
+ context.suppressExports = suppressExports;
stack.push(context);
+ suppressExports = false; //always defaults to false
this.currentClass = currentClass;
bindableVars = new HashMap<String, BindableVarInfo>();
staticPropertyMap = new LinkedHashMap<String, PropertyNodes>();
@@ -166,6 +179,7 @@
vars = context.vars;
methods = context.methods;
implicitBindableImplementation = context.bindableImplementation;
+ suppressExports = context.suppressExports;
}
public HashMap<String, PropertyNodes> getPropertyMap()
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSWriter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSWriter.java
index 50b0be2..376bcba 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSWriter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/JSWriter.java
@@ -99,7 +99,13 @@
try
{
- jsOut.write(emitter.postProcess(writer.toString()).getBytes());
+ String emitted = writer.toString();
+ if(!isExterns)
+ {
+ //nothing to post-process in externs
+ emitted = emitter.postProcess(emitted);
+ }
+ jsOut.write(emitted.getBytes("utf8"));
}
catch (IOException e)
{
@@ -109,11 +115,19 @@
if (jsSourceMapOut != null)
{
String sourceMapFilePath = null;
+ String sourceRoot = null;
if (sourceMapFile != null)
{
sourceMapFilePath = sourceMapFile.getAbsolutePath();
convertMappingSourcePathsToRelative(emitter, sourceMapFile);
}
+ else
+ {
+ sourceRoot = System.getProperty("user.dir");
+ convertMappingSourcePathsToRelative((IMappingEmitter) emitter, new File(sourceRoot, "test.js.map"));
+ sourceRoot = convertSourcePathToURI(sourceRoot);
+ }
+ convertMappingSourcePathsToURI(emitter);
File compilationUnitFile = new File(compilationUnit.getAbsoluteFilename());
ISourceMapEmitter sourceMapEmitter = backend.createSourceMapEmitter(emitter);
@@ -121,8 +135,8 @@
{
String fileName = compilationUnitFile.getName();
fileName = fileName.replace(".as", ".js");
- String sourceMap = sourceMapEmitter.emitSourceMap(fileName, sourceMapFilePath, null);
- jsSourceMapOut.write(sourceMap.getBytes());
+ String sourceMap = sourceMapEmitter.emitSourceMap(fileName, sourceMapFilePath, sourceRoot);
+ jsSourceMapOut.write(sourceMap.getBytes("utf8"));
} catch (Exception e)
{
e.printStackTrace();
@@ -135,13 +149,36 @@
List<IMappingEmitter.SourceMapMapping> mappings = emitter.getSourceMapMappings();
for (IMappingEmitter.SourceMapMapping mapping : mappings)
{
- mapping.sourcePath = relativePath(mapping.sourcePath, relativeToFile.getAbsolutePath());
+ String relativePath = relativize(mapping.sourcePath, relativeToFile.getAbsolutePath());
+ mapping.sourcePath = relativePath;
}
}
+
+ protected void convertMappingSourcePathsToURI(IMappingEmitter emitter)
+ {
+ List<IMappingEmitter.SourceMapMapping> mappings = emitter.getSourceMapMappings();
+ for (IMappingEmitter.SourceMapMapping mapping : mappings)
+ {
+ //prefer forward slash because web browser devtools expect it
+ String sourcePath = mapping.sourcePath;
+ sourcePath = convertSourcePathToURI(sourcePath);
+ mapping.sourcePath = sourcePath;
+ }
+ }
+
+ protected String convertSourcePathToURI(String sourcePath)
+ {
+ File file = new File(sourcePath);
+ if(file.isAbsolute())
+ {
+ sourcePath = "file:///" + sourcePath;
+ }
+ return sourcePath.replace('\\', '/');
+ }
//if we ever support Java 7, the java.nio.file.Path relativize() method
//should be able to replace this method
- private String relativePath(String filePath, String relativeToFilePath)
+ private String relativize(String filePath, String relativeToFilePath)
{
boolean caseInsensitive = System.getProperty("os.name").toLowerCase().startsWith("windows");
if(caseInsensitive)
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogDocEmitter.java
index 6c94259..c64823a 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogDocEmitter.java
@@ -39,6 +39,7 @@
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.scopes.ASScope;
import org.apache.royale.compiler.internal.semantics.SemanticUtils;
+import org.apache.royale.compiler.internal.tree.as.TypedExpressionNode;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IClassNode;
@@ -128,7 +129,7 @@
if (def != null)
packageName = def.getPackageName();
- emitType(node, packageName);
+ emitType(node, packageName, project);
end();
}
@@ -257,15 +258,14 @@
packageName = ((ITypeDefinition) type).getPackageName();
}
}
-
- emitTypeShort(node, project.getActualPackageName(packageName));
+ emitTypeShort(node, project.getActualPackageName(packageName), project);
}
else
{
writeNewline();
begin();
emitConst(node);
- emitType(node, project.getActualPackageName(packageName));
+ emitType(node, project.getActualPackageName(packageName), project);
end();
}
}
@@ -361,9 +361,18 @@
}
@Override
- public void emitType(IASNode node, String packageName)
+ public void emitType(IASNode node, String packageName, ICompilerProject project)
{
String type = ((IVariableNode) node).getVariableType();
+ if (((IVariableNode) node).getVariableTypeNode() instanceof TypedExpressionNode) {
+ ITypeDefinition elemenTypeDef = ((TypedExpressionNode)(((IVariableNode) node).getVariableTypeNode())).getTypeNode().resolveType(project);
+ if (elemenTypeDef != null) {
+ type = "Vector.<" +
+ convertASTypeToJS(elemenTypeDef.getQualifiedName(),"")
+ +">";
+ packageName = "";
+ }
+ }
emitJSDocLine(JSGoogDocEmitterTokens.TYPE.getToken(),
convertASTypeToJS(type, packageName));
}
@@ -375,9 +384,18 @@
convertASTypeToJS(type, packageName));
}
- public void emitTypeShort(IASNode node, String packageName)
+ public void emitTypeShort(IASNode node, String packageName, ICompilerProject project)
{
String type = ((IVariableNode) node).getVariableType();
+ if (((IVariableNode) node).getVariableTypeNode() instanceof TypedExpressionNode) {
+ ITypeDefinition elemenTypeDef = ((TypedExpressionNode)(((IVariableNode) node).getVariableTypeNode())).getTypeNode().resolveType(project);
+ if (elemenTypeDef != null) {
+ type = "Vector.<" +
+ convertASTypeToJS(elemenTypeDef.getQualifiedName(),"")
+ +">";
+ packageName = "";
+ }
+ }
writeToken(JSDocEmitterTokens.JSDOC_OPEN);
write(ASEmitterTokens.ATSIGN);
writeToken(JSGoogDocEmitterTokens.TYPE);
@@ -494,16 +512,18 @@
// is a vector so convert the element type
String elementType = name.substring(8, name.length() - 1);
elementType = convertASTypeToJSType(elementType, pname);
- name = "Vector.<" + elementType + ">";
+ name = "Array.<" + elementType + ">";
}
- IASGlobalFunctionConstants.BuiltinType[] builtinTypes = IASGlobalFunctionConstants.BuiltinType
- .values();
- for (IASGlobalFunctionConstants.BuiltinType builtinType : builtinTypes)
- {
- if (name.equalsIgnoreCase(builtinType.getName()))
+ else {
+ IASGlobalFunctionConstants.BuiltinType[] builtinTypes = IASGlobalFunctionConstants.BuiltinType
+ .values();
+ for (IASGlobalFunctionConstants.BuiltinType builtinType : builtinTypes)
{
- isBuiltinFunction = true;
- break;
+ if (name.equalsIgnoreCase(builtinType.getName()))
+ {
+ isBuiltinFunction = true;
+ break;
+ }
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java
index 88628d5..0d495f7 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogEmitter.java
@@ -44,17 +44,13 @@
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
-import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
-import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition.INamepaceDeclarationDirective;
import org.apache.royale.compiler.internal.definitions.VariableDefinition;
import org.apache.royale.compiler.internal.scopes.PackageScope;
import org.apache.royale.compiler.internal.tree.as.ChainedVariableNode;
import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
import org.apache.royale.compiler.internal.tree.as.FunctionNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.VariableNode;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.VariableUsedBeforeDeclarationProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
@@ -186,6 +182,7 @@
ITypeNode tnode = EmitterUtils.findTypeNode(definition.getNode());
if (tnode != null)
{
+ getModel().primaryDefinitionQName = formatQualifiedName(type.getQualifiedName());
getWalker().walk(tnode); // IClassNode | IInterfaceNode
}
return;
@@ -703,7 +700,10 @@
boolean isLocal = false;
if (node.getFunctionClassification() == IFunctionDefinition.FunctionClassification.LOCAL)
isLocal = true;
- if (EmitterUtils.hasBody(node) && !isStatic && !isLocal)
+ boolean isPackage = false;
+ if (node.getFunctionClassification() == IFunctionDefinition.FunctionClassification.PACKAGE_MEMBER)
+ isPackage = true;
+ if (EmitterUtils.hasBody(node) && !isStatic && !isLocal && !isPackage)
emitSelfReference(node);
if (node.isConstructor()
@@ -954,22 +954,15 @@
}
else
{
- // AJH need Language.bind here and maybe not require
- // that the node is a MemberAccessExpression
- if (definition instanceof FunctionDefinition &&
- !((FunctionDefinition)definition).isStatic() &&
- (!(definition instanceof AccessorDefinition)) &&
- node instanceof MemberAccessExpressionNode &&
- ((MemberAccessExpressionNode)node).getLeftOperandNode().getNodeID() != ASTNodeID.SuperID)
+ if (definition instanceof IFunctionDefinition &&
+ node.getNodeID() == ASTNodeID.NamespaceAccessExpressionID)
{
- emitClosureStart();
- getWalker().walk(node);
- writeToken(ASEmitterTokens.COMMA);
- getWalker().walk(((MemberAccessExpressionNode)node).getLeftOperandNode());
- emitClosureEnd(((MemberAccessExpressionNode)node).getLeftOperandNode(), definition);
+ // can't do normal walk. Need to generate closure
+ // so walk just the right operand
+ getWalker().walk(node.getChild(1));
}
else
- getWalker().walk(node);
+ getWalker().walk(node);
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogPublisher.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogPublisher.java
index 45c14a9..97dd8d4 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogPublisher.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JSGoogPublisher.java
@@ -111,14 +111,14 @@
DirectoryFileFilter.DIRECTORY);
for (File file : files)
{
- inputs.add(SourceFile.fromFile(file));
+ inputs.add(SourceFile.fromFile(file.getAbsolutePath()));
}
copyFile(closureGoogSrcLibDir, closureGoogTgtLibDir);
copyFile(closureTPSrcLibDir, closureTPTgtLibDir);
final List<SourceFile> deps = new ArrayList<SourceFile>();
- deps.add(SourceFile.fromFile(depsSrcFile));
+ deps.add(SourceFile.fromFile(depsSrcFile.getAbsolutePath()));
ErrorManager errorManager = new JSGoogErrorManager();
DepsGenerator depsGenerator = new DepsGenerator(deps, inputs,
@@ -322,6 +322,7 @@
{
if (!dir.mkdirs())
{
+ jar.close();
throw new IOException("Unable to create directory "
+ dir.getAbsolutePath());
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JarSourceFile.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JarSourceFile.java
index 8878f62..1f97c80 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JarSourceFile.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/goog/JarSourceFile.java
@@ -19,7 +19,6 @@
package org.apache.royale.compiler.internal.codegen.js.goog;
-import com.google.common.io.CharSource;
import com.google.javascript.jscomp.Region;
import com.google.javascript.jscomp.SourceFile;
@@ -32,12 +31,16 @@
*/
public class JarSourceFile extends SourceFile {
- private String fileName;
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3821969963886712441L;
+ private String fileName;
private boolean isExtern;
private String code;
public JarSourceFile(String fileName, String code, boolean isExtern) {
- super(fileName);
+ super(fileName, isExtern ? SourceKind.EXTERN : SourceKind.STRONG);
this.fileName = fileName;
this.isExtern = isExtern;
this.code = code;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
index ce3fd25..dcaeacf 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AccessorEmitter.java
@@ -105,7 +105,7 @@
if (emitExports)
writeNewline(" * @export");
if (p.type != null)
- writeNewline(" * @type {"+JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
+ writeNewline(" * @type {"+ JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
else
writeNewline(" */");
write(getEmitter().formatQualifiedName(qname));
@@ -117,7 +117,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, propName, true));
}
else
{
@@ -143,7 +143,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -205,7 +205,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -321,7 +321,12 @@
if (emitExports)
writeNewline(" * @export");
if (p.type != null)
- writeNewline(" * @type {"+JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
+ {
+ String typeName = p.type.getBaseName();
+ if (getModel().isInternalClass(typeName))
+ typeName = getModel().getInternalClasses().get(typeName);
+ writeNewline(" * @type {" + JSGoogDocEmitter.convertASTypeToJSType(typeName, p.type.getPackageName()) + "} */");
+ }
else
writeNewline(" */");
FunctionNode fnNode = getterNode != null ? (FunctionNode) getterNode : (FunctionNode) setterNode;
@@ -331,7 +336,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("\"" + s + "::" + propName + "\"");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, propName, false));
}
else
write(propName);
@@ -353,7 +358,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -386,7 +391,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -414,7 +419,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -448,7 +453,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -483,7 +488,7 @@
if (emitExports)
writeNewline(" * @export");
if (p.type != null)
- writeNewline(" * @type {"+JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
+ writeNewline(" * @type {" + JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
else
writeNewline(" */");
write(getEmitter().formatQualifiedName(qname));
@@ -493,7 +498,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, propName, true));
}
else
{
@@ -516,7 +521,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -546,7 +551,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -602,7 +607,7 @@
if (emitExports)
writeNewline(" * @export");
if (p.type != null)
- writeNewline(" * @type {"+JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
+ writeNewline(" * @type {" + JSGoogDocEmitter.convertASTypeToJSType(p.type.getBaseName(), p.type.getPackageName()) + "} */");
else
writeNewline(" */");
write(propName);
@@ -622,7 +627,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.GETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -646,7 +651,7 @@
INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- write("[\"" + s + "::" + JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, JSRoyaleEmitterTokens.SETTER_PREFIX.getToken() + propName, true));
}
else
{
@@ -663,7 +668,7 @@
}
}
- public void emitGet(IGetterNode node)
+ public void emitGet(IGetterNode node)
{
// TODO (mschmalle) will remove this cast as more things get abstracted
JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
@@ -675,8 +680,8 @@
HashMap<String, PropertyNodes> map = isStatic ? getModel()
.getStaticPropertyMap() : getModel().getPropertyMap();
String name = node.getName();
- if (!isStatic && def != null && def.isPrivate() && getProject().getAllowPrivateNameConflicts())
- name = fjs.formatPrivateName(def.getParent().getQualifiedName(), name);
+ if (!isStatic && def != null && def.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ name = fjs.formatPrivateName(def.getParent().getQualifiedName(), name);
PropertyNodes p = map.get(name);
if (p == null)
{
@@ -704,8 +709,8 @@
HashMap<String, PropertyNodes> map = isStatic ? getModel()
.getStaticPropertyMap() : getModel().getPropertyMap();
String name = node.getName();
- if (!isStatic && def != null && def.isPrivate() && getProject().getAllowPrivateNameConflicts())
- name = fjs.formatPrivateName(def.getParent().getQualifiedName(), name);
+ if (!isStatic && def != null && def.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ name = fjs.formatPrivateName(def.getParent().getQualifiedName(), name);
PropertyNodes p = map.get(name);
if (p == null)
{
@@ -758,6 +763,7 @@
fjs.emitParameters(node.getParametersContainerNode());
//writeNewline();
fjs.emitMethodScope(node.getScopedNode());
+ writeNewline();
}
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java
index e8ffe98..9ddea56 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/AsIsEmitter.java
@@ -22,6 +22,7 @@
import org.apache.royale.compiler.asdoc.royale.ASDocComment;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.definitions.IAppliedVectorDefinition;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
@@ -29,12 +30,14 @@
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
+import org.apache.royale.compiler.utils.NativeUtils;
public class AsIsEmitter extends JSSubEmitter
{
@@ -53,7 +56,7 @@
.resolve(getProject()) : null;
if (id != ASTNodeID.Op_IsID && dnode != null)
{
- boolean emit = coercion ?
+ boolean emit = coercion ?
!((RoyaleJSProject)getProject()).config.getJSOutputOptimizations().contains(JSRoyaleEmitterTokens.SKIP_FUNCTION_COERCIONS.getToken()) :
!((RoyaleJSProject)getProject()).config.getJSOutputOptimizations().contains(JSRoyaleEmitterTokens.SKIP_AS_COERCIONS.getToken());
@@ -147,7 +150,7 @@
getEmitter().getModel().needLanguage = true;
if (node instanceof IBinaryOperatorNode)
{
- IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node;
+ IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node;
startMapping(node, binaryOperatorNode.getLeftOperandNode());
}
else
@@ -181,7 +184,29 @@
if (dnode instanceof IClassDefinition)
{
startMapping(right);
- write(getEmitter().formatQualifiedName(((JSRoyaleEmitter)getEmitter()).convertASTypeToJS(dnode.getQualifiedName())));
+ if (NativeUtils.isSyntheticJSType(dnode.getQualifiedName())) {
+ JSRoyaleEmitterTokens langMethod;
+ String synthName;
+ if (NativeUtils.isVector(dnode.getQualifiedName()) && dnode instanceof IAppliedVectorDefinition) {
+ langMethod = JSRoyaleEmitterTokens.SYNTH_VECTOR;
+ synthName = getEmitter().formatQualifiedName(((IAppliedVectorDefinition) dnode).resolveElementType(project).getQualifiedName());
+ } else {
+ //non-vector, e.g. int/uint
+ langMethod = JSRoyaleEmitterTokens.SYNTH_TYPE;
+ synthName = getEmitter().formatQualifiedName(dnode.getQualifiedName());
+ }
+ write(langMethod);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(synthName);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject)project).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+ } else {
+ write(getEmitter().formatQualifiedName(((JSRoyaleEmitter)getEmitter()).convertASTypeToJS(dnode.getQualifiedName())));
+ }
endMapping(right);
}
else
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
index 756c3d8..e55ed32 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java
@@ -21,24 +21,23 @@
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
-import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.IFunctionDefinition;
+import org.apache.royale.compiler.definitions.IFunctionDefinition.FunctionClassification;
import org.apache.royale.compiler.definitions.ITypeDefinition;
-import org.apache.royale.compiler.definitions.metadata.IMetaTag;
-import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
+import org.apache.royale.compiler.definitions.IVariableDefinition;
+import org.apache.royale.compiler.definitions.IVariableDefinition.VariableClassification;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
-import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
-import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
-import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
-import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.UnaryOperatorAtNode;
+import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
+import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.internal.semantics.SemanticUtils;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
@@ -91,11 +90,44 @@
IDefinition dnode = (node.getRightOperandNode())
.resolve(getProject());
- if (dnode != null)
- write(getEmitter()
- .formatQualifiedName(dnode.getQualifiedName()));
- else
- getWalker().walk(node.getRightOperandNode());
+ if (dnode != null)
+ {
+ String dnodeQname = dnode.getQualifiedName();
+ boolean isPackageOrFileMember = false;
+ if (dnode instanceof IVariableDefinition)
+ {
+ IVariableDefinition variable = (IVariableDefinition) dnode;
+ VariableClassification classification = variable.getVariableClassification();
+ if (classification == VariableClassification.PACKAGE_MEMBER ||
+ classification == VariableClassification.FILE_MEMBER)
+ {
+ isPackageOrFileMember = true;
+ }
+ }
+ else if (dnode instanceof IFunctionDefinition)
+ {
+ IFunctionDefinition func = (IFunctionDefinition) dnode;
+ FunctionClassification classification = func.getFunctionClassification();
+ if (classification == FunctionClassification.PACKAGE_MEMBER ||
+ classification == FunctionClassification.FILE_MEMBER)
+ {
+ isPackageOrFileMember = true;
+ }
+ }
+ else if(dnode instanceof ITypeDefinition)
+ {
+ isPackageOrFileMember = true;
+ }
+ if(isPackageOrFileMember)
+ {
+ dnodeQname = getEmitter().formatQualifiedName(dnodeQname);
+ }
+ write(dnodeQname);
+ }
+ else
+ {
+ getWalker().walk(node.getRightOperandNode());
+ }
}
else
{
@@ -105,7 +137,7 @@
{
IASNode lnode = leftSide.getChild(0);
IASNode rnode = leftSide.getChild(1);
- IDefinition rnodeDef = (rnode instanceof IIdentifierNode) ?
+ IDefinition rnodeDef = (rnode instanceof IIdentifierNode) ?
((IIdentifierNode) rnode).resolve(getWalker().getProject()) :
null;
boolean isDynamicAccess = rnode instanceof DynamicAccessNode;
@@ -122,7 +154,7 @@
else
write(getEmitter().formatQualifiedName(
getModel().getCurrentClass().getQualifiedName()));
-
+
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSGoogEmitterTokens.SUPERCLASS);
write(ASEmitterTokens.MEMBER_ACCESS);
@@ -318,7 +350,7 @@
else if (leftSide.getNodeID() == ASTNodeID.IdentifierID)
{
if ((leftDef != null)
- && IdentifierNode.isXMLish(leftDef, getWalker().getProject()))
+ && SemanticUtils.isXMLish(leftDef, getWalker().getProject()))
{
if (node.getNodeID() == ASTNodeID.Op_AddAssignID)
{
@@ -396,161 +428,13 @@
}
}
-
- boolean leftIsNumber = (leftDef != null && (leftDef.getQualifiedName().equals(IASLanguageConstants.Number) ||
- leftDef.getQualifiedName().equals(IASLanguageConstants._int) ||
- leftDef.getQualifiedName().equals(IASLanguageConstants.uint)));
- IExpressionNode rNode = node.getRightOperandNode();
- IDefinition rightDef = rNode.resolveType(getWalker().getProject());
- boolean rightIsNumber = (rightDef != null && (rightDef.getQualifiedName().equals(IASLanguageConstants.Number) ||
- rightDef.getQualifiedName().equals(IASLanguageConstants._int) ||
- rightDef.getQualifiedName().equals(IASLanguageConstants.uint)));
- if (leftIsNumber && !rightIsNumber && (rightDef == null || rightDef.getQualifiedName().equals(IASLanguageConstants.ANY_TYPE)))
- {
- if (rNode.getNodeID() == ASTNodeID.FunctionCallID)
- {
- IExpressionNode fnNameNode = ((FunctionCallNode)rNode).getNameNode();
- if (fnNameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
- {
- MemberAccessExpressionNode mae = (MemberAccessExpressionNode)fnNameNode;
- IExpressionNode rightNode = mae.getRightOperandNode();
- rightIsNumber = rightNode.getNodeID() == ASTNodeID.IdentifierID &&
- ((IdentifierNode)rightNode).getName().equals("length") &&
- fjs.isXMLList(mae);
- }
- }
- else if (rNode.getNodeID() == ASTNodeID.ArrayIndexExpressionID)
- {
- DynamicAccessNode dyn = (DynamicAccessNode)rNode;
- IDefinition lDef = dyn.getLeftOperandNode().resolveType(getProject());
- IDefinition rDef = dyn.getRightOperandNode().resolveType(getProject());
- // numeric indexing?
- if (rDef.getQualifiedName().equals(IASLanguageConstants.Number))
- {
- IMetaTag[] metas = lDef.getAllMetaTags();
- for (IMetaTag meta : metas)
- {
- if (meta.getTagName().equals("ArrayElementType"))
- {
- IMetaTagAttribute[] attrs = meta.getAllAttributes();
- for (IMetaTagAttribute attr : attrs)
- {
- String t = attr.getValue();
- if (t.equals(IASLanguageConstants.Number))
- rightIsNumber = true;
- }
- }
- }
- }
- }
- }
- String coercion = (leftIsNumber && !rightIsNumber && isAssignment) ? "Number(" : "";
- if (isAssignment && leftDef != null && leftDef.getQualifiedName().equals(IASLanguageConstants.String))
- {
- if (rNode.getNodeID() != ASTNodeID.LiteralStringID &&
- rNode.getNodeID() != ASTNodeID.LiteralNullID)
- {
- if (rightDef == null ||
- (!(rightDef.getQualifiedName().equals(IASLanguageConstants.String) ||
- (rightDef.getQualifiedName().equals(IASLanguageConstants.ANY_TYPE)
- && rNode.getNodeID() == ASTNodeID.FunctionCallID &&
- isToString(rNode)) ||
- // if not an assignment we don't need to coerce numbers
- (!isAssignment && rightIsNumber) ||
- rightDef.getQualifiedName().equals(IASLanguageConstants.Null))))
- {
- JSRoyaleDocEmitter docEmitter = (JSRoyaleDocEmitter)(getEmitter().getDocEmitter());
- if (docEmitter.emitStringConversions)
- {
- coercion = "org.apache.royale.utils.Language.string(";
- }
- }
- }
- }
- super_emitBinaryOperator(node, coercion);
- if (coercion.length() > 0)
- write(")");
-
- /*
- IExpressionNode leftSide = node.getLeftOperandNode();
-
- IExpressionNode property = null;
- int leftSideChildCount = leftSide.getChildCount();
- if (leftSideChildCount > 0)
- {
- IASNode childNode = leftSide.getChild(leftSideChildCount - 1);
- if (childNode instanceof IExpressionNode)
- property = (IExpressionNode) childNode;
- else
- property = leftSide;
- }
- else
- property = leftSide;
-
- IDefinition def = null;
- if (property instanceof IIdentifierNode)
- def = ((IIdentifierNode) property).resolve(getWalker()
- .getProject());
-
- boolean isSuper = false;
- if (leftSide.getNodeID() == ASTNodeID.MemberAccessExpressionID)
- {
- IASNode cnode = leftSide.getChild(0);
- ASTNodeID cId = cnode.getNodeID();
-
- isSuper = cId == ASTNodeID.SuperID;
- }
-
- String op = node.getOperator().getOperatorText();
- boolean isAssignment = op.contains("=") && !op.contains("==") &&
- !(op.startsWith("<") ||
- op.startsWith(">") ||
- op.startsWith("!"));
-
- if (def instanceof AccessorDefinition && isAssignment)
- {
- // this will make the set_foo call
- getWalker().walk(leftSide);
- }
- else if (isSuper)
- {
- emitSuperCall(node, "");
- }
- else
- {
- if (ASNodeUtils.hasParenOpen(node))
- write(ASEmitterTokens.PAREN_OPEN);
-
- getWalker().walk(leftSide);
-
- if (node.getNodeID() != ASTNodeID.Op_CommaID)
- write(ASEmitterTokens.SPACE);
-
- writeToken(node.getOperator().getOperatorText());
-
- getWalker().walk(node.getRightOperandNode());
-
- if (ASNodeUtils.hasParenClose(node))
- write(ASEmitterTokens.PAREN_CLOSE);
- }
- */
+
+ super_emitBinaryOperator(node, isAssignment);
}
}
- private boolean isToString(IASNode rNode)
- {
- IExpressionNode fnNameNode = ((FunctionCallNode)rNode).getNameNode();
- if (fnNameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
- {
- MemberAccessExpressionNode mae = (MemberAccessExpressionNode)fnNameNode;
- IExpressionNode rightNode = mae.getRightOperandNode();
- return rightNode.getNodeID() == ASTNodeID.IdentifierID &&
- ((IdentifierNode)rightNode).getName().equals("toString");
- }
- return false;
- }
- private void super_emitBinaryOperator(IBinaryOperatorNode node, String coercion)
+ private void super_emitBinaryOperator(IBinaryOperatorNode node, boolean isAssignment)
{
if (ASNodeUtils.hasParenOpen(node))
write(ASEmitterTokens.PAREN_OPEN);
@@ -585,8 +469,28 @@
}
else
{
- getWalker().walk(node.getLeftOperandNode());
-
+ if (isAssignment
+ && (getProject() instanceof RoyaleJSProject && ((RoyaleJSProject) getProject()).config != null && ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass() == null)
+ && node.getLeftOperandNode() instanceof MemberAccessExpressionNode
+ && ((MemberAccessExpressionNode) node.getLeftOperandNode()).getRightOperandNode() instanceof IdentifierNode
+ && ((IdentifierNode) ((MemberAccessExpressionNode) node.getLeftOperandNode()).getRightOperandNode()).getName().equals("length")
+ && ((MemberAccessExpressionNode) node.getLeftOperandNode()).getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition)
+ {
+ //for default Vector implementation, when setting length, we need to set it on the associated 'synthType' instance which tags the native
+ //Array representation of the Vector. This allows running 'setter' code because it is not possible to override the native length setter on Array
+ //unless using a different approach, like es6 Proxy.
+ //this code inserts the extra access name for setting length, e.g. myVectInstance['_synthType'].length = assignedValue
+ //the dynamic access field name is a constant on Language, so it can be different/shorter in release build
+ getWalker().walk(((MemberAccessExpressionNode) node.getLeftOperandNode()).getLeftOperandNode());
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken());
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(JSRoyaleEmitterTokens.ROYALE_SYNTH_TAG_FIELD_NAME);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ getWalker().walk(((MemberAccessExpressionNode) node.getLeftOperandNode()).getRightOperandNode());
+ }
+ else getWalker().walk(node.getLeftOperandNode());
startMapping(node, node.getLeftOperandNode());
if (id != ASTNodeID.Op_CommaID)
@@ -617,25 +521,26 @@
write(ASEmitterTokens.SPACE);
endMapping(node);
- write(coercion);
- /*
- IDefinition definition = node.getRightOperandNode().resolve(getProject());
- if (definition instanceof FunctionDefinition &&
- (!(definition instanceof AccessorDefinition)))
- {
- }
- else */
- getWalker().walk(node.getRightOperandNode());
- if (node.getNodeID() == ASTNodeID.Op_InID &&
- ((JSRoyaleEmitter)getEmitter()).isXML(node.getRightOperandNode()))
- {
- write(".elementNames()");
- }
- else if (node.getNodeID() == ASTNodeID.Op_InID &&
- ((JSRoyaleEmitter)getEmitter()).isProxy(node.getRightOperandNode()))
- {
- write(".propertyNames()");
- }
+ if (isAssignment)
+ {
+ getEmitter().emitAssignmentCoercion(node.getRightOperandNode(), node.getLeftOperandNode().resolveType(getProject()));
+ }
+ else
+ {
+
+ getWalker().walk(node.getRightOperandNode());
+
+ if (node.getNodeID() == ASTNodeID.Op_InID &&
+ ((JSRoyaleEmitter)getEmitter()).isXML(node.getRightOperandNode()))
+ {
+ write(".elementNames()");
+ }
+ else if (node.getNodeID() == ASTNodeID.Op_InID &&
+ ((JSRoyaleEmitter)getEmitter()).isProxy(node.getRightOperandNode()))
+ {
+ write(".propertyNames()");
+ }
+ }
}
if (ASNodeUtils.hasParenOpen(node))
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BindableEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BindableEmitter.java
index cbefd7e..b1c1527 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BindableEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BindableEmitter.java
@@ -447,7 +447,7 @@
{
// TODO (mschmalle) will remove this cast as more things get abstracted
JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
- String qname = info.namespace.equals("private") ? fjs.formatPrivateName(cdef.getQualifiedName(), name) : name;
+ String qname = (info.namespace.equals("private") && getProject().getAllowPrivateNameConflicts()) ? fjs.formatPrivateName(cdef.getQualifiedName(), name) : name;
if (info.namespace != "public") {
writeNewline("/** @export");
writeNewline(" * @private");
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java
index 6c3ddda..4c1877d 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java
@@ -19,6 +19,8 @@
package org.apache.royale.compiler.internal.codegen.js.jx;
+import java.util.List;
+
import org.apache.royale.compiler.asdoc.royale.ASDocComment;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
@@ -55,9 +57,11 @@
@Override
public void emit(IClassNode node)
{
- boolean keepASDoc = false;
+ boolean keepASDoc = false;
+ boolean verbose = false;
RoyaleJSProject project = (RoyaleJSProject)getEmitter().getWalker().getProject();
keepASDoc = project.config != null && project.config.getKeepASDoc();
+ verbose = project.config != null && project.config.isVerbose();
getModel().pushClass(node.getDefinition());
@@ -66,7 +70,20 @@
ASDocComment asDoc = (ASDocComment) node.getASDocComment();
if (asDoc != null && keepASDoc)
- DocEmitterUtils.loadImportIgnores(fjs, asDoc.commentNoEnd());
+ {
+ List<String> ignoreList = DocEmitterUtils.loadImportIgnores(fjs, asDoc.commentNoEnd());
+ if(verbose)
+ {
+ for(String ignorable : ignoreList)
+ {
+ System.out.println("Found ignorable: " + ignorable);
+ }
+ }
+ }
+
+ boolean suppressExport = (asDoc != null && DocEmitterUtils.hasSuppressExport(fjs, asDoc.commentNoEnd()));
+
+ getModel().suppressExports = suppressExport;
IClassDefinition definition = node.getDefinition();
@@ -131,7 +148,7 @@
}
}
- if (!getEmitter().getModel().isExterns)
+ if (!getEmitter().getModel().isExterns && !suppressExport)
{
JSRoyaleDocEmitter doc = (JSRoyaleDocEmitter) getEmitter()
.getDocEmitter();
@@ -246,8 +263,8 @@
write(ASEmitterTokens.MEMBER_ACCESS);
String dname = dnode.getName();
IDefinition dDef = dnode.getDefinition();
- if (dDef != null && dDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
- dname = getEmitter().formatPrivateName(dDef.getParent().getQualifiedName(), dname);
+ if (dDef != null && dDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ dname = getEmitter().formatPrivateName(dDef.getParent().getQualifiedName(), dname);
write(dname);
if (dnode.getNodeID() == ASTNodeID.BindableVariableID)
{
@@ -255,7 +272,7 @@
}
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
- getEmitter().getWalker().walk(vnode);
+ getEmitter().emitAssignmentCoercion(vnode, varnode.getVariableTypeNode().resolve(getProject()));
write(ASEmitterTokens.SEMICOLON);
wroteOne = true;
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java
index 33231d1..5b78317 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java
@@ -19,17 +19,30 @@
package org.apache.royale.compiler.internal.codegen.js.jx;
+import org.apache.royale.compiler.codegen.IDocEmitter;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
+import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.internal.tree.as.BinaryOperatorAssignmentNode;
+import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
+import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.NumericLiteralNode;
+import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.as.ILiteralNode;
+import org.apache.royale.compiler.tree.as.IOperatorNode.OperatorType;
+import org.apache.royale.compiler.utils.NativeUtils;
public class DynamicAccessEmitter extends JSSubEmitter implements
ISubEmitter<IDynamicAccessNode>
@@ -48,19 +61,24 @@
return;
IExpressionNode rightOperandNode = node.getRightOperandNode();
+ ITypeDefinition type = rightOperandNode.resolveType(getProject());
IJSEmitter ijs = getEmitter();
JSRoyaleEmitter fjs = (ijs instanceof JSRoyaleEmitter) ?
(JSRoyaleEmitter)ijs : null;
if (fjs != null)
{
+ boolean isProxy = false;
boolean isXML = false;
if (leftOperandNode instanceof MemberAccessExpressionNode)
isXML = fjs.isLeftNodeXMLish((MemberAccessExpressionNode)leftOperandNode);
else if (leftOperandNode instanceof IExpressionNode)
isXML = fjs.isXML((IExpressionNode)leftOperandNode);
+ if (leftOperandNode instanceof MemberAccessExpressionNode)
+ isProxy = fjs.isProxy((MemberAccessExpressionNode)leftOperandNode);
+ else if (leftOperandNode instanceof IExpressionNode)
+ isProxy = fjs.isProxy((IExpressionNode)leftOperandNode);
if (isXML)
{
- ITypeDefinition type = rightOperandNode.resolveType(getProject());
if (type.isInstanceOf("String", getProject()))
{
String field = fjs.stringifyNode(rightOperandNode);
@@ -74,14 +92,70 @@
return;
}
}
+ else if (isProxy)
+ {
+ boolean isLiteral = rightOperandNode instanceof ILiteralNode;
+ write(".getProperty(");
+ if (isLiteral) write("'");
+ String s = fjs.stringifyNode(rightOperandNode);
+ write(s);
+ if (isLiteral) write("'");
+ write(")");
+ return;
+ }
}
startMapping(node, leftOperandNode);
write(ASEmitterTokens.SQUARE_OPEN);
endMapping(node);
+ boolean wrapVectorIndex = false;
+ if (getProject() instanceof RoyaleJSProject) {
+ if (node.getNodeID().equals(ASTNodeID.ArrayIndexExpressionID)){
+ if (node.getParent() instanceof BinaryOperatorAssignmentNode) {
+ if (node.getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition) {
+ boolean suppressVectorIndexCheck = !(((RoyaleJSProject)getProject()).config.getJsVectorIndexChecks());
+ IDocEmitter docEmitter = getEmitter().getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ //check for local toggle
+ suppressVectorIndexCheck = royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_VECTOR_INDEX_CHECK, suppressVectorIndexCheck);
+
+ if (!suppressVectorIndexCheck) {
+ //check for individual specified suppression, based on variable name
+ if (leftOperandNode instanceof IdentifierNode) {
+ if (royaleDocEmitter.getLocalSettingIncludesString(
+ JSRoyaleEmitterTokens.SUPPRESS_VECTOR_INDEX_CHECK,
+ ((IdentifierNode) leftOperandNode).getName()
+ )){
+ suppressVectorIndexCheck = true;
+ }
+ }
+ }
+ }
+ if (!suppressVectorIndexCheck) {
+ getModel().needLanguage = true;
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getWalker().walk(leftOperandNode);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(JSRoyaleEmitterTokens.VECTOR_INDEX_CHECK_METHOD_NAME);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.PAREN_OPEN);
+ wrapVectorIndex = true;
+ }
+ }
+ }
+ }
+ }
+
getWalker().walk(rightOperandNode);
-
+ if (wrapVectorIndex) {
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
+ if (type != null && type.getQualifiedName().contentEquals(IASLanguageConstants.QName))
+ write(".objectAccessFormat()");
startMapping(node, rightOperandNode);
write(ASEmitterTokens.SQUARE_CLOSE);
endMapping(node);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java
index c9dddc4..784c9c5 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FieldEmitter.java
@@ -25,7 +25,9 @@
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.common.ModifiersSet;
import org.apache.royale.compiler.constants.IASKeywordConstants;
+import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.IVariableDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
@@ -45,6 +47,10 @@
import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
import org.apache.royale.compiler.tree.metadata.IMetaTagsNode;
+/**
+ * Static or member variables of a class. For local variables in a function, see
+ * VarDeclarationEmitter. For accessors, see AccessorEmitter.
+ */
public class FieldEmitter extends JSSubEmitter implements
ISubEmitter<IVariableNode>
{
@@ -103,8 +109,8 @@
+ ASEmitterTokens.MEMBER_ACCESS.getToken() + root);
String qname = node.getName();
IDefinition nodeDef = node.getDefinition();
- if (nodeDef != null && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
- qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
+ if (nodeDef != null && !nodeDef.isStatic() && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
write(qname);
endMapping(node.getNameExpressionNode());
}
@@ -122,12 +128,12 @@
String vnodeString = getEmitter().stringifyNode(vnode);
if (ndef.isStatic() && vnode instanceof FunctionCallNode)
{
- FunctionCallNode fcn = (FunctionCallNode)vnode;
+ FunctionCallNode fcn = (FunctionCallNode)vnode;
if (fcn.getNameNode() instanceof IdentifierNode)
{
+ IDefinition d = fcn.getNameNode().resolve(getProject());
// assume this is a call to static method in the class
// otherwise it would be a memberaccessexpression?
- IDefinition d = (IDefinition)fcn.getNameNode().resolve(getProject());
if (d instanceof FunctionDefinition)
{
FunctionDefinition fd = (FunctionDefinition)d;
@@ -137,11 +143,26 @@
// re-emit it to collect static initializer class references in usedNames
getEmitter().stringifyNode(m);
}
- }
+ }
+ //it could also be a constructor
+ else if (d instanceof IClassDefinition)
+ {
+ IClassDefinition classDef = (IClassDefinition) d;
+ IFunctionDefinition constructorDef = classDef.getConstructor();
+ if (constructorDef != null)
+ {
+ IASNode m = constructorDef.getNode();
+ if (m != null)
+ {
+ // re-emit it to collect static initializer class references in usedNames
+ getEmitter().stringifyNode(m);
+ }
+ }
+ }
}
}
getModel().inStaticInitializer = false;
- if ((ndef.isStatic() && !EmitterUtils.needsStaticInitializer(vnodeString, className)) ||
+ if ((ndef.isStatic() && !EmitterUtils.needsStaticInitializer(vnodeString, className)) ||
(!ndef.isStatic() && EmitterUtils.isScalar(vnode)) ||
isPackageOrFileMember)
{
@@ -154,15 +175,36 @@
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
endMapping(node);
- startMapping(vnode);
- write(vnodeString);
- endMapping(vnode);
+ getEmitter().emitAssignmentCoercion(vnode, node.getVariableTypeNode().resolve(getProject()));
}
else if (ndef.isStatic() && EmitterUtils.needsStaticInitializer(vnodeString, className))
{
hasComplexStaticInitializers = true;
}
- }
+
+ if (!isPackageOrFileMember && !ndef.isStatic() && !EmitterUtils.isScalar(vnode)
+ && getProject() instanceof RoyaleJSProject
+ && ((RoyaleJSProject) getProject()).config != null
+ && ((RoyaleJSProject) getProject()).config.getJsDefaultInitializers()
+ )
+ {
+ //this value will actually be initialized inside the constructor.
+ //but if default initializers is set, we define it on the prototype with null value first.
+ //Why?: this needs to be defined on the prototype to support reflection
+ //otherwise the constructor initializers will create the new property value on 'this' and
+ //there is no runtime clue to separate what is 'dynamic' and what is 'inherited'
+ //these clues throughout the prototype chain are important for runtime identification
+ //of dynamic fields.
+ //runtime checks will only work accurately using this technique if the entire inheritance chain
+ //for the reflection target is compiled with default js initializers, because it permits
+ //inspection of the prototype chain to determine all the sealed members, and isolate them
+ //from whatever else is defined as 'own' properties on the instance (which can be assumed to be
+ // 'dynamic' properties).
+ write(ASEmitterTokens.SPACE);
+ writeToken(ASEmitterTokens.EQUAL);
+ write(ASEmitterTokens.NULL);
+ }
+ }
if (vnode == null && def != null)
{
String defName = def.getQualifiedName();
@@ -197,12 +239,17 @@
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
write(IASKeywordConstants.FALSE);
+
+ } else if (defName.equals("*")) {
+ //setting the value to *undefined* is needed to create the field
+ //on the prototype - this is important for reflection purposes
+ write(ASEmitterTokens.SPACE);
+ writeToken(ASEmitterTokens.EQUAL);
+ write(ASEmitterTokens.UNDEFINED);
}
- else if (!defName.equals("*"))
+ else
{
- //type * is meant to default to undefined, so it
- //doesn't need to be initialized, but everything
- //else should default to null
+ //everything else should default to null
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
write(IASKeywordConstants.NULL);
@@ -263,8 +310,8 @@
if (ndef.isStatic() && EmitterUtils.needsStaticInitializer(vnodeString, className) && !isPackageOrFileMember)
{
writeNewline();
- write(className
- + ASEmitterTokens.MEMBER_ACCESS.getToken());
+ write(className);
+ write(ASEmitterTokens.MEMBER_ACCESS.getToken());
write(node.getName());
if (node.getNodeID() == ASTNodeID.BindableVariableID && !node.isConst())
@@ -278,7 +325,7 @@
write(vnodeString);
write(ASEmitterTokens.SEMICOLON);
return true;
- }
+ }
}
return false;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java
index bca4c59..c92f189 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java
@@ -21,10 +21,14 @@
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.IFunctionDefinition;
+import org.apache.royale.compiler.definitions.IParameterDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.tree.as.IContainerNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.as.IFunctionCallNode;
public class FunctionCallArgumentsEmitter extends JSSubEmitter implements
ISubEmitter<IContainerNode>
@@ -41,11 +45,38 @@
write(ASEmitterTokens.PAREN_OPEN);
endMapping(node);
+ IParameterDefinition[] paramDefs = null;
+ IFunctionCallNode functionCallNode = (IFunctionCallNode) node.getAncestorOfType(IFunctionCallNode.class);
+ if (functionCallNode != null)
+ {
+ IDefinition calledDef = functionCallNode.resolveCalledExpression(getProject());
+ if (calledDef instanceof IFunctionDefinition)
+ {
+ IFunctionDefinition functionDef = (IFunctionDefinition) calledDef;
+ paramDefs = functionDef.getParameters();
+ }
+ }
+
int len = node.getChildCount();
for (int i = 0; i < len; i++)
{
IExpressionNode argumentNode = (IExpressionNode) node.getChild(i);
- getWalker().walk(argumentNode);
+ IDefinition paramTypeDef = null;
+ if (paramDefs != null && paramDefs.length > i)
+ {
+ IParameterDefinition paramDef = paramDefs[i];
+ if (paramDef.isRest())
+ {
+ paramDef = null;
+ }
+ if (paramDef != null)
+ {
+ paramTypeDef = paramDef.resolveType(getProject());
+ }
+ }
+
+ getEmitter().emitAssignmentCoercion(argumentNode, paramTypeDef);
+
if (i < len - 1)
{
//we're mapping the comma to the container, but we use the
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java
index 776ebca..4de1d14 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java
@@ -20,31 +20,29 @@
package org.apache.royale.compiler.internal.codegen.js.jx;
import org.apache.royale.compiler.codegen.IASGlobalFunctionConstants;
+import org.apache.royale.compiler.codegen.IDocEmitter;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.common.SourceLocation;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
-import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
-import org.apache.royale.compiler.internal.definitions.ClassDefinition;
-import org.apache.royale.compiler.internal.definitions.InterfaceDefinition;
+import org.apache.royale.compiler.internal.definitions.*;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.internal.tree.as.ContainerNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.VectorLiteralNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.problems.TooFewFunctionParametersProblem;
import org.apache.royale.compiler.problems.TooManyFunctionParametersProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IContainerNode;
-import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.IFunctionCallNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.utils.NativeUtils;
public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFunctionCallNode>
@@ -60,12 +58,11 @@
{
// TODO (mschmalle) will remove this cast as more things get abstracted
JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
-
IASNode cnode = node.getChild(0);
if (cnode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
cnode = cnode.getChild(0);
-
+ String postCallAppend = null;
ASTNodeID id = cnode.getNodeID();
if (id != ASTNodeID.SuperID)
{
@@ -74,16 +71,45 @@
def = nameNode.resolve(getProject());
boolean isClassCast = false;
-
+ boolean wrapResolve = false;
if (node.isNewExpression())
{
- if (!(node.getChild(1) instanceof VectorLiteralNode))
+ boolean omitNew = false;
+ if (nameNode instanceof IdentifierNode
+ && (((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.String)
+ || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Boolean)
+ || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Number)))
{
- if (def == null || !(def.getBaseName().equals(IASGlobalFunctionConstants._int) ||
- def.getBaseName().equals(IASGlobalFunctionConstants.uint) ||
- def instanceof AppliedVectorDefinition))
+ omitNew = true;
+ }
+
+ if (!((node.getChild(1) instanceof VectorLiteralNode)))
+ {
+ if (!omitNew
+ && ((def == null
+ || !(def.getBaseName().equals(IASGlobalFunctionConstants._int) || def.getBaseName().equals(IASGlobalFunctionConstants.uint)))
+ && !(def instanceof AppliedVectorDefinition && (
+ ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass()!= null
+ && ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass().equals("Array"))
+ ))
+ )
{
- startMapping(node.getNewKeywordNode());
+ if (getProject() instanceof RoyaleJSProject
+ && nameNode.resolveType(getProject()) != null
+ && nameNode.resolveType(getProject()).getQualifiedName().equals("Class")) {
+
+ wrapResolve = shouldResolveUncertain(nameNode, false);
+
+ if (wrapResolve) {
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("resolveUncertain");
+ write(ASEmitterTokens.PAREN_OPEN);
+ }
+ }
+ startMapping(node.getNewKeywordNode());
writeToken(ASEmitterTokens.NEW);
endMapping(node.getNewKeywordNode());
}
@@ -91,7 +117,52 @@
else
{
VectorLiteralNode vectorLiteralNode = (VectorLiteralNode) node.getChild(1);
+ String vectorEmulationClass = (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass());
+ SourceLocation mappingLocation;
+ String elementClassName;
+ IDefinition elementClass = (((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()));
+ elementClassName = getEmitter().formatQualifiedName(elementClass.getQualifiedName());
+ if (vectorEmulationClass != null)
+ {
+ if (!vectorEmulationClass.equals("Array")) {
+ //Explanation:
+ //this was how it was originally set up, but it assumes the constructor of the emulation
+ //class can handle first argument being an Array or numeric value...
+ writeToken(ASEmitterTokens.NEW);
+ write(vectorEmulationClass);
+ write(ASEmitterTokens.PAREN_OPEN);
+ }// otherwise.... if 'Array' is the emulation class, then just use the literal content
+ } else {
+ //no 'new' output in this case, just coercion, so map from the start of 'new'
+ startMapping(node);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(elementClassName);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write("coerce");
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ mappingLocation = new SourceLocation(vectorLiteralNode.getCollectionTypeNode());
+ mappingLocation.setEndColumn(mappingLocation.getEndColumn() + 1);
+ endMapping(mappingLocation);
+ write(ASEmitterTokens.PAREN_OPEN);
+ if (getProject() instanceof RoyaleJSProject)
+ ((RoyaleJSProject)getProject()).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+
+ }
+ mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode());
+ if (mappingLocation.getColumn()>0) mappingLocation.setColumn(mappingLocation.getColumn() -1);
+ mappingLocation.setEndColumn(mappingLocation.getColumn()+1);
+ startMapping(mappingLocation);
write("[");
+
+ endMapping(mappingLocation);
ContainerNode contentsNode = vectorLiteralNode.getContentsNode();
int len = contentsNode.getChildCount();
for (int i = 0; i < len; i++)
@@ -102,7 +173,25 @@
writeToken(ASEmitterTokens.COMMA);
}
}
+ mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode());
+ mappingLocation.setLine(vectorLiteralNode.getContentsNode().getEndLine());
+ mappingLocation.setColumn(vectorLiteralNode.getContentsNode().getEndColumn());
+ mappingLocation.setEndColumn(mappingLocation.getColumn() + 1);
+ startMapping(mappingLocation);
write("]");
+ endMapping(mappingLocation);
+ if (vectorEmulationClass != null)
+ {
+ if (!vectorEmulationClass.equals("Array")) {
+ writeToken(ASEmitterTokens.COMMA);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(elementClassName);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
+ } else {
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
return;
}
}
@@ -110,12 +199,15 @@
{
def = node.getNameNode().resolve(getProject());
- isClassCast = (def instanceof ClassDefinition || def instanceof InterfaceDefinition)
+ isClassCast = def != null && (def instanceof ClassDefinition
+ || def instanceof InterfaceDefinition
+ || ( def instanceof VariableDefinition && ((VariableDefinition) def).resolveType(getProject()).getBaseName().equals("Class")))
&& !(NativeUtils.isJSNative(def.getBaseName()))
&& !def.getBaseName().equals(IASLanguageConstants.XML)
&& !def.getBaseName().equals(IASLanguageConstants.XMLList);
+
}
-
+
if (node.isNewExpression())
{
def = node.resolveCalledExpression(getProject());
@@ -156,16 +248,39 @@
if (nameNode.hasParenthesis())
write(ASEmitterTokens.PAREN_CLOSE);
}
-
- if (def instanceof AppliedVectorDefinition)
+ if ( def instanceof AppliedVectorDefinition
+ && (fjs.getWalker().getProject() instanceof RoyaleJSProject)
+ && (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass() != null))
{
- ContainerNode args = node.getArgumentsNode();
- if (args.getChildCount() == 0)
- {
- getEmitter().emitArguments(node.getArgumentsNode());
- }
- else
- {
+ ContainerNode args = node.getArgumentsNode();
+ String vectorEmulationClass = ((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass();
+ if (args.getChildCount() == 0)
+ {
+ if (vectorEmulationClass.equals("Array")) {
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ } else {
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.COMMA);
+ write(ASEmitterTokens.SPACE);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getQualifiedName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
+ } else {
+ if (vectorEmulationClass.equals("Array")) {
+ if (getProject() instanceof RoyaleJSProject)
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ startMapping(node.getNameNode());
+ write("arrayAsVector");
+ endMapping(node.getNameNode());
+ }
startMapping(node);
write(ASEmitterTokens.PAREN_OPEN);
endMapping(node);
@@ -173,13 +288,29 @@
write(ASEmitterTokens.COMMA);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.SINGLE_QUOTE);
- write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getBaseName());
+ write(((AppliedVectorDefinition) def).resolveElementType(getWalker().getProject()).getQualifiedName());
write(ASEmitterTokens.SINGLE_QUOTE);
+ if (args.getChildCount() == 2 && !vectorEmulationClass.equals("Array")) {
+ IASNode second = args.getChild(1);
+ if (second instanceof IExpressionNode) {
+ ITypeDefinition secondType =
+ ((IExpressionNode) second).resolveType(fjs.getWalker().getProject());
+ if (fjs.getWalker().getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(secondType)) {
+ write(ASEmitterTokens.COMMA);
+ write(ASEmitterTokens.SPACE);
+ getWalker().walk(second);
+ }
+ }
+ }
write(ASEmitterTokens.PAREN_CLOSE);
- }
+ }
+ } else {
+ getEmitter().emitArguments(node.getArgumentsNode());
}
- else
- getEmitter().emitArguments(node.getArgumentsNode());
+ //end wrap resolve
+ if (wrapResolve) {
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
}
else if (!isClassCast)
{
@@ -220,37 +351,100 @@
}
else if (def.getBaseName().equals("sort"))
{
- if (def.getParent() != null &&
- def.getParent().getQualifiedName().equals("Array"))
- {
- IExpressionNode args[] = node.getArgumentNodes();
- if (args.length > 0)
- {
- IExpressionNode optionsParamCheck = args.length == 1 ? args[0] : args[1];
- ICompilerProject project = this.getProject();
- IDefinition paramCheck = optionsParamCheck.resolveType(project);
-
- if (paramCheck.getBaseName().equals(IASLanguageConstants._int)
- || paramCheck.getBaseName().equals(IASLanguageConstants.uint)
- || paramCheck.getBaseName().equals(IASLanguageConstants.Number))
+ if (def.getParent() != null) {
+ if (def.getParent().getQualifiedName().equals("Array")
+ || (node.getNameNode() instanceof MemberAccessExpressionNode
+ && (((MemberAccessExpressionNode) node.getNameNode()).getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition)
+ && getProject() instanceof RoyaleJSProject
+ && (((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass() == null
+ || ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass().equals("Array"))))
+ {
+ IExpressionNode args[] = node.getArgumentNodes();
+ if (args.length > 0)
{
- //deal with specific numeric option argument variations
- //either: Array.sort(option:uint) or Array.sort(compareFunction:Function, option:uint)
- //use our Language sort implementation to support these actionscript-specific method signatures
- if (project instanceof RoyaleJSProject)
- ((RoyaleJSProject) project).needLanguage = true;
- getEmitter().getModel().needLanguage = true;
- write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
- write(ASEmitterTokens.MEMBER_ACCESS);
- write("sort");
- IContainerNode newArgs = EmitterUtils.insertArgumentsBefore(node.getArgumentsNode(), cnode);
- fjs.emitArguments(newArgs);
- return;
+ IExpressionNode optionsParamCheck = args.length == 1 ? args[0] : args[1];
+ ICompilerProject project = this.getProject();
+ IDefinition paramCheck = optionsParamCheck.resolveType(project);
+
+ if (paramCheck.getBaseName().equals(IASLanguageConstants._int)
+ || paramCheck.getBaseName().equals(IASLanguageConstants.uint)
+ || paramCheck.getBaseName().equals(IASLanguageConstants.Number))
+ {
+ //deal with specific numeric option argument variations
+ //either: Array.sort(option:uint) or Array.sort(compareFunction:Function, option:uint)
+ //use our Language sort implementation to support these actionscript-specific method signatures
+ if (project instanceof RoyaleJSProject)
+ ((RoyaleJSProject) project).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("sort");
+ IContainerNode newArgs = EmitterUtils.insertArgumentsBefore(node.getArgumentsNode(), cnode);
+ fjs.emitArguments(newArgs);
+ return;
+ }
}
- }
- }
+ }
+ }
+
}
+ else if ((def.getBaseName().equals("insertAt")
+ || def.getBaseName().equals("removeAt"))
+ && def.getParent() instanceof AppliedVectorDefinition
+ && ((getProject() instanceof RoyaleJSProject) && (
+ ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass() == null
+ || ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass().equals("Array")))
+ ) {
+ if ((((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass() != null)
+ && ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass().equals("Array")) {
+ //use a similar approach to regular 'Array' insertAt/removeAt
+ //for Array Vector emulation only (not for other custom classes)
+ //replace the insertAt/removeAt method with 'splice'
+ IdentifierNode splice = new IdentifierNode("splice");
+ splice.setSourceLocation(((MemberAccessExpressionNode)node.getNameNode()).getRightOperandNode());
+ splice.setParent((MemberAccessExpressionNode)node.getNameNode());
+ ((MemberAccessExpressionNode)node.getNameNode()).setRightOperandNode(splice);
+ NumericLiteralNode spliceArg;
+ if (def.getBaseName().equals("insertAt")) {
+ //insertAt
+ spliceArg = new NumericLiteralNode("0");
+ //This works like 'insertAt' itself, pushing the insertee to 3rd position (correct position):
+ node.getArgumentsNode().addChild(spliceArg, 1);
+ } else {
+ //removeAt
+ spliceArg = new NumericLiteralNode("1");
+ node.getArgumentsNode().addChild(spliceArg, 1);
+ postCallAppend = "[0]";
+ }
+ } else {
+ //default Vector implementation
+ //unlike Array implementation of these methods, the synthetic Vector implementation supports these methods at runtime,
+ //and they behave differently with fixed length vectors compared to the native 'splice' method output which is used to
+ //support them in Array, however they are not protected from GCL renaming in release builds by any actual class definition,
+ //so we explicitly 'protect' them here by using DynamicAccess instead of MemberAccess
+ ExpressionNodeBase leftSide = (ExpressionNodeBase)(((BinaryOperatorNodeBase) (node.getNameNode())).getLeftOperandNode());
+ LiteralNode dynamicName = new LiteralNode(ILiteralNode.LiteralType.STRING, "'" + def.getBaseName() + "'");
+ dynamicName.setSourceLocation(((BinaryOperatorNodeBase) (node.getNameNode())).getRightOperandNode());
+ DynamicAccessNode replacement = new DynamicAccessNode(leftSide);
+ leftSide.setParent(replacement);
+ replacement.setSourceLocation(node.getNameNode());
+ replacement.setRightOperandNode(dynamicName);
+ dynamicName.setParent(replacement);
+
+ FunctionCallNode replacer = new FunctionCallNode(replacement) ;
+ replacement.setParent(replacer);
+ IExpressionNode[] args = node.getArgumentNodes();
+ for (IExpressionNode arg : args) {
+ replacer.getArgumentsNode().addItem((NodeBase) arg);
+ }
+ replacer.getArgumentsNode().setParent(replacer);
+ replacer.getArgumentsNode().setSourceLocation(node.getArgumentsNode());
+ replacer.setParent((NodeBase) node.getParent());
+ //swap it out
+ node = replacer;
+ }
+ }
else if (def instanceof AppliedVectorDefinition)
{
IExpressionNode[] argumentNodes = node.getArgumentNodes();
@@ -265,9 +459,54 @@
}
else
{
- IExpressionNode argumentNode = argumentNodes[0];
- getWalker().walk(argumentNode);
- write(".slice()");
+ String elementClassName = getEmitter().formatQualifiedName(((TypedExpressionNode)nameNode).getTypeNode().resolve(getProject()).getQualifiedName());
+ if (getProject() instanceof RoyaleJSProject
+ && ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass()!= null) {
+ String vectorEmulationClass = ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass();
+ if (vectorEmulationClass.equals("Array")) {
+ //just do a slice copy of the array which is the first argument
+ getWalker().walk(node.getArgumentsNode().getChild(0));
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("slice");
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ } else {
+ //assume the emulation class can handle an array or numeric value for first constructor arg...
+ writeToken(ASEmitterTokens.NEW);
+ startMapping(node.getNameNode());
+ write(vectorEmulationClass);
+ endMapping(node.getNameNode());
+ write(ASEmitterTokens.PAREN_OPEN);
+ getWalker().walk(node.getArgumentsNode().getChild(0));
+ writeToken(ASEmitterTokens.COMMA);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(elementClassName);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
+ } else {
+ //default Vector implementation
+ startMapping(node.getNameNode());
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(elementClassName);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.SQUARE_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write("coerce");
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ endMapping(node.getNameNode());
+
+ getEmitter().emitArguments(node.getArgumentsNode());
+ if (getProject() instanceof RoyaleJSProject)
+ ((RoyaleJSProject)getProject()).needLanguage = true;
+ getEmitter().getModel().needLanguage = true;
+ }
}
return;
}
@@ -277,6 +516,44 @@
getEmitter().emitArguments(node.getArgumentsNode());
return;
}
+ else if (def.getBaseName().equals(IASLanguageConstants.XMLList))
+ {
+ write("XMLList.conversion");
+ getEmitter().emitArguments(node.getArgumentsNode());
+ return;
+ }
+ else if (def.getQualifiedName().equals(IASLanguageConstants.Object)) {
+ //'resolveUncertain' always output here
+ //unless a) there are no arguments
+ //or b) it is *explicitly* suppressed for 'Object'
+ if (node.getArgumentNodes().length > 0) {
+ if (shouldResolveUncertain(nameNode, true)) {
+ wrapResolve = true;
+ ((RoyaleJSProject) getProject()).needLanguage = true;
+ getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.LANGUAGE_QNAME);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write("resolveUncertain");
+ write(ASEmitterTokens.PAREN_OPEN);
+ }
+ }
+ }
+ else if (nameNode.getNodeID() == ASTNodeID.NamespaceAccessExpressionID && def instanceof FunctionDefinition)
+ {
+ if (fjs.isCustomNamespace((FunctionDefinition)def))
+ {
+ write(ASEmitterTokens.THIS);
+ NamespaceIdentifierNode nin = (NamespaceIdentifierNode)nameNode.getChild(0);
+ NamespaceDefinition nsDef = (NamespaceDefinition)nin.resolve(getProject());
+ IdentifierNode idNode = (IdentifierNode)nameNode.getChild(1);
+ String propName = idNode.getName();
+ fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+ String s = nsDef.getURI();
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, propName, true));
+ getEmitter().emitArguments(node.getArgumentsNode());
+ return;
+ }
+ }
}
else if (nameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID && ((JSRoyaleEmitter)getEmitter()).isProxy(((MemberAccessExpressionNode)nameNode).getLeftOperandNode()) && def == null)
{
@@ -301,6 +578,14 @@
getWalker().walk(node.getNameNode());
getEmitter().emitArguments(node.getArgumentsNode());
+
+ if (postCallAppend != null) {
+ write(postCallAppend);
+ }
+ //end wrap resolve
+ if (wrapResolve) {
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
}
else //function-style cast
{
@@ -312,5 +597,31 @@
fjs.emitSuperCall(node, JSSessionModel.SUPER_FUNCTION_CALL);
}
}
+
+
+ private boolean shouldResolveUncertain(IExpressionNode nameNode, boolean forceExplicit) {
+ //default if not avoided globally
+ boolean should = ((RoyaleJSProject)getProject()).config.getJsResolveUncertain();
+ //just in case:
+ if (!(getProject() instanceof RoyaleJSProject)) return false;
+
+ IDocEmitter docEmitter = getEmitter().getDocEmitter();
+ if (docEmitter instanceof JSRoyaleDocEmitter)
+ {
+ JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter;
+ //look for local boolean toggle, unless forceExplicit is set
+ boolean suppress = !forceExplicit && royaleDocEmitter.getLocalSettingAsBoolean(
+ JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN, !should);
+ //if it is still on, look for sepcific/named 'off' setting based on name node
+ if (!suppress && nameNode !=null) {
+ //check to suppress for indvidual named node
+ if (nameNode instanceof IdentifierNode) {
+ suppress = royaleDocEmitter.getLocalSettingIncludesString(JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN, ((IdentifierNode) nameNode).getName());
+ }
+ }
+ should = !suppress;
+ }
+ return should;
+ }
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java
index 3874676..f6363ea 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java
@@ -19,9 +19,12 @@
package org.apache.royale.compiler.internal.codegen.js.jx;
+import org.apache.royale.abc.ABCConstants;
import org.apache.royale.abc.semantics.Namespace;
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.definitions.IConstantDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition.FunctionClassification;
@@ -34,17 +37,16 @@
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
-import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
-import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
-import org.apache.royale.compiler.internal.definitions.TypeDefinitionBase;
+import org.apache.royale.compiler.internal.definitions.*;
+import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
+import org.apache.royale.compiler.internal.tree.as.BinaryOperatorAssignmentNode;
+import org.apache.royale.compiler.internal.tree.as.BinaryOperatorDivisionAssignmentNode;
+import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
import org.apache.royale.compiler.internal.tree.as.NonResolvingIdentifierNode;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IFunctionNode;
-import org.apache.royale.compiler.tree.as.IFunctionObjectNode;
-import org.apache.royale.compiler.tree.as.IIdentifierNode;
-import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.utils.NativeUtils;
public class IdentifierEmitter extends JSSubEmitter implements
@@ -78,12 +80,43 @@
&& !identifierIsAccessorFunction;
boolean emitName = true;
JSRoyaleEmitter fjs = (JSRoyaleEmitter)getEmitter();
+ RoyaleJSProject project = (RoyaleJSProject)getWalker().getProject();
boolean isCustomNamespace = false;
boolean isStatic = nodeDef != null && nodeDef.isStatic();
if (nodeDef instanceof FunctionDefinition &&
fjs.isCustomNamespace((FunctionDefinition)nodeDef))
- isCustomNamespace = true;
+ isCustomNamespace = true;
+ if (isStatic
+ && nodeDef instanceof IConstantDefinition
+ && project != null && project.config != null
+ && project.config.getInlineConstants())
+ {
+ IConstantDefinition constDef = (IConstantDefinition) nodeDef;
+ Object initialValue = constDef.resolveInitialValue(project);
+ if (initialValue != null)
+ {
+ startMapping(parentNode);
+ if(initialValue instanceof String)
+ {
+ write("\"" + initialValue + "\"");
+ }
+ else if(initialValue == ABCConstants.UNDEFINED_VALUE)
+ {
+ write(IASLanguageConstants.UNDEFINED);
+ }
+ else if(initialValue == ABCConstants.NULL_VALUE)
+ {
+ write(IASLanguageConstants.NULL);
+ }
+ else
+ {
+ write(initialValue.toString());
+ }
+ endMapping(parentNode);
+ return;
+ }
+ }
if (isStatic)
{
String sname = nodeDef.getParent().getQualifiedName();
@@ -238,14 +271,14 @@
{
Namespace ns = (Namespace)((INamespaceResolvedReference)((FunctionDefinition)nodeDef).getNamespaceReference()).resolveAETNamespace(getProject());
INamespaceDefinition nsDef = ((FunctionDefinition)nodeDef).getNamespaceReference().resolveNamespaceReference(getProject());
- fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+ fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String nsName = ns.getName();
- write("[\"" + nsName + "::" + node.getName() + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(nsName, node.getName(), true));
}
else
{
String qname = node.getName();
- if (nodeDef != null && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ if (nodeDef != null && !isStatic && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
write(qname);
}
@@ -310,36 +343,47 @@
else if (isCustomNamespace)
{
String ns = ((INamespaceResolvedReference)((FunctionDefinition)nodeDef).getNamespaceReference()).resolveAETNamespace(getProject()).getName();
- write("[\"" + ns + "::" + qname + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(ns, qname, true));
}
else if (identifierIsAccessorFunction && isStatic)
{
- write("[\"" +node.getName() + "\"]");
+ write("[\"" +node.getName() + "\"]");
}
else
{
qname = node.getName();
- if (nodeDef != null && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ if (nodeDef != null && !isStatic && (nodeDef.getParent() instanceof ClassDefinition) && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
- write(qname);
+ write(qname);
}
}
else if (isPackageOrFileMember)
write(getEmitter().formatQualifiedName(qname));
else if (nodeDef instanceof TypeDefinitionBase)
- write(getEmitter().formatQualifiedName(qname));
+ {
+ if (NativeUtils.isSyntheticJSType(qname) && !(parentNode instanceof IFunctionCallNode)) {
+ getEmitter().getModel().needLanguage = true;
+ write(JSRoyaleEmitterTokens.SYNTH_TYPE);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(getEmitter().formatQualifiedName(qname));
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ }
+ else write(getEmitter().formatQualifiedName(qname));
+ }
else if (isCustomNamespace)
{
String ns = ((INamespaceResolvedReference)((FunctionDefinition)nodeDef).getNamespaceReference()).resolveAETNamespace(getProject()).getName();
- write("[\"" + ns + "::" + qname + "\"]");
+ write(JSRoyaleEmitter.formatNamespacedProperty(ns, qname, true));
}
else if (identifierIsAccessorFunction && isStatic)
{
- write("[\"" + qname + "\"]");
+ write("[\"" + qname + "\"]");
}
- else
+ else
{
- if (nodeDef != null && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
+ if (nodeDef != null && !isStatic && (nodeDef.getParent() instanceof ClassDefinition) && (!(nodeDef instanceof IParameterDefinition)) && nodeDef.isPrivate() && getProject().getAllowPrivateNameConflicts())
qname = getEmitter().formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
write(qname);
}
@@ -352,7 +396,7 @@
write("child('");
write(node.getName());
write("')");
- endMapping(node);
+ endMapping(node);
}
else
{
@@ -362,5 +406,7 @@
}
}
}
+
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IfEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IfEmitter.java
index 74ca31c..a5c987b 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IfEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IfEmitter.java
@@ -68,6 +68,13 @@
{
emitElse(elseNode);
}
+ // if no actual work is done in the if clause, and there are no else/elseif causes
+ // emit an empty block. Closure doesn't like a plain semicolon.
+ if (nodes.length == 0 && elseNode == null && conditional.getChild(1).getChildCount() == 0)
+ {
+ write(ASEmitterTokens.BLOCK_OPEN);
+ writeNewline(ASEmitterTokens.BLOCK_CLOSE);
+ }
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/InterfaceEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/InterfaceEmitter.java
index 0221afc..eb8f079 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/InterfaceEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/InterfaceEmitter.java
@@ -26,9 +26,11 @@
import org.apache.royale.compiler.internal.codegen.js.JSDocEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.tree.as.TypedExpressionNode;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IAccessorNode;
@@ -114,6 +116,14 @@
ITypeDefinition typeDef = typeNode.resolveType(project);
String packageName = typeDef.getPackageName();
packageName = project.getActualPackageName(packageName);
+ if (typeNode instanceof TypedExpressionNode) {
+ propType = "Vector.<" +
+ JSGoogDocEmitter.convertASTypeToJSType(
+ ((TypedExpressionNode)typeNode).getTypeNode().resolveType(project).getQualifiedName(),
+ "")
+ +">";
+ packageName = "";
+ }
write(JSDocEmitterTokens.JSDOC_OPEN);
write(ASEmitterTokens.SPACE);
fjs.getDocEmitter().emitType(propType, packageName);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralContainerEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralContainerEmitter.java
index 45fc4e8..c42c211 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralContainerEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralContainerEmitter.java
@@ -23,6 +23,8 @@
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.tree.as.LiteralNode;
+import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IContainerNode;
import org.apache.royale.compiler.tree.as.ILiteralContainerNode;
@@ -42,6 +44,7 @@
final IContainerNode.ContainerType type = cnode.getContainerType();
String preFix = null;
String postFix = null;
+ boolean isXMLList = node.getNodeID() == ASTNodeID.XMLListContentID;
if (type == IContainerNode.ContainerType.BRACES)
{
@@ -70,22 +73,50 @@
endMapping(node);
}
+ if (isXMLList)
+ {
+ write("new XMLList(\"");
+ }
final int len = cnode.getChildCount();
for (int i = 0; i < len; i++)
{
IASNode child = cnode.getChild(i);
- getWalker().walk(child);
- if (i < len - 1)
+ if (isXMLList)
{
- //we're mapping the comma to the literal container, but we fill
- //the space between the current child and the next because we
- //don't know exactly where the comma appears in ActionScript
- startMapping(node, child);
- writeToken(ASEmitterTokens.COMMA);
- endMapping(node);
+ if (child instanceof LiteralNode)
+ {
+ String value = ((LiteralNode)child).getValue(true);
+ value = value.replace("\"", "\\\"");
+ value = value.replace("\r", "");
+ value = value.replace("\n", "\\n");
+ // skip the wrapping empty nodes. XMLList
+ // is expecting illegal xml (a sequence of children nodes
+ // and will wrap it
+ // in containing nodes
+ if (value.contentEquals("<>"))
+ continue;
+ else if (value.contentEquals("</>"))
+ continue;
+ write(value);
+ }
+ }
+ else
+ {
+ getWalker().walk(child);
+ if (i < len - 1)
+ {
+ //we're mapping the comma to the literal container, but we fill
+ //the space between the current child and the next because we
+ //don't know exactly where the comma appears in ActionScript
+ startMapping(node, child);
+ writeToken(ASEmitterTokens.COMMA);
+ endMapping(node);
+ }
}
}
-
+ if (isXMLList)
+ write("\")");
+
if (postFix != null)
{
startMapping(node, node.getEndLine(), node.getEndColumn() - postFix.length());
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java
index 6c79341..939f498 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java
@@ -107,6 +107,7 @@
if (child instanceof LiteralNode)
{
s = ((LiteralNode)child).getValue(true);
+ s = s.replace("\n", "");
if (s.contains("'"))
sb.append("\"" + s + "\"");
else
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
index e74820c..d6e5ccb 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java
@@ -21,11 +21,16 @@
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.constants.IASKeywordConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.INamespaceConstants;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.INamespaceDefinition;
+import org.apache.royale.compiler.definitions.IPackageDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
@@ -33,19 +38,10 @@
import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
-import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
-import org.apache.royale.compiler.internal.tree.as.GetterNode;
-import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
-import org.apache.royale.compiler.internal.tree.as.NamespaceAccessExpressionNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.IIdentifierNode;
-import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
-import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.tree.as.IOperatorNode.OperatorType;
import org.apache.royale.compiler.utils.ASNodeUtils;
@@ -102,30 +98,69 @@
rightNode.getNodeID() != ASTNodeID.Op_AtID &&
!((rightNode.getNodeID() == ASTNodeID.ArrayIndexExpressionID) &&
(((DynamicAccessNode)rightNode).getLeftOperandNode().getNodeID() == ASTNodeID.Op_AtID));
- if (descendant || child)
- {
- writeLeftSide(node, leftNode, rightNode);
- if (descendant)
- write(".descendants('");
- if (child)
- write(".child('");
- String s = fjs.stringifyNode(rightNode);
- int dot = s.indexOf('.');
- if (dot != -1)
- {
- String name = s.substring(0, dot);
- String afterDot = s.substring(dot);
- write(name);
- write("')");
- write(afterDot);
- }
- else
- {
- write(s);
- write("')");
- }
- return;
- }
+ if (descendant || child) {
+ writeLeftSide(node, leftNode, rightNode);
+ if (descendant)
+ write(".descendants(");
+ if (child)
+ write(".child(");
+ String closeMethodCall = "')";
+ String s = "";
+ if (rightNode instanceof INamespaceAccessExpressionNode) {
+ NamespaceIdentifierNode namespaceIdentifierNode = (NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode();
+ IDefinition nsDef = namespaceIdentifierNode.resolve(getProject());
+ if (nsDef instanceof INamespaceDefinition
+ && ((INamespaceDefinition)nsDef).getNamespaceClassification().equals(INamespaceDefinition.NamespaceClassification.LANGUAGE)) {
+ //deal with built-ins
+ String name = ((NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode()).getName();
+ if (name.equals(INamespaceConstants.ANY)) {
+ //let the internal support within 'QName' class deal with it
+ write("new QName('*', '");
+ //only stringify the right node at the next step (it is the localName part)
+ rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode();
+ closeMethodCall = "'))";
+ } else if (name.equals(IASKeywordConstants.PUBLIC)
+ || name.equals(IASKeywordConstants.PROTECTED)) {
+ //@todo check this, but both public and protected appear to have the effect of skipping the namespace part in swf, so just use default namespace
+ write("/* as3 " + name + " */ '");
+ //skip the namespace to just output the name
+ rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode();
+ } else {
+ //this is an unlikely condition, but do something that should give same results as swf...
+ //private, internal namespaces used in an XML context (I don't think this makes sense)
+ //@todo check this, but it seems like it should never match anything in a valid XML query
+ write("new QName('");
+ //provide an 'unlikely' 'uri':
+ write("_as3Lang_" + fjs.stringifyNode(namespaceIdentifierNode));
+ write(s + "', '");
+ //only stringify the right node at the next step (it is the localName part)
+ rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode();
+ closeMethodCall = "'))";
+ }
+ } else {
+ write("new QName(");
+ s = fjs.stringifyNode(namespaceIdentifierNode);
+ write(s + ", '");
+ //only stringify the right node at the next step (it is the localName part)
+ rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode();
+ closeMethodCall = "'))";
+ }
+ } else write("'"); //normal string name for child
+
+ s = fjs.stringifyNode(rightNode);
+ int dot = s.indexOf('.');
+ if (dot != -1) {
+ String name = s.substring(0, dot);
+ String afterDot = s.substring(dot);
+ write(name);
+ write(closeMethodCall);
+ write(afterDot);
+ } else {
+ write(s);
+ write(closeMethodCall);
+ }
+ return;
+ }
}
else if (isProxy)
{
@@ -177,10 +212,18 @@
write(r.getName());
write(ASEmitterTokens.SINGLE_QUOTE);
write(ASEmitterTokens.PAREN_CLOSE);
+ write(".objectAccessFormat()");
write(ASEmitterTokens.SQUARE_CLOSE);
return;
}
}
+ else if(def.getParent() instanceof IPackageDefinition)
+ {
+ //this is a fully qualified name, and we should output it directly
+ //because we don't want it to be treated as dynamic access
+ write(fjs.formatQualifiedName(def.getQualifiedName()));
+ return;
+ }
else if (def.getParent() != null &&
def.getParent().getQualifiedName().equals("Array"))
{
@@ -199,6 +242,32 @@
}
else if (rightNode instanceof NamespaceAccessExpressionNode)
{
+ boolean isStatic = false;
+ if (def != null && def.isStatic())
+ isStatic = true;
+ boolean needClosure = false;
+ if (def instanceof FunctionDefinition && (!(def instanceof AccessorDefinition))
+ && !def.getBaseName().equals("constructor")) // don't wrap references to obj.constructor
+ {
+ IASNode parentNode = node.getParent();
+ if (parentNode != null)
+ {
+ ASTNodeID parentNodeId = parentNode.getNodeID();
+ // we need a closure if this MAE is the top-level in a chain
+ // of MAE and not in a function call.
+ needClosure = !isStatic && parentNodeId != ASTNodeID.FunctionCallID &&
+ parentNodeId != ASTNodeID.MemberAccessExpressionID &&
+ parentNodeId != ASTNodeID.ArrayIndexExpressionID;
+ }
+ }
+
+ if (needClosure
+ && getEmitter().getDocEmitter() instanceof JSRoyaleDocEmitter
+ && ((JSRoyaleDocEmitter)getEmitter().getDocEmitter()).getSuppressClosure())
+ needClosure = false;
+ if (needClosure)
+ getEmitter().emitClosureStart();
+
NamespaceAccessExpressionNode naen = (NamespaceAccessExpressionNode)rightNode;
IDefinition d = naen.getLeftOperandNode().resolve(getProject());
IdentifierNode r = (IdentifierNode)(naen.getRightOperandNode());
@@ -218,6 +287,7 @@
write(r.getName());
write(ASEmitterTokens.SINGLE_QUOTE);
write(ASEmitterTokens.PAREN_CLOSE);
+ write(".objectAccessFormat()");
write(ASEmitterTokens.SQUARE_CLOSE);
}
else
@@ -225,8 +295,19 @@
write(node.getOperator().getOperatorText());
write(r.getName());
}
+
+ if (needClosure)
+ {
+ write(ASEmitterTokens.COMMA);
+ write(ASEmitterTokens.SPACE);
+ if (leftNode.getNodeID() == ASTNodeID.SuperID)
+ write(ASEmitterTokens.THIS);
+ else
+ writeLeftSide(node, leftNode, rightNode);
+ getEmitter().emitClosureEnd(leftNode, def);
+ }
return;
- }
+ }
boolean isCustomNamespace = false;
if (def instanceof FunctionDefinition && node.getOperator() == OperatorType.MEMBER_ACCESS)
isCustomNamespace = fjs.isCustomNamespace((FunctionDefinition)def);
@@ -246,6 +327,11 @@
needClosure = !isStatic && parentNodeId != ASTNodeID.FunctionCallID &&
parentNodeId != ASTNodeID.MemberAccessExpressionID &&
parentNodeId != ASTNodeID.ArrayIndexExpressionID;
+
+ if (needClosure
+ && getEmitter().getDocEmitter() instanceof JSRoyaleDocEmitter
+ && ((JSRoyaleDocEmitter)getEmitter().getDocEmitter()).getSuppressClosure())
+ needClosure = false;
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java
index aad1184..0fc7b0b 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MethodEmitter.java
@@ -108,8 +108,12 @@
}
endMapping(node.getNameExpressionNode());
}
-
- startMapping(node);
+ if (node.getMetaTags() != null) {
+ //offset mapping by any metadata tags that will be in the first child node
+ startMapping(node.getChild(1));
+ } else {
+ startMapping(node);
+ }
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
write(ASEmitterTokens.FUNCTION);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageFooterEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageFooterEmitter.java
index 0048b91..86bc80d 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageFooterEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageFooterEmitter.java
@@ -37,12 +37,14 @@
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
+import org.apache.royale.compiler.internal.definitions.ClassDefinition;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.tree.as.SetterNode;
import org.apache.royale.compiler.problems.UnknownTypeProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.scopes.IASScope;
+import org.apache.royale.compiler.scopes.IDefinitionSet;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
@@ -74,13 +76,13 @@
JSRoyaleDocEmitter doc = (JSRoyaleDocEmitter) getEmitter()
.getDocEmitter();
- boolean isInterface = tnode instanceof IInterfaceNode;
-
- if (!getEmitter().getModel().isExterns)
+ if (!getEmitter().getModel().isExterns && doc.getEmitExports())
{
- /*
+ boolean isInterface = tnode instanceof IInterfaceNode;
+ boolean isDynamic = tnode instanceof IClassNode && tnode.hasModifier(ASModifier.DYNAMIC);
+ /*
* Metadata
- *
+ *
* @type {Object.<string, Array.<Object>>}
*/
writeNewline();
@@ -123,7 +125,19 @@
write(ASEmitterTokens.SINGLE_QUOTE);
if (isInterface) write(JSRoyaleEmitterTokens.ROYALE_CLASS_INFO_INTERFACE_KIND);
else write(JSRoyaleEmitterTokens.ROYALE_CLASS_INFO_CLASS_KIND);
- writeToken(ASEmitterTokens.SINGLE_QUOTE);
+ //writeToken(ASEmitterTokens.SINGLE_QUOTE);
+
+ if (isDynamic) {
+ //only add the 'isDynamic' tag when it is needed
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ writeToken(ASEmitterTokens.COMMA);
+ write(JSRoyaleEmitterTokens.ROYALE_CLASS_INFO_IS_DYNAMIC);
+ writeToken(ASEmitterTokens.COLON);
+ write(ASEmitterTokens.TRUE);
+ } else {
+ writeToken(ASEmitterTokens.SINGLE_QUOTE);
+ }
+
write(ASEmitterTokens.BLOCK_CLOSE);
write(ASEmitterTokens.SQUARE_CLOSE);
@@ -184,14 +198,18 @@
String typeName = getEmitter().formatQualifiedName(tnode.getQualifiedName());
- emitReflectionData(
- typeName,
+ emitReflectionData(
+ typeName,
reflectionKind,
- varData,
- accessorData,
- methodData,
- metadata);
-
+ varData,
+ accessorData,
+ methodData,
+ metadata);
+
+ if (!isInterface) {
+ emitReflectionRegisterInitialStaticFields(typeName, (ClassDefinition) tnode.getDefinition());
+ }
+
emitExportProperties(typeName, exportProperties, exportSymbols);
}
}
@@ -249,7 +267,7 @@
methodData = new ArrayList<MethodData>();
/*
* Reflection
- *
+ *
* @return {Object.<string, Function>}
*/
IDefinitionNode[] dnodes;
@@ -278,14 +296,14 @@
//todo consider outputting consts, none output for now
continue;
}
- if (ns == IASKeywordConstants.PUBLIC || isInterface)
+ if (isInterface || (ns != null && ns.equals(IASKeywordConstants.PUBLIC )))
{
name = varNode.getName();
IMetaTagsNode metaData = varNode.getMetaTags();
//first deal with 'Bindable' upgrades to getters/setters
if (!isInterface && bindableVars.containsKey(name)
- && bindableVars.get(name).namespace == IASKeywordConstants.PUBLIC) {
+ && bindableVars.get(name).namespace.equals(IASKeywordConstants.PUBLIC)) {
AccessorData bindableAccessor = new AccessorData();
bindableAccessor.name = name;
@@ -347,7 +365,7 @@
staticEventDispatcher.isStatic = true;
accessorData.add(staticEventDispatcher);
}
-
+
HashMap<String, AccessorData> instanceAccessorMap = new HashMap<String, AccessorData>();
HashMap<String, AccessorData> staticAccessorMap = new HashMap<String, AccessorData>();
for (IDefinitionNode dnode : dnodes)
@@ -362,7 +380,8 @@
{
IFunctionNode fnNode = (IFunctionNode)dnode;
String ns = fnNode.getNamespace();
- if (ns == IASKeywordConstants.PUBLIC || isInterface)
+
+ if (isInterface || (ns != null && ns.equals(IASKeywordConstants.PUBLIC)))
{
String accessorName = fnNode.getName();
AccessorData data = accessorMap.get(accessorName);
@@ -426,7 +445,7 @@
{
IFunctionNode fnNode = (IFunctionNode)dnode;
String ns = fnNode.getNamespace();
- if (ns == IASKeywordConstants.PUBLIC || isInterface)
+ if (isInterface || (ns != null && ns.equals(IASKeywordConstants.PUBLIC)))
{
MethodData data = new MethodData();
data.isStatic = isStatic;
@@ -519,6 +538,8 @@
}
private void emitReflectionDataEnd(String typeName) {
+ JSGoogConfiguration config = ((RoyaleJSProject)getWalker().getProject()).config;
+
writeNewline();
// close return object
write(ASEmitterTokens.BLOCK_CLOSE);
@@ -529,6 +550,28 @@
writeNewline();
write(ASEmitterTokens.BLOCK_CLOSE);
writeNewline(ASEmitterTokens.SEMICOLON);
+
+ if (config == null) return;
+ //add compiletime descriptor flags
+ //doc emitter-ish:
+ writeNewline("/**");
+ writeNewline(" * @export");
+ writeNewline(" * @const");
+ writeNewline(" * @type {number}");
+ writeNewline(" */");
+
+ //{typeName}.prototype.ROYALE_REFLECTION_INFO.compileFlags = {int value here};
+ write(typeName);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(JSEmitterTokens.PROTOTYPE);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(JSRoyaleEmitterTokens.ROYALE_REFLECTION_INFO);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ writeToken(JSRoyaleEmitterTokens.ROYALE_REFLECTION_INFO_COMPILE_TIME_FLAGS);
+ writeToken(ASEmitterTokens.EQUAL);
+ //
+ write(String.valueOf(config.getReflectionFlags()));
+ writeNewline(ASEmitterTokens.SEMICOLON);
}
public void emitReflectionData(
@@ -538,7 +581,6 @@
List<AccessorData> accessorData,
List<MethodData> methodData,
IMetaTagNode[] metaData
-
)
{
@@ -586,13 +628,48 @@
write(ASEmitterTokens.SINGLE_QUOTE);
write(var.type);
write(ASEmitterTokens.SINGLE_QUOTE);
- // if (var.isStatic) {
- // writeIsStatic();
- // }
+
+ //provide a get_set function that works in release build with public vars
+ writeToken(ASEmitterTokens.COMMA);
+ write(JSRoyaleEmitterTokens.ROYALE_REFLECTION_INFO_GET_SET);
+ writeToken(ASEmitterTokens.COLON);
+ writeToken(ASEmitterTokens.FUNCTION);
+ boolean valueIsUntyped = var.type.equals("*");
+ if (valueIsUntyped) {
+ //give the function a local name because a self-reference argument will be used to signify that
+ //it is not being used as a setter (because 'undefined' is a valid possible value to set)
+ write("f");
+ }
+ write(ASEmitterTokens.PAREN_OPEN);
+
+ if (!var.isStatic) {
+ //instance type parameter
+ writeToken("/** " + typeName + " */");
+ write("inst");
+ writeToken(ASEmitterTokens.COMMA);
+ }
+ //any type for value
+ write("/** * */ v");
+ writeToken(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.BLOCK_OPEN);
+ String getterSetter;
+ String field = var.isStatic ? typeName + "." + var.name : "inst." + var.name;
+ if (valueIsUntyped) {
+ //to avoid setting when type is '*' set the 'value' param to the function being called, which
+ //causes a 'getter only' result
+ //In the case of no parameter or literal undefined being passed, it will be treated as the value
+ //of undefined to be assigned to the variable field
+ getterSetter = "return v !== f ? "+ field + " = v : " + field + ";";
+ } else {
+ getterSetter = "return v !== undefined ? " + field + " = v : " + field + ";";
+ }
+ write(getterSetter);
+ write(ASEmitterTokens.BLOCK_CLOSE);
+
IMetaTagNode[] tags = var.metaData;
if (tags != null) {
- writeToken(ASEmitterTokens.COMMA);
- writeMetaData(tags);
+ //writeToken(ASEmitterTokens.COMMA);
+ writeMetaData(tags, true, false);
}
// close object
write(ASEmitterTokens.BLOCK_CLOSE);
@@ -651,9 +728,6 @@
write(ASEmitterTokens.SINGLE_QUOTE);
write(accessor.type);
write(ASEmitterTokens.SINGLE_QUOTE);
- // if (accessor.isStatic) {
- // writeIsStatic();
- // }
writeToken(ASEmitterTokens.COMMA);
write("access");
writeToken(ASEmitterTokens.COLON);
@@ -669,8 +743,8 @@
IMetaTagNode[] tags = accessor.metaData;
if (tags != null)
{
- writeToken(ASEmitterTokens.COMMA);
- writeMetaData(tags);
+ //writeToken(ASEmitterTokens.COMMA);
+ writeMetaData(tags, true, false);
}
// close object
write(ASEmitterTokens.BLOCK_CLOSE);
@@ -728,9 +802,6 @@
write(ASEmitterTokens.SINGLE_QUOTE);
write(method.type);
write(ASEmitterTokens.SINGLE_QUOTE);
- // if (method.isStatic) {
- // writeIsStatic();
- // }
writeToken(ASEmitterTokens.COMMA);
write("declaredBy");
writeToken(ASEmitterTokens.COLON);
@@ -747,8 +818,8 @@
IMetaTagNode[] metas = method.metaData;
if (metas != null)
{
- writeToken(ASEmitterTokens.COMMA);
- writeMetaData(metas);
+ //writeToken(ASEmitterTokens.COMMA);
+ writeMetaData(metas, true, false);
}
// close object
@@ -764,18 +835,15 @@
// close method function
write(ASEmitterTokens.BLOCK_CLOSE);
}
-
-
-
+
if (metaData != null && metaData.length > 0)
{
- write(ASEmitterTokens.COMMA);
- writeNewline();
- writeMetaData(metaData);
- }
+ //write(ASEmitterTokens.COMMA);
+ //writeNewline();
+ writeMetaData(metaData, true, true);
+ }
indentPop();
-
emitReflectionDataEnd(typeName);
}
@@ -798,13 +866,7 @@
writeToken(ASEmitterTokens.SQUARE_CLOSE);
}
*/
-
- /*private void writeIsStatic() {
- writeToken(ASEmitterTokens.COMMA);
- write("isStatic");
- writeToken(ASEmitterTokens.COLON);
- writeToken(ASEmitterTokens.TRUE);
- }*/
+
private void writeEmptyContent(Boolean appendComma, Boolean includeNewline) {
//return {};
@@ -830,7 +892,6 @@
// return [ array of parameter definitions ]
writeToken(ASEmitterTokens.RETURN);
writeToken(ASEmitterTokens.SQUARE_OPEN);
- write(ASEmitterTokens.SPACE);
int len = params.length;
for (int i = 0; i < len ; i++) {
@@ -872,96 +933,116 @@
// close function
write(ASEmitterTokens.BLOCK_CLOSE);
}
-
- private void writeMetaData(IMetaTagNode[] tags)
- {
- JSGoogConfiguration config = ((RoyaleJSProject)getWalker().getProject()).config;
- Set<String> allowedNames = config.getCompilerKeepAs3Metadata();
-
- // metadata: function() {
- write("metadata");
- writeToken(ASEmitterTokens.COLON);
- writeToken(ASEmitterTokens.FUNCTION);
- write(ASEmitterTokens.PAREN_OPEN);
- writeToken(ASEmitterTokens.PAREN_CLOSE);
- writeToken(ASEmitterTokens.BLOCK_OPEN);
- // return [ array of metadata tags ]
- writeToken(ASEmitterTokens.RETURN);
- writeToken(ASEmitterTokens.SQUARE_OPEN);
-
+
+ private ArrayList<IMetaTagNode> getAllowedMetadata(IMetaTagNode[] tags) {
+ JSGoogConfiguration config = ((RoyaleJSProject)getWalker().getProject()).config;
+ Set<String> allowedNames = config.getCompilerKeepAs3Metadata();
+
ArrayList<IMetaTagNode> filteredTags = new ArrayList<IMetaTagNode>(tags.length);
for (IMetaTagNode tag : tags)
{
if (allowedNames.contains(tag.getTagName())) filteredTags.add(tag);
-
}
-
- int count = 0;
+ return filteredTags;
+ }
+
+ private void writeAllowedMetadata(ArrayList<IMetaTagNode> filteredTags ) {
+ int count = 0;
int len = filteredTags.size();
- for (IMetaTagNode tag : filteredTags)
- {
-
-
- count++;
- // { name: <tag name>
- writeToken(ASEmitterTokens.BLOCK_OPEN);
- write("name");
- writeToken(ASEmitterTokens.COLON);
- write(ASEmitterTokens.SINGLE_QUOTE);
- write(tag.getTagName());
- write(ASEmitterTokens.SINGLE_QUOTE);
- IMetaTagAttribute[] args = tag.getAllAttributes();
- if (args.length > 0)
- {
- writeToken(ASEmitterTokens.COMMA);
-
- // args: [
- write("args");
- writeToken(ASEmitterTokens.COLON);
- writeToken(ASEmitterTokens.SQUARE_OPEN);
-
- for (int j = 0; j < args.length; j++)
- {
- if (j > 0)
- {
- writeToken(ASEmitterTokens.COMMA);
- }
- // { key: key, value: value }
- IMetaTagAttribute arg = args[j];
- writeToken(ASEmitterTokens.BLOCK_OPEN);
- write("key");
- writeToken(ASEmitterTokens.COLON);
- write(ASEmitterTokens.SINGLE_QUOTE);
- String key = arg.getKey();
- write(key == null ? "" : key);
- write(ASEmitterTokens.SINGLE_QUOTE);
- writeToken(ASEmitterTokens.COMMA);
- write("value");
- writeToken(ASEmitterTokens.COLON);
- write(ASEmitterTokens.SINGLE_QUOTE);
- write(formatJSStringValue(arg.getValue()));
- write(ASEmitterTokens.SINGLE_QUOTE);
+
+ // metadata: function() {
+ write("metadata");
+ writeToken(ASEmitterTokens.COLON);
+ writeToken(ASEmitterTokens.FUNCTION);
+ write(ASEmitterTokens.PAREN_OPEN);
+ writeToken(ASEmitterTokens.PAREN_CLOSE);
+ writeToken(ASEmitterTokens.BLOCK_OPEN);
+ // return [ array of metadata tags ]
+ writeToken(ASEmitterTokens.RETURN);
+ writeToken(ASEmitterTokens.SQUARE_OPEN);
+
+ for (IMetaTagNode tag : filteredTags)
+ {
+ count++;
+ // { name: <tag name>
+ writeToken(ASEmitterTokens.BLOCK_OPEN);
+ write("name");
+ writeToken(ASEmitterTokens.COLON);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(tag.getTagName());
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ IMetaTagAttribute[] args = tag.getAllAttributes();
+ if (args.length > 0)
+ {
+ writeToken(ASEmitterTokens.COMMA);
+
+ // args: [
+ write("args");
+ writeToken(ASEmitterTokens.COLON);
+ writeToken(ASEmitterTokens.SQUARE_OPEN);
+
+ for (int j = 0; j < args.length; j++)
+ {
+ if (j > 0)
+ {
+ writeToken(ASEmitterTokens.COMMA);
+ }
+ // { key: key, value: value }
+ IMetaTagAttribute arg = args[j];
+ writeToken(ASEmitterTokens.BLOCK_OPEN);
+ write("key");
+ writeToken(ASEmitterTokens.COLON);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ String key = arg.getKey();
+ write(key == null ? "" : key);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ writeToken(ASEmitterTokens.COMMA);
+ write("value");
+ writeToken(ASEmitterTokens.COLON);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(formatJSStringValue(arg.getValue()));
+ write(ASEmitterTokens.SINGLE_QUOTE);
write(ASEmitterTokens.SPACE);
- write(ASEmitterTokens.BLOCK_CLOSE);
- }
- // close array of args
+ write(ASEmitterTokens.BLOCK_CLOSE);
+ }
+ // close array of args
write(ASEmitterTokens.SPACE);
- write(ASEmitterTokens.SQUARE_CLOSE);
- }
- // close metadata object
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ }
+ // close metadata object
write(ASEmitterTokens.SPACE);
- write(ASEmitterTokens.BLOCK_CLOSE);
+ write(ASEmitterTokens.BLOCK_CLOSE);
if (count > 0 && count < len)
{
writeToken(ASEmitterTokens.COMMA);
}
- }
- // close array of metadatas
+ }
+ // close array of metadatas
write(ASEmitterTokens.SPACE);
- write(ASEmitterTokens.SQUARE_CLOSE);
- writeToken(ASEmitterTokens.SEMICOLON);
- // close function
- write(ASEmitterTokens.BLOCK_CLOSE);
+ write(ASEmitterTokens.SQUARE_CLOSE);
+ writeToken(ASEmitterTokens.SEMICOLON);
+ // close function
+ write(ASEmitterTokens.BLOCK_CLOSE);
+ }
+
+ private void writeMetaData(IMetaTagNode[] tags, boolean prefixComma, boolean prefixNewline)
+ {
+ ArrayList<IMetaTagNode> filteredTags = getAllowedMetadata(tags);
+ if (filteredTags.size() == 0) {
+ //nothing to write
+ return;
+ }
+ if (prefixNewline) {
+ if (prefixComma) {
+ write(ASEmitterTokens.COMMA);
+ }
+ writeNewline();
+ } else {
+ if (prefixComma) {
+ writeToken(ASEmitterTokens.COMMA);
+ }
+ }
+ writeAllowedMetadata(filteredTags);
}
private String formatJSStringValue(String value) {
@@ -969,6 +1050,52 @@
value = value.replace("'","\\'");
return value;
}
+
+ public void emitReflectionRegisterInitialStaticFields(String typeName, IClassDefinition classDef) {
+ //this is only output if the default initializers are enabled (otherwise runtime reflection results are not reliable)
+ //local config check here (instead of call site check) - in case this needs to change in the future:
+ JSGoogConfiguration config = ((RoyaleJSProject)getWalker().getProject()).config;
+ if (config == null || !config.getJsDefaultInitializers()) return;
+
+ boolean needsStaticsList = false;
+ Collection<IDefinitionSet> defs = classDef.getContainedScope().getAllLocalDefinitionSets();
+ for (IDefinitionSet set : defs) {
+ for (int i = 0, l = set.getSize(); i < l; ++i) {
+ IDefinition d = set.getDefinition(i);
+ if (d.isStatic()) {
+ needsStaticsList = true;
+ break;
+ }
+ }
+ if (needsStaticsList) break;
+ }
+ if (needsStaticsList) {
+ //support for reflection on static classes: supports ability to distinguish between initial fields and dynamic fields
+ //doc emitter-ish:
+ writeNewline("/**");
+ writeNewline(" * Provide reflection support for distinguishing dynamic fields on class object (static)");
+ writeNewline(" * @export");
+ writeNewline(" * @const");
+ writeNewline(" * @type {Array<string>}");
+ writeNewline(" */");
+
+ //{typeName}.prototype.ROYALE_REFLECTION_INFO.statics = Object.keys({typeName});
+ write(typeName);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(JSEmitterTokens.PROTOTYPE);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(JSRoyaleEmitterTokens.ROYALE_REFLECTION_INFO);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ writeToken(JSRoyaleEmitterTokens.ROYALE_REFLECTION_INFO_INITIAL_STATICS);
+ writeToken(ASEmitterTokens.EQUAL);
+ write("Object.keys");
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(typeName);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.SEMICOLON);
+ writeNewline();
+ }
+ }
public void emitExportProperties(String typeName, ArrayList<String> exportProperties, ArrayList<String> exportSymbols)
{
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java
index 2d7f52d..d5ef151 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/PackageHeaderEmitter.java
@@ -142,7 +142,7 @@
}
writeNewline("/**");
- writeNewline(" * Generated by Apache Royale Compiler from " + sourceName);
+ writeNewline(" * Generated by Apache Royale Compiler from " + sourceName.replace('\\', '/'));
writeNewline(" * " + qname);
writeNewline(" *");
writeNewline(" * @fileoverview");
@@ -380,9 +380,6 @@
if (imp.equals(cname))
continue;
-
- if (project.sourceExterns.contains(imp))
- continue;
if (NativeUtils.isNative(imp))
{
@@ -395,9 +392,13 @@
continue;
}
+ if(!project.isGoogProvided(imp))
+ {
+ continue;
+ }
+
if (writtenRequires.indexOf(imp) == -1)
{
-
/* goog.require('x');\n */
write(JSGoogEmitterTokens.GOOG_REQUIRE);
write(ASEmitterTokens.PAREN_OPEN);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ReturnEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ReturnEmitter.java
index a7f5d7e..0573110 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ReturnEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ReturnEmitter.java
@@ -21,10 +21,12 @@
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
+import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IReturnNode;
public class ReturnEmitter extends JSSubEmitter implements
@@ -51,7 +53,17 @@
if (hasReturnValue)
{
- getWalker().walk(rnode);
+ IDefinition returnDef = null;
+ IFunctionNode parentFn = (IFunctionNode) node.getAncestorOfType(IFunctionNode.class);
+ if (parentFn != null)
+ {
+ IExpressionNode returnTypeNode = parentFn.getReturnTypeNode();
+ if (returnTypeNode != null)
+ {
+ returnDef = returnTypeNode.resolve(getProject());
+ }
+ }
+ getEmitter().emitAssignmentCoercion(rnode, returnDef);
}
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SourceMapDirectiveEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SourceMapDirectiveEmitter.java
index 4109f1e..3dece8e 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SourceMapDirectiveEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SourceMapDirectiveEmitter.java
@@ -40,6 +40,8 @@
super(emitter);
}
+ public boolean isExterns = false;
+
@Override
public void emit(ITypeNode node)
{
@@ -56,7 +58,7 @@
}
}
- if (sourceMap)
+ if (sourceMap && !isExterns)
{
String name = node.getName() + EXTENSION_JS;
if (node instanceof IMXMLDocumentNode)
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SuperCallEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SuperCallEmitter.java
index 02f6972..285773b 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SuperCallEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/SuperCallEmitter.java
@@ -73,14 +73,24 @@
IClassNode cnode = (IClassNode) node
.getAncestorOfType(IClassNode.class);
- IExpressionNode fcNameNode = fcnode.getNameNode();
- // assume it is memberaccess of the form super.somefunction
- MemberAccessExpressionNode mae = null;
- if (fcNameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
- mae = (MemberAccessExpressionNode)fcNameNode;
- if (mae != null
- && (mae.getRightOperandNode().getNodeID() == ASTNodeID.GetterID || mae.getRightOperandNode()
- .getNodeID() == ASTNodeID.SetterID))
+ boolean isGetterSetter = false;
+ if (fcnode != null)
+ {
+ IExpressionNode fcNameNode = fcnode.getNameNode();
+ // assume it is memberaccess of the form super.somefunction
+ MemberAccessExpressionNode mae = null;
+ if (fcNameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
+ mae = (MemberAccessExpressionNode)fcNameNode;
+ if (mae != null
+ && (mae.getRightOperandNode().getNodeID() == ASTNodeID.GetterID || mae.getRightOperandNode()
+ .getNodeID() == ASTNodeID.SetterID))
+ isGetterSetter = true;
+ }
+ else if (fnode != null && (fnode.getNodeID() == ASTNodeID.GetterID || fnode.getNodeID() == ASTNodeID.SetterID))
+ {
+ isGetterSetter = true;
+ }
+ if (isGetterSetter)
{
if (cnode == null && thisClass != null)
write(getEmitter().formatQualifiedName(
@@ -204,7 +214,6 @@
}
boolean usingApply = false;
- boolean isCustomNamespace = false;
if (fnode != null && !fnode.isConstructor())
{
write(ASEmitterTokens.MEMBER_ACCESS);
@@ -226,21 +235,12 @@
if (nsDef.getContainingScope() != null) // was null for flash_proxy in unit test
fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names
String s = nsDef.getURI();
- superName = s + "::" + superName;
- isCustomNamespace = true;
- }
- if (isCustomNamespace)
- {
- write(ASEmitterTokens.SQUARE_OPEN);
- write(ASEmitterTokens.SINGLE_QUOTE);
+ write(JSRoyaleEmitter.formatNamespacedProperty(s, superName, true));
}
else
- write(ASEmitterTokens.MEMBER_ACCESS);
- write(superName);
- if (isCustomNamespace)
{
- write(ASEmitterTokens.SINGLE_QUOTE);
- write(ASEmitterTokens.SQUARE_CLOSE);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+ write(superName);
}
write(ASEmitterTokens.MEMBER_ACCESS);
write(JSEmitterTokens.APPLY);
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java
index b575d55..bc040e7 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/UnaryOperatorEmitter.java
@@ -23,8 +23,12 @@
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
+import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens;
+import org.apache.royale.compiler.internal.definitions.AppliedVectorDefinition;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.as.ILiteralNode;
import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
import org.apache.royale.compiler.utils.ASNodeUtils;
@@ -41,6 +45,31 @@
{
if (ASNodeUtils.hasParenOpen(node))
write(ASEmitterTokens.PAREN_OPEN);
+
+ Boolean isAssignment = (node.getNodeID() == ASTNodeID.Op_PreIncrID
+ || node.getNodeID() == ASTNodeID.Op_PreDecrID
+ || node.getNodeID() == ASTNodeID.Op_PostIncrID
+ || node.getNodeID() == ASTNodeID.Op_PostDecrID);
+
+ if (isAssignment && (node.getOperandNode() instanceof MemberAccessExpressionNode)
+ && (((MemberAccessExpressionNode)(node.getOperandNode())).getRightOperandNode() instanceof IdentifierNode)
+ && ((IdentifierNode)(((MemberAccessExpressionNode)(node.getOperandNode())).getRightOperandNode())).getName().equals("length")
+ && ((MemberAccessExpressionNode)(node.getOperandNode())).getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition
+ ) {
+ //support for output of alternate length setter, example: vectorInst.length++ as vectorInst['_synthType'].length++
+ //likewise for pre/post increment/decrement
+
+ String synthTagName = JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken() + ASEmitterTokens.MEMBER_ACCESS.getToken() + JSRoyaleEmitterTokens.ROYALE_SYNTH_TAG_FIELD_NAME.getToken();
+ LiteralNode synthType = new LiteralNode(ILiteralNode.LiteralType.STRING, synthTagName);
+ synthType.setSynthetic(true);
+ DynamicAccessNode patchedVectorReference = new DynamicAccessNode(((ExpressionNodeBase)((MemberAccessExpressionNode) node.getOperandNode()).getLeftOperandNode()));
+ ((ExpressionNodeBase)((MemberAccessExpressionNode) node.getOperandNode()).getLeftOperandNode()).setParent(patchedVectorReference);
+ patchedVectorReference.setRightOperandNode(synthType);
+ synthType.setParent(patchedVectorReference);
+ patchedVectorReference.setParent((NodeBase) node.getOperandNode());
+ patchedVectorReference.setSourceLocation(((MemberAccessExpressionNode) node.getOperandNode()).getLeftOperandNode());
+ ((MemberAccessExpressionNode) node.getOperandNode()).setLeftOperandNode(patchedVectorReference);
+ }
if (node.getNodeID() == ASTNodeID.Op_PreIncrID
|| node.getNodeID() == ASTNodeID.Op_PreDecrID
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java
index bead66f..70be284 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/VarDeclarationEmitter.java
@@ -22,26 +22,25 @@
import org.apache.royale.compiler.codegen.ISubEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.constants.IASKeywordConstants;
-import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.IDefinition;
-import org.apache.royale.compiler.definitions.metadata.IMetaTag;
-import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
+import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.tree.as.ChainedVariableNode;
-import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
-import org.apache.royale.compiler.internal.tree.as.FunctionCallNode;
-import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
-import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IEmbedNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
+/**
+ * Local variable in a function. For member and static variables of a class, see
+ * FieldEmitter instead.
+ */
public class VarDeclarationEmitter extends JSSubEmitter implements
ISubEmitter<IVariableNode>
{
@@ -59,15 +58,37 @@
getModel().getVars().add(node);
+ boolean defaultInitializers = false;
+ ICompilerProject project = getProject();
+ if(project instanceof RoyaleJSProject)
+ {
+ RoyaleJSProject fjsProject = (RoyaleJSProject) project;
+ if(fjsProject.config != null)
+ {
+ defaultInitializers = fjsProject.config.getJsDefaultInitializers();
+ }
+ }
+ boolean needsDefaultValue = EmitterUtils.needsDefaultValue(node, defaultInitializers, getProject());
+
+ IFunctionNode parentFnNode = (IFunctionNode) node.getAncestorOfType(IFunctionNode.class);
+ boolean isHoisting = fjs.isEmittingHoistedNodes(parentFnNode);
+
+ if (!(node instanceof ChainedVariableNode) && !isHoisting && needsDefaultValue)
+ {
+ write("//");
+ }
+
if (!(node instanceof ChainedVariableNode) && !node.isConst())
{
fjs.emitMemberKeyword(node);
}
IExpressionNode variableTypeNode = node.getVariableTypeNode();
+ IDefinition variableDef = null;
boolean hasVariableType = variableTypeNode.getLine() >= 0;
if(hasVariableType)
{
+ variableDef = variableTypeNode.resolve(getProject());
startMapping(variableTypeNode,
variableTypeNode.getLine(),
variableTypeNode.getColumn() - 1); //include the :
@@ -83,19 +104,19 @@
nameExpressionNode.getColumn() + nameExpressionNode.getAbsoluteEnd() - nameExpressionNode.getAbsoluteStart());
}
IExpressionNode avnode = node.getAssignedValueNode();
- IDefinition avdef = null;
+ IDefinition avtypedef = null;
if (avnode != null)
{
- avdef = avnode.resolveType(getWalker().getProject());
+ avtypedef = avnode.resolveType(getProject());
String opcode = avnode.getNodeID().getParaphrase();
if (opcode != "AnonymousFunction")
{
- fjs.getDocEmitter().emitVarDoc(node, avdef, getWalker().getProject());
+ fjs.getDocEmitter().emitVarDoc(node, avtypedef, getProject());
}
}
else
{
- fjs.getDocEmitter().emitVarDoc(node, null, getWalker().getProject());
+ fjs.getDocEmitter().emitVarDoc(node, null, getProject());
}
endMapping(variableTypeNode);
@@ -105,7 +126,12 @@
}
fjs.emitDeclarationName(node);
- if (avnode != null && !(avnode instanceof IEmbedNode))
+
+ if (avnode == null)
+ {
+ emitDefaultInitializer(node, defaultInitializers);
+ }
+ else if(!(avnode instanceof IEmbedNode))
{
if (hasVariableType)
{
@@ -118,141 +144,119 @@
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
endMapping(node);
- boolean varIsNumber = (variableTypeNode.getNodeID() == ASTNodeID.IdentifierID &&
- (((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants.Number) ||
- ((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants._int) ||
- ((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants.uint)));
- boolean valIsNumber = (avdef != null && (avdef.getQualifiedName().equals(IASLanguageConstants.Number) ||
- avdef.getQualifiedName().equals(IASLanguageConstants._int) ||
- avdef.getQualifiedName().equals(IASLanguageConstants.uint)));
- if (!valIsNumber && avdef == null && avnode.getNodeID() == ASTNodeID.MemberAccessExpressionID &&
- fjs.isDateProperty(avnode, false))
- valIsNumber = true;
- if (varIsNumber && !valIsNumber && (avdef == null || avdef.getQualifiedName().equals(IASLanguageConstants.ANY_TYPE)))
- {
- if (avnode.getNodeID() == ASTNodeID.FunctionCallID)
- {
- IExpressionNode fnNameNode = ((FunctionCallNode)avnode).getNameNode();
- if (fnNameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
- {
- MemberAccessExpressionNode mae = (MemberAccessExpressionNode)fnNameNode;
- IExpressionNode rightNode = mae.getRightOperandNode();
- valIsNumber = rightNode.getNodeID() == ASTNodeID.IdentifierID &&
- ((IdentifierNode)rightNode).getName().equals("length") &&
- fjs.isXMLList(mae);
- }
- }
- else if (avnode.getNodeID() == ASTNodeID.ArrayIndexExpressionID)
- {
- DynamicAccessNode dyn = (DynamicAccessNode)avnode;
- IDefinition leftDef = dyn.getLeftOperandNode().resolveType(getProject());
- IDefinition rightDef = dyn.getRightOperandNode().resolveType(getProject());
- // numeric indexing?
- if (rightDef.getQualifiedName().equals(IASLanguageConstants.Number))
- {
- IMetaTag[] metas = leftDef.getAllMetaTags();
- for (IMetaTag meta : metas)
- {
- if (meta.getTagName().equals("ArrayElementType"))
- {
- IMetaTagAttribute[] attrs = meta.getAllAttributes();
- for (IMetaTagAttribute attr : attrs)
- {
- String t = attr.getValue();
- if (t.equals(IASLanguageConstants.Number))
- valIsNumber = true;
- }
- }
- }
- }
- }
- }
- String coercion = "";
- if (varIsNumber && !valIsNumber)
- coercion = "Number(";
- if (variableTypeNode.getNodeID() == ASTNodeID.IdentifierID &&
- ((IdentifierNode)variableTypeNode).getName().equals(IASLanguageConstants.String) &&
- (avdef == null || (!avdef.getQualifiedName().equals(IASLanguageConstants.String) &&
- !avdef.getQualifiedName().equals(IASLanguageConstants.Null))))
- coercion = "org.apache.royale.utils.Language.string(";
- write(coercion);
- fjs.emitAssignedValue(avnode);
- if (coercion.length() > 0)
- write(")");
+ getEmitter().emitAssignmentCoercion(avnode, variableDef);
}
- if (avnode == null)
+
+ emitChainedVariables(node, defaultInitializers, isHoisting);
+ }
+
+ private void emitDefaultInitializer(IVariableNode node, boolean defaultInitializers)
+ {
+ IDefinition typedef = null;
+ IExpressionNode enode = node.getVariableTypeNode();
+ if (enode != null)
{
- IDefinition typedef = null;
- IExpressionNode enode = node.getVariableTypeNode();//getAssignedValueNode();
- if (enode != null)
- typedef = enode.resolveType(getWalker().getProject());
- if (typedef != null)
+ typedef = enode.resolveType(getProject());
+ }
+ if (typedef != null)
+ {
+ if (node.getParent() != null &&
+ node.getParent().getParent() != null &&
+ node.getParent().getParent().getNodeID() != ASTNodeID.Op_InID)
{
- boolean defaultInitializers = false;
- ICompilerProject project = getProject();
- if(project instanceof RoyaleJSProject)
+ String defName = typedef.getQualifiedName();
+ if (defName.equals("int") || defName.equals("uint"))
{
- RoyaleJSProject fjsProject = (RoyaleJSProject) project;
- if(fjsProject.config != null)
- {
- defaultInitializers = fjsProject.config.getJsDefaultInitializers();
- }
+ write(ASEmitterTokens.SPACE);
+ writeToken(ASEmitterTokens.EQUAL);
+ write("0");
}
- if (node.getParent() != null &&
- node.getParent().getParent() != null &&
- node.getParent().getParent().getNodeID() != ASTNodeID.Op_InID)
+ else if (defaultInitializers)
{
- String defName = typedef.getQualifiedName();
- if (defName.equals("int") || defName.equals("uint"))
+ if (defName.equals("Number"))
{
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
- write("0");
+ write(IASKeywordConstants.NA_N);
}
- else if (defaultInitializers)
+ else if (defName.equals("Boolean"))
{
- if (defName.equals("Number"))
- {
- write(ASEmitterTokens.SPACE);
- writeToken(ASEmitterTokens.EQUAL);
- write(IASKeywordConstants.NA_N);
- }
- else if (defName.equals("Boolean"))
- {
- write(ASEmitterTokens.SPACE);
- writeToken(ASEmitterTokens.EQUAL);
- write(IASKeywordConstants.FALSE);
- }
- else if (!defName.equals("*"))
- {
- //type * is meant to default to undefined, so it
- //doesn't need to be initialized, but everything
- //else should default to null
- write(ASEmitterTokens.SPACE);
- writeToken(ASEmitterTokens.EQUAL);
- write(IASKeywordConstants.NULL);
- }
+ write(ASEmitterTokens.SPACE);
+ writeToken(ASEmitterTokens.EQUAL);
+ write(IASKeywordConstants.FALSE);
}
- }
- }
- }
-
- if (!(node instanceof ChainedVariableNode))
- {
- // check for chained variables
- int len = node.getChildCount();
- for (int i = 0; i < len; i++)
- {
- IASNode child = node.getChild(i);
- if (child instanceof ChainedVariableNode)
- {
- startMapping(node, node.getChild(i - 1));
- writeToken(ASEmitterTokens.COMMA);
- endMapping(node);
- fjs.emitVarDeclaration((IVariableNode) child);
+ else if (!defName.equals("*"))
+ {
+ //type * is meant to default to undefined, so it
+ //doesn't need to be initialized, but everything
+ //else should default to null
+ write(ASEmitterTokens.SPACE);
+ writeToken(ASEmitterTokens.EQUAL);
+ write(IASKeywordConstants.NULL);
+ }
}
}
}
}
+ private void emitChainedVariables(IVariableNode node, boolean defaultInitializers, boolean isHoisting)
+ {
+ JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();
+ if (!(node instanceof ChainedVariableNode))
+ {
+ // check for chained variables
+ int len = node.getChildCount();
+ boolean splitVariables = false;
+ for (int i = 0; i < len; i++)
+ {
+ IASNode child = node.getChild(i);
+ if (child instanceof ChainedVariableNode)
+ {
+ ChainedVariableNode varChild = (ChainedVariableNode) child;
+ //if any of them need a default value, they all should be
+ //split onto different lines
+ if(EmitterUtils.needsDefaultValue(varChild, defaultInitializers, getProject()))
+ {
+ splitVariables = true;
+ break;
+ }
+ }
+ }
+
+ for (int i = 0; i < len; i++)
+ {
+ IASNode child = node.getChild(i);
+ if (child instanceof ChainedVariableNode)
+ {
+ if (splitVariables)
+ {
+ boolean childNeedsDefault = EmitterUtils.needsDefaultValue((IVariableNode) child, defaultInitializers, getProject());
+ if (isHoisting && !childNeedsDefault)
+ {
+ //this one does not need to be hoisted because it
+ //already has a default value
+ continue;
+ }
+ startMapping(node, node.getChild(i - 1));
+ write(ASEmitterTokens.SEMICOLON);
+ endMapping(node);
+ writeNewline();
+ if (!isHoisting && childNeedsDefault)
+ {
+ write("//");
+ }
+ writeToken(ASEmitterTokens.VAR);
+ }
+ else
+ {
+ startMapping(node, node.getChild(i - 1));
+ writeToken(ASEmitterTokens.COMMA);
+ endMapping(node);
+ }
+ fjs.emitVarDeclaration((IVariableNode) child);
+ }
+ }
+
+ }
+ }
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocDITAEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocDITAEmitter.java
index 266a0d6..c9a0863 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocDITAEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocDITAEmitter.java
@@ -20,6 +20,7 @@
package org.apache.royale.compiler.internal.codegen.js.royale;
import java.io.File;
+import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.FilterWriter;
import java.io.IOException;
@@ -1015,10 +1016,13 @@
public void outputIndex(File outputFolder, RoyaleASDocProject project) throws IOException
{
- final File indexFile = new File(outputFolder, "index.json");
- FileWriter out = new FileWriter(indexFile);
+ final File indexFile = new File(outputFolder, "index.json");
+ BufferedWriter out = new BufferedWriter(new FileWriter(indexFile));
out.write("{ \"index\": [");
- System.out.println("Compiling file: " + indexFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + indexFile);
+ }
Set<String> keys = project.index.keySet();
List<String> keyList = new ArrayList<String>(keys);
Collections.sort(keyList);
@@ -1084,10 +1088,13 @@
public void outputClasses(File outputFolder, RoyaleASDocProject project) throws IOException
{
- final File indexFile = new File(outputFolder, "classes.json");
- FileWriter out = new FileWriter(indexFile);
+ final File indexFile = new File(outputFolder, "classes.json");
+ BufferedWriter out = new BufferedWriter(new FileWriter(indexFile));
out.write("{ \"classes\": [");
- System.out.println("Compiling file: " + indexFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + indexFile);
+ }
Set<String> keys = project.classes.keySet();
List<String> keyList = new ArrayList<String>(keys);
Collections.sort(keyList);
@@ -1122,10 +1129,13 @@
public void outputTags(File outputFolder, RoyaleASDocProject project) throws IOException
{
- final File indexFile = new File(outputFolder, "tags.json");
- FileWriter out = new FileWriter(indexFile);
+ final File indexFile = new File(outputFolder, "tags.json");
+ BufferedWriter out = new BufferedWriter(new FileWriter(indexFile));
out.write("{ \"tags\": [");
- System.out.println("Compiling file: " + indexFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + indexFile);
+ }
Collections.sort(project.tags);
boolean firstLine = true;
for (String tag : project.tags)
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocEmitter.java
index d8a3d84..07c840a 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleASDocEmitter.java
@@ -19,6 +19,7 @@
package org.apache.royale.compiler.internal.codegen.js.royale;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.FilterWriter;
@@ -194,7 +195,7 @@
}
else if (pnode instanceof IClassNode)
{
- getWalker().walk(pnode);
+ //getWalker().walk(pnode); don't emit internal classes outside of a package
}
else if (pnode instanceof IInterfaceNode)
{
@@ -232,6 +233,9 @@
@Override
public void emitClass(IClassNode node)
{
+ if (!node.getDefinition().isPublic())
+ return;
+
ASDocComment asDoc = (ASDocComment) node.getASDocComment();
writeNewline("{ \"type\": \"class\",");
write(" \"qname\": \"");
@@ -619,7 +623,11 @@
List<String> tagList = project.tags;
asDoc.compile();
write(" \"description\": \"");
- write(asDoc.getDescription());
+ String d = asDoc.getDescription();
+ d = d.replace("\t", " ");
+ d = d.replace("\"", """);
+ d = d.replace("\\", "\\\\");
+ write(d);
write("\"");
Map<String, List<IASDocTag>> tags = asDoc.getTags();
if (tags != null)
@@ -653,7 +661,11 @@
if (!firstOne) write(", ");
firstOne = false;
write("\"");
- write(value.getDescription().trim());
+ d = value.getDescription().trim();
+ d = d.replace("\t", " ");
+ d = d.replace("\"", """);
+ d = d.replace("\\", "\\\\");
+ write(d);
write("\"");
}
}
@@ -724,19 +736,37 @@
writeNewline(",");
if (def.isDeprecated())
{
- writeNewline(",");
IDeprecationInfo dep = def.getDeprecationInfo();
writeNewline(" \"deprecated\": {");
indentPush();
- write(" \"message\": \"");
- write(dep.getMessage());
- writeNewline("\",");
- write(" \"replacement\": \"");
- write(dep.getReplacement());
- writeNewline("\",");
- write(" \"since\": \"");
- write(dep.getSince());
- writeNewline("\"}");
+ String comma = "";
+ String msg = dep.getMessage();
+ if (msg != null)
+ {
+ write(" \"message\": \"");
+ write(msg);
+ write("\"");
+ comma = ",";
+ }
+ String replace = dep.getReplacement();
+ if (replace != null)
+ {
+ writeNewline(comma);
+ write(" \"replacement\": \"");
+ write(replace);
+ write("\"");
+ comma = ",";
+ }
+ String since = dep.getSince();
+ if (since != null)
+ {
+ writeNewline("\",");
+ write(" \"since\": \"");
+ write(since);
+ write("\"");
+ comma = ",";
+ }
+ writeNewline("}");
}
else
{
@@ -813,10 +843,13 @@
public void outputIndex(File outputFolder, RoyaleASDocProject project) throws IOException
{
- final File indexFile = new File(outputFolder, "index" + getMiddle(project) + ".json");
- FileWriter out = new FileWriter(indexFile);
+ final File indexFile = new File(outputFolder, "index" + getMiddle(project) + ".json");
+ BufferedWriter out = new BufferedWriter(new FileWriter(indexFile));
out.write("{ \"index\": [");
- System.out.println("Compiling file: " + indexFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + indexFile);
+ }
Set<String> keys = project.index.keySet();
List<String> keyList = new ArrayList<String>(keys);
Collections.sort(keyList);
@@ -896,11 +929,10 @@
return false;
}
- private void writeCommentaryValues(FileWriter commentaryWriter, List<IASDocTag> values) throws IOException
+ private void writeCommentaryValues(BufferedWriter commentaryWriter, List<IASDocTag> values) throws IOException
{
HashMap<String, String> map = new HashMap<String, String>();
boolean firstOne = true;
- int count = 0;
for (IASDocTag value : values) {
String description = value.getDescription().trim();
if (map.containsKey(description)) {
@@ -914,11 +946,10 @@
commentaryWriter.write("\"");
map.put(description, "true");
- count++;
}
}
- public void writeCommentaryFile(FileWriter commentaryWriter, String qname, ASDocComment asDoc) throws IOException
+ public void writeCommentaryFile(BufferedWriter commentaryWriter, String qname, ASDocComment asDoc) throws IOException
{
//asDoc.compile();
Map<String, List<IASDocTag>> tags = asDoc.getTags();
@@ -1006,10 +1037,13 @@
public void outputClasses(File outputFolder, RoyaleASDocProject project) throws IOException
{
- final File indexFile = new File(outputFolder, "classes" + getMiddle(project) + ".json");
- FileWriter out = new FileWriter(indexFile);
- out.write("{ \"classes\": [");
- System.out.println("Compiling file: " + indexFile);
+ final File indexFile = new File(outputFolder, "classes" + getMiddle(project) + ".json");
+ BufferedWriter out = new BufferedWriter(new FileWriter(indexFile));
+ out.write("{ \"classes\": [");
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + indexFile);
+ }
Set<String> keys = project.classes.keySet();
List<String> keyList = new ArrayList<String>(keys);
Collections.sort(keyList);
@@ -1067,9 +1101,12 @@
}
final File listFile = new File(outputFolder, "classlist" + getMiddle(project) + ".json");
- out = new FileWriter(listFile);
+ out = new BufferedWriter(new FileWriter(listFile));
out.write("{ \"classnames\": [");
- System.out.println("Compiling file: " + listFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + listFile);
+ }
firstLine = true;
for (String key : keyList)
@@ -1077,7 +1114,6 @@
if (!firstLine)
out.write(",\n");
firstLine = false;
- RoyaleASDocProject.ASDocRecord record = project.classes.get(key);
out.write("\"");
out.write(key);
out.write("\"");
@@ -1099,9 +1135,12 @@
if (commentaryList.size() > 0) {
final File commentaryFile = new File(outputFolder, "commentary" + getMiddle(project) + ".json");
- FileWriter commentaryWriter = new FileWriter(commentaryFile);
+ BufferedWriter commentaryWriter = new BufferedWriter(new FileWriter(commentaryFile));
commentaryWriter.write("{ \"list\": [");
- System.out.println("Building commentary comparison file: "+commentaryFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Building commentary comparison file: "+commentaryFile);
+ }
firstLine = true;
int index = 0;
@@ -1132,10 +1171,13 @@
public void outputTags(File outputFolder, RoyaleASDocProject project) throws IOException
{
- final File indexFile = new File(outputFolder, "tags" + getMiddle(project) + ".json");
- FileWriter out = new FileWriter(indexFile);
+ final File indexFile = new File(outputFolder, "tags" + getMiddle(project) + ".json");
+ BufferedWriter out = new BufferedWriter(new FileWriter(indexFile));
out.write("{ \"tags\": [");
- System.out.println("Compiling file: " + indexFile);
+ if (project.config.isVerbose())
+ {
+ System.out.println("Compiling file: " + indexFile);
+ }
Collections.sort(project.tags);
boolean firstLine = true;
for (String tag : project.tags)
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java
index 71ecd89..0c32ad3 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleDocEmitter.java
@@ -19,10 +19,10 @@
package org.apache.royale.compiler.internal.codegen.js.royale;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.*;
import org.apache.royale.compiler.asdoc.royale.ASDocComment;
+import org.apache.royale.compiler.codegen.as.IASEmitter;
import org.apache.royale.compiler.codegen.js.IJSEmitter;
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.common.DependencyType;
@@ -37,20 +37,14 @@
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitter;
-import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogDocEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.jx.BindableEmitter;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.scopes.ASScope;
+import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.problems.PublicVarWarningProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.as.IASNode;
-import org.apache.royale.compiler.tree.as.IClassNode;
-import org.apache.royale.compiler.tree.as.IDefinitionNode;
-import org.apache.royale.compiler.tree.as.IExpressionNode;
-import org.apache.royale.compiler.tree.as.IFunctionNode;
-import org.apache.royale.compiler.tree.as.IParameterNode;
-import org.apache.royale.compiler.tree.as.IVariableNode;
+import org.apache.royale.compiler.tree.as.*;
import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
import org.apache.royale.compiler.tree.metadata.IMetaTagsNode;
@@ -59,8 +53,12 @@
private List<String> classIgnoreList;
private List<String> ignoreList;
private List<String> coercionList;
+ private Map<String,List<String>> localSettings;
public boolean emitStringConversions = true;
private boolean emitExports = true;
+ private boolean exportProtected = false;
+
+ private boolean suppressClosure = false;
public JSRoyaleDocEmitter(IJSEmitter emitter)
{
@@ -76,6 +74,14 @@
{
this.classIgnoreList = value;
}
+
+ public Boolean getSuppressClosure() {
+ return suppressClosure;
+ }
+
+ public Boolean getEmitExports() {
+ return emitExports;
+ }
@Override
protected String convertASTypeToJS(String name, String pname)
@@ -96,9 +102,19 @@
return IASLanguageConstants.Object;
}
if (name.matches("Vector\\.<.*>"))
- return IASLanguageConstants.Array;
+ {
+ RoyaleJSProject fjp = (RoyaleJSProject)((IASEmitter)emitter).getWalker().getProject();
+ String vectorClassName = fjp.config == null ? null : fjp.config.getJsVectorEmulationClass();
+ if (vectorClassName != null) return vectorClassName;
+ return super.convertASTypeToJS(name, pname);
+ }
name = super.convertASTypeToJS(name, pname);
+ if (name.equals(IASLanguageConstants.Boolean.toLowerCase())
+ || name.equals(IASLanguageConstants.String.toLowerCase())
+ || name.equals(IASLanguageConstants.Number.toLowerCase()))
+ return name;
+
return formatQualifiedName(name);
}
@@ -115,12 +131,21 @@
{
RoyaleJSProject fjp = (RoyaleJSProject)project;
boolean keepASDoc = fjp.config != null && fjp.config.getKeepASDoc();
+ boolean suppressExports = false;
+ if (emitter instanceof JSRoyaleEmitter) {
+ suppressExports = ((JSRoyaleEmitter) emitter).getModel().suppressExports;
+ }
if (fjp.config != null)
- emitExports = fjp.config.getExportPublicSymbols();
+ {
+ emitExports = !suppressExports && fjp.config.getExportPublicSymbols();
+ exportProtected = !suppressExports && fjp.config.getExportProtectedSymbols();
+ }
coercionList = null;
ignoreList = null;
+ localSettings = null;
emitStringConversions = true;
+ suppressClosure = false;
IClassDefinition classDefinition = resolveClassDefinition(node);
@@ -220,6 +245,31 @@
.getToken();
if (docText.contains(noStringToken))
emitStringConversions = false;
+
+ String noImplicitComplexCoercion = JSRoyaleEmitterTokens.SUPPRESS_COMPLEX_IMPLICIT_COERCION
+ .getToken();
+ if (docText.contains(noImplicitComplexCoercion))
+ loadLocalSettings(docText, noImplicitComplexCoercion, "true");
+
+ String noResolveUncertain = JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN
+ .getToken();
+ if (docText.contains(noResolveUncertain))
+ loadLocalSettings(docText,noResolveUncertain, "true");
+
+ String suppressVectorIndexCheck = JSRoyaleEmitterTokens.SUPPRESS_VECTOR_INDEX_CHECK
+ .getToken();
+ if (docText.contains(suppressVectorIndexCheck))
+ loadLocalSettings(docText,suppressVectorIndexCheck, "true");
+
+ String suppressClosureToken = JSRoyaleEmitterTokens.SUPPRESS_CLOSURE.getToken();
+
+ if (docText.contains(suppressClosureToken))
+ suppressClosure = true;
+
+ String suppressExport = JSRoyaleEmitterTokens.SUPPRESS_EXPORT.getToken();
+ if (docText.contains(suppressExport))
+ emitExports = false;
+
write(changeAnnotations(asDoc.commentNoEnd()));
}
else
@@ -304,6 +354,78 @@
end();
}
}
+
+ private void loadLocalSettings(String doc, String settingToken, String defaultSetting)
+ {
+ if (localSettings == null) localSettings = new HashMap<String, List<String>>();
+ int index = doc.indexOf(settingToken);
+ List<String> settings = localSettings.containsKey(settingToken) ? localSettings.get(settingToken) : null;
+ while (index != -1)
+ {
+ String setting = doc.substring(index + settingToken.length());
+ int endIndex = setting.indexOf("\n");
+ setting = setting.substring(0, endIndex);
+ setting = setting.trim();
+ if (settings == null) {
+ settings = new ArrayList<String>();
+ localSettings.put(settingToken, settings);
+ }
+ List<String> settingItems = null;
+ if (setting.length() >0) {
+ settingItems = Arrays.asList(setting.split("\\s*(,\\s*)+"));
+ } else {
+ settingItems = Arrays.asList(defaultSetting);
+ }
+ for (String settingItem: settingItems) {
+ if (settings.contains(settingItem)) {
+ //change the order to reflect the latest addition
+ settings.remove(settingItem);
+ }
+ settings.add(settingItem);
+ //System.out.println("---Adding setting "+settingToken+":"+settingItem);
+ }
+ index = doc.indexOf(settingToken, index + settingToken.length());
+ }
+ }
+
+ public boolean hasLocalSetting(String settingToken) {
+ if (localSettings == null) return false;
+ return (localSettings.keySet().contains(settingToken));
+ }
+
+ public boolean getLocalSettingAsBoolean(JSRoyaleEmitterTokens token, Boolean defaultValue) {
+ return getLocalSettingAsBoolean(token.getToken(), defaultValue);
+ }
+
+ public boolean getLocalSettingAsBoolean(String settingToken, Boolean defaultValue) {
+ boolean setting = defaultValue;
+ if (hasLocalSetting(settingToken)) {
+ for (String stringVal: localSettings.get(settingToken)) {
+ //don't bail out after finding a boolean-ish string val
+ //'last one wins'
+ if (stringVal.equals("false")) setting = false;
+ else if (stringVal.equals("true")) setting = true;
+ }
+ }
+ return setting;
+ }
+
+ public boolean getLocalSettingIncludesString(JSRoyaleEmitterTokens token, String searchValue) {
+ return getLocalSettingIncludesString(token.getToken(), searchValue);
+ }
+
+ public boolean getLocalSettingIncludesString(String settingToken, String searchValue) {
+ boolean hasValue = false;
+ if (hasLocalSetting(settingToken)) {
+ for (String stringVal: localSettings.get(settingToken)) {
+ if (stringVal.equals(searchValue)) {
+ hasValue = true;
+ break;
+ }
+ }
+ }
+ return hasValue;
+ }
private void loadIgnores(String doc)
{
@@ -405,7 +527,7 @@
{
emitProtected(node);
}
- else if (ns != null && ns == IASKeywordConstants.PUBLIC)
+ else /*if (ns != null && ns == IASKeywordConstants.PUBLIC)*/
{
emitPublic(node);
}
@@ -437,12 +559,35 @@
if (tag != null)
bindable = true;
}
- if (warnPublicVars && !node.isConst() && !bindable)
+ if (warnPublicVars && !node.isConst() && !bindable && ns.contentEquals("public"))
{
+ IASNode warningNode = node;
+ //find "public" child node, which may not be the start of the IVariableNode node because of associated metadata
+ int childCount = node.getChildCount();
+ int index = 0;
+ while (index < childCount) {
+ IASNode child = node.getChild(index);
+ if (child instanceof IIdentifierNode && ((IIdentifierNode) child).getName().equals("public")) {
+ warningNode = child;
+ break;
+ }
+ index++;
+ }
+
if (!suppressedWarning(node, fjp))
- fjp.getProblems().add(new PublicVarWarningProblem(node));
+ fjp.getProblems().add(new PublicVarWarningProblem(node.getSourcePath(),
+ node.getStart(), node.getEnd(),
+ warningNode.getLine(), warningNode.getColumn(),
+ node.getEndLine(), node.getEndColumn()));
+
+
}
- emitPublic(node);
+ if (!(node.getASDocComment() instanceof ASDocComment
+ && ((ASDocComment)node.getASDocComment()).commentNoEnd()
+ .contains(JSRoyaleEmitterTokens.SUPPRESS_EXPORT.getToken()))) {
+ emitPublic(node);
+ }
+
}
if (node.isConst())
@@ -452,12 +597,21 @@
if (def != null)
packageName = def.getPackageName();
- emitType(node, project.getActualPackageName(packageName));
+ emitType(node, project.getActualPackageName(packageName), project);
end();
}
@Override
+ public void emitProtected(IASNode node)
+ {
+ if (exportProtected)
+ super.emitPublic(node);
+ else
+ super.emitProtected(node);
+ }
+
+ @Override
public void emitPublic(IASNode node)
{
if (emitExports)
@@ -466,7 +620,6 @@
private boolean suppressedWarning(IVariableNode node, RoyaleJSProject fjp)
{
- boolean suppressed = false;
ASDocComment asDoc = (ASDocComment) node.getASDocComment();
boolean keepASDoc = fjp.config != null && fjp.config.getKeepASDoc();
String suppressToken = JSRoyaleEmitterTokens.SUPPRESS_PUBLIC_VAR_WARNING
@@ -492,6 +645,8 @@
IClassDefinition cdef = ((IClassNode)classNode).getDefinition();
if (cdef.isBindable())
return true;
+ if (!cdef.isPublic())
+ return true;
}
return false;
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java
index f258b16..d3a65ab 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java
@@ -23,7 +23,10 @@
import java.io.FilterWriter;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import org.apache.commons.io.FileUtils;
import org.apache.royale.compiler.codegen.js.royale.IJSRoyaleEmitter;
@@ -36,6 +39,7 @@
import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.IPackageDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
+import org.apache.royale.compiler.definitions.IVariableDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.definitions.references.INamespaceResolvedReference;
import org.apache.royale.compiler.embedding.EmbedAttribute;
@@ -75,8 +79,10 @@
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
+import org.apache.royale.compiler.internal.semantics.SemanticUtils;
import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.problems.EmbedUnableToReadSourceProblem;
+import org.apache.royale.compiler.problems.FilePrivateItemsWithMainVarWarningProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
@@ -152,6 +158,8 @@
public ArrayList<String> usedNames = new ArrayList<String>();
public ArrayList<String> staticUsedNames = new ArrayList<String>();
private boolean needNamespace;
+
+ private Set<IFunctionNode> emittingHoistedNodes = new HashSet<IFunctionNode>();
@Override
public String postProcess(String output)
@@ -173,14 +181,17 @@
String line = lines[i];
if (stillSearching)
{
- int c = line.indexOf(JSGoogEmitterTokens.GOOG_PROVIDE.getToken());
- if (c != -1)
+ if (provideIndex == -1 || !sawRequires)
{
- // if zero requires are found, require Language after the
- // call to goog.provide
- provideIndex = addIndex = i + 1;
+ int c = line.indexOf(JSGoogEmitterTokens.GOOG_PROVIDE.getToken());
+ if (c != -1)
+ {
+ // if zero requires are found, require Language after the
+ // call to goog.provide
+ provideIndex = addIndex = i + 1;
+ }
}
- c = line.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken());
+ int c = line.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken());
if (c != -1)
{
// we found other requires, so we'll just add Language at
@@ -401,17 +412,35 @@
@Override
public void emitLocalNamedFunction(IFunctionNode node)
{
- IFunctionNode fnNode = (IFunctionNode)node.getAncestorOfType(IFunctionNode.class);
- if (fnNode.getEmittingLocalFunctions())
+ IFunctionNode parentFnNode = (IFunctionNode) node.getAncestorOfType(IFunctionNode.class);
+ if (parentFnNode == null || isEmittingHoistedNodes(parentFnNode))
{
+ // emit named functions only when allowed
super.emitLocalNamedFunction(node);
- }
+ }
+ }
+
+ public Boolean isEmittingHoistedNodes(IFunctionNode node)
+ {
+ return emittingHoistedNodes.contains(node);
+ }
+
+ protected void setEmittingHoistedNodes(IFunctionNode node, boolean emit)
+ {
+ if (emit)
+ {
+ emittingHoistedNodes.add(node);
+ }
+ else
+ {
+ emittingHoistedNodes.remove(node);
+ }
}
@Override
public void emitFunctionBlockHeader(IFunctionNode node)
{
- node.setEmittingLocalFunctions(true);
+ setEmittingHoistedNodes(node, true);
super.emitFunctionBlockHeader(node);
if (node.isConstructor())
{
@@ -424,47 +453,133 @@
bindableEmitter.emitBindableExtendsConstructorCode(cnode.getDefinition().getQualifiedName(),false);
}
emitComplexInitializers(cnode);
-
}
- if (node.containsLocalFunctions())
+
+ emitHoistedFunctionsCodeBlock(node);
+
+ if (!getModel().isExterns)
+ emitHoistedVariablesCodeBlock(node);
+
+ setEmittingHoistedNodes(node, false);
+ }
+
+ protected void emitHoistedFunctionsCodeBlock(IFunctionNode node)
+ {
+ if (!node.containsLocalFunctions())
{
- List<IFunctionNode> anonFns = node.getLocalFunctions();
- int n = anonFns.size();
- for (int i = 0; i < n; i++)
+ return;
+ }
+ List<IFunctionNode> localFns = node.getLocalFunctions();
+ int n = localFns.size();
+ for (int i = 0; i < n; i++)
+ {
+ IFunctionNode localFn = localFns.get(i);
+ // named functions need to be declared at the top level to
+ // comply with JS strict mode.
+ // anonymous functions can be emitted inline, so we'll do that.
+ if (localFn.getName().length() > 0)
{
- IFunctionNode anonFn = anonFns.get(i);
- if (anonFn.getParent().getNodeID() == ASTNodeID.AnonymousFunctionID)
- {
- write("var /** @type {Function} */ __localFn" + Integer.toString(i) + "__ = ");
- getWalker().walk(anonFn.getParent());
- }
- else
- {
- getWalker().walk(anonFn);
- write(ASEmitterTokens.SEMICOLON);
- }
+ getWalker().walk(localFn);
+ write(ASEmitterTokens.SEMICOLON);
this.writeNewline();
}
}
- node.setEmittingLocalFunctions(false);
+ }
+
+ protected void emitHoistedVariablesCodeBlock(IFunctionNode node)
+ {
+ boolean defaultInitializers = false;
+ ICompilerProject project = getWalker().getProject();
+ if(project instanceof RoyaleJSProject)
+ {
+ RoyaleJSProject fjsProject = (RoyaleJSProject) project;
+ if(fjsProject.config != null)
+ {
+ defaultInitializers = fjsProject.config.getJsDefaultInitializers();
+ }
+ }
+ Collection<IDefinition> localDefs = node.getScopedNode().getScope().getAllLocalDefinitions();
+ for (IDefinition localDef : localDefs)
+ {
+ if (localDef instanceof IVariableDefinition)
+ {
+ IVariableDefinition varDef = (IVariableDefinition) localDef;
+ IVariableNode varNode = varDef.getVariableNode();
+ if (varNode == null)
+ {
+ //no associated node is possible for implicit variables,
+ //like "arguments"
+ continue;
+ }
+ if (varNode instanceof ChainedVariableNode)
+ {
+ //these will be handled from the first variable in the chain
+ continue;
+ }
+ if (EmitterUtils.needsDefaultValue(varNode, defaultInitializers, getWalker().getProject()))
+ {
+ emitVarDeclaration(varNode);
+ write(ASEmitterTokens.SEMICOLON);
+ writeNewline();
+ }
+ else
+ {
+ //when the first varible in a chain doesn't need a default
+ //value, we need to manually check the rest of the chain
+ int len = varNode.getChildCount();
+ for(int i = 0; i < len; i++)
+ {
+ IASNode child = varNode.getChild(i);
+ if(child instanceof ChainedVariableNode)
+ {
+ ChainedVariableNode childVarNode = (ChainedVariableNode) child;
+ if (EmitterUtils.needsDefaultValue(childVarNode, defaultInitializers, getWalker().getProject()))
+ {
+ writeToken(ASEmitterTokens.VAR);
+ emitVarDeclaration(childVarNode);
+ write(ASEmitterTokens.SEMICOLON);
+ writeNewline();
+ }
+ }
+ }
+ }
+ }
+ }
}
@Override
public void emitFunctionObject(IFunctionObjectNode node)
{
- IFunctionNode fnNode = (IFunctionNode)node.getAncestorOfType(IFunctionNode.class);
- if (fnNode == null || fnNode.getEmittingLocalFunctions())
+ IFunctionNode parentFnNode = (IFunctionNode) node.getAncestorOfType(IFunctionNode.class);
+ IFunctionNode localFnNode = node.getFunctionNode();
+ if (parentFnNode == null || isEmittingHoistedNodes(parentFnNode))
{
+ // emit named functions only when allowed
super.emitFunctionObject(node);
- }
+ }
+ else if(localFnNode.getName().length() == 0)
+ {
+ // anonymous functions are allowed to be inline
+ super.emitFunctionObject(node);
+ }
else
{
- List<IFunctionNode> anonFns = fnNode.getLocalFunctions();
- int i = anonFns.indexOf(node.getFunctionNode());
+ List<IFunctionNode> localFns = parentFnNode.getLocalFunctions();
+ int i = localFns.indexOf(node.getFunctionNode());
if (i < 0)
System.out.println("missing index for " + node.toString());
else
- write("__localFn" + Integer.toString(i) + "__");
+ {
+ IFunctionNode localFn = localFns.get(i);
+ IExpressionNode idNode = localFn.getNameExpressionNode();
+ String fnName = "";
+ if (idNode != null && idNode.getNodeID() == ASTNodeID.IdentifierID)
+ fnName = ((IdentifierNode)idNode).getName();
+ if (!fnName.isEmpty())
+ write(((IdentifierNode)idNode).getName());
+ else
+ write("__localFn" + Integer.toString(i) + "__");
+ }
}
}
@@ -478,7 +593,8 @@
writeToken(ASEmitterTokens.NEW);
write(IASLanguageConstants.Namespace);
write(ASEmitterTokens.PAREN_OPEN);
- staticUsedNames.add(IASLanguageConstants.Namespace);
+ if (!staticUsedNames.contains(IASLanguageConstants.Namespace))
+ staticUsedNames.add(IASLanguageConstants.Namespace);
IExpressionNode uriNode = node.getNamespaceURINode();
if (uriNode == null)
{
@@ -514,7 +630,7 @@
{
INamespaceDefinition nsDef = def.getNamespaceReference().resolveNamespaceReference(getWalker().getProject());
String uri = nsDef.getURI();
- if (!def.getNamespaceReference().isLanguageNamespace() && !uri.equals(INamespaceConstants.AS3URI) &&
+ if (!def.getNamespaceReference().isLanguageNamespace() && !uri.equals(INamespaceConstants.AS3URI) &&
!nsDef.getBaseName().equals(ASEmitterTokens.PRIVATE.getToken()))
return true;
return false;
@@ -524,27 +640,40 @@
public void emitMemberName(IDefinitionNode node)
{
ICompilerProject project = getWalker().getProject();
- if (node.getNodeID() == ASTNodeID.FunctionID)
- {
- FunctionNode fn = (FunctionNode)node;
- if (isCustomNamespace(fn))
- {
- INamespaceDecorationNode ns = ((FunctionNode)node).getActualNamespaceNode();
- INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
- formatQualifiedName(nsDef.getQualifiedName()); // register with used names
- String s = nsDef.getURI();
- write("[\"" + s + "::" + node.getName() + "\"]");
- return;
- }
- }
- String qname = node.getName();
- IDefinition nodeDef = node.getDefinition();
- if (nodeDef != null && nodeDef.isPrivate() && project.getAllowPrivateNameConflicts())
- qname = formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
+ if (node.getNodeID() == ASTNodeID.FunctionID)
+ {
+ FunctionNode fn = (FunctionNode)node;
+ if (isCustomNamespace(fn))
+ {
+ INamespaceDecorationNode ns = ((FunctionNode)node).getActualNamespaceNode();
+ INamespaceDefinition nsDef = (INamespaceDefinition)ns.resolve(project);
+ formatQualifiedName(nsDef.getQualifiedName()); // register with used names
+ String s = nsDef.getURI();
+ write(formatNamespacedProperty(s, node.getName(), true));
+ return;
+ }
+ }
+ String qname = node.getName();
+ IDefinition nodeDef = node.getDefinition();
+ if (nodeDef != null && !nodeDef.isStatic() && nodeDef.isPrivate() && project.getAllowPrivateNameConflicts())
+ qname = formatPrivateName(nodeDef.getParent().getQualifiedName(), qname);
write(qname);
}
- @Override
+ public static String formatNamespacedProperty(String s, String propName, boolean access) {
+ //closure compiler choked on this syntax so stop using bracket notation for now
+ //if (access) return "[\"" + s + "::" + propName + "\"]";
+ //return "\"" + s + "::" + propName + "\"";
+ s = s.replace(":", "_");
+ s = s.replace(".", "_");
+ s = s.replace("/", "$");
+ s += "__" + propName;
+ if (access)
+ s = ASEmitterTokens.MEMBER_ACCESS.getToken() + s;
+ return s;
+ }
+
+ @Override
public String formatQualifiedName(String name)
{
return formatQualifiedName(name, false);
@@ -569,10 +698,13 @@
else if (!isDoc)
{
if (getModel().inStaticInitializer)
- if (!staticUsedNames.contains(name) && !NativeUtils.isJSNative(name) && !isExternal(name))
+ if (!staticUsedNames.contains(name) && !NativeUtils.isJSNative(name)
+ && isGoogProvided(name) && !getModel().getCurrentClass().getQualifiedName().equals(name)
+ && (getModel().primaryDefinitionQName == null
+ || !getModel().primaryDefinitionQName.equals(name)))
staticUsedNames.add(name);
- if (!usedNames.contains(name) && !isExternal(name))
+ if (!usedNames.contains(name) && isGoogProvided(name))
usedNames.add(name);
}
return name;
@@ -589,88 +721,99 @@
else if (name.equals(IASLanguageConstants._int)
|| name.equals(IASLanguageConstants.uint))
result = IASLanguageConstants.Number;
-
- boolean isBuiltinFunction = name.matches("Vector\\.<.*>");
- if (isBuiltinFunction)
- {
- result = IASLanguageConstants.Array;
+ else if (name.equals(IASLanguageConstants.Vector) || name.equals("__AS3__.vec.Vector")) {
+ result = JSRoyaleEmitterTokens.VECTOR.getToken();
}
+
return result;
}
//--------------------------------------------------------------------------
// Package Level
//--------------------------------------------------------------------------
-
+
@Override
public void emitPackageHeader(IPackageDefinition definition)
{
- IPackageNode packageNode = definition.getNode();
- IFileNode fileNode = (IFileNode) packageNode.getAncestorOfType(IFileNode.class);
+ IPackageNode packageNode = definition.getNode();
+ IFileNode fileNode = (IFileNode) packageNode.getAncestorOfType(IFileNode.class);
int nodeCount = fileNode.getChildCount();
String mainClassName = null;
+ Boolean mainClassNameisVar = false;
+ IASNode firstInternalContent = null;
for (int i = 0; i < nodeCount; i++)
{
- IASNode pnode = fileNode.getChild(i);
-
- if (pnode instanceof IPackageNode)
- {
- IScopedNode snode = ((IPackageNode)pnode).getScopedNode();
- int snodeCount = snode.getChildCount();
- for (int j = 0; j < snodeCount; j++)
- {
- IASNode cnode = snode.getChild(j);
- if (cnode instanceof IClassNode)
- {
- mainClassName = ((IClassNode)cnode).getQualifiedName();
- break;
- }
- else if (j == 0)
- {
- if (cnode instanceof IFunctionNode)
- {
- mainClassName = ((IFunctionNode)cnode).getQualifiedName();
- }
- else if (cnode instanceof INamespaceNode)
- {
- mainClassName = ((INamespaceNode)cnode).getQualifiedName();
- }
- else if (cnode instanceof IVariableNode)
- {
- mainClassName = ((IVariableNode)cnode).getQualifiedName();
- }
-
- }
- }
- }
- else if (pnode instanceof IClassNode)
- {
- String className = ((IClassNode)pnode).getQualifiedName();
- getModel().getInternalClasses().put(className, mainClassName + "." + className);
- }
- else if (pnode instanceof IInterfaceNode)
- {
- String className = ((IInterfaceNode)pnode).getQualifiedName();
- getModel().getInternalClasses().put(className, mainClassName + "." + className);
- }
+ IASNode pnode = fileNode.getChild(i);
+
+ if (pnode instanceof IPackageNode)
+ {
+ IScopedNode snode = ((IPackageNode)pnode).getScopedNode();
+ int snodeCount = snode.getChildCount();
+ for (int j = 0; j < snodeCount; j++)
+ {
+ //there can only be one externally visible definition of either class, namespace, variable or function
+ //and package scope does not permit other class level access modifiers, otherwise a compiler error has already occurred.
+ //So mainClassName is derived from the first instance of any of these.
+ IASNode cnode = snode.getChild(j);
+ if (cnode instanceof IClassNode)
+ {
+ mainClassName = ((IClassNode)cnode).getQualifiedName();
+ break;
+ }
+ else if (cnode instanceof IFunctionNode)
+ {
+ mainClassName = ((IFunctionNode)cnode).getQualifiedName();
+ break;
+ }
+ else if (cnode instanceof INamespaceNode)
+ {
+ mainClassName = ((INamespaceNode)cnode).getQualifiedName();
+ break;
+ }
+ else if (cnode instanceof IVariableNode)
+ {
+ mainClassName = ((IVariableNode)cnode).getQualifiedName();
+ mainClassNameisVar = true;
+ break;
+ }
+ }
+ }
+ else if (pnode instanceof IClassNode)
+ {
+ String className = ((IClassNode)pnode).getQualifiedName();
+ getModel().getInternalClasses().put(className, mainClassName + "." + className);
+ if (firstInternalContent == null) firstInternalContent = pnode;
+ }
+ else if (pnode instanceof IInterfaceNode)
+ {
+ String className = ((IInterfaceNode)pnode).getQualifiedName();
+ getModel().getInternalClasses().put(className, mainClassName + "." + className);
+ if (firstInternalContent == null) firstInternalContent = pnode;
+ }
else if (pnode instanceof IFunctionNode)
{
String className = ((IFunctionNode)pnode).getQualifiedName();
getModel().getInternalClasses().put(className, mainClassName + "." + className);
+ if (firstInternalContent == null) firstInternalContent = pnode;
}
else if (pnode instanceof INamespaceNode)
{
String className = ((INamespaceNode)pnode).getQualifiedName();
getModel().getInternalClasses().put(className, mainClassName + "." + className);
+ if (firstInternalContent == null) firstInternalContent = pnode;
}
else if (pnode instanceof IVariableNode)
{
String className = ((IVariableNode)pnode).getQualifiedName();
getModel().getInternalClasses().put(className, mainClassName + "." + className);
+ if (firstInternalContent == null) firstInternalContent = pnode;
}
}
-
+ if (mainClassNameisVar && firstInternalContent != null) {
+ getProblems().add(new FilePrivateItemsWithMainVarWarningProblem(firstInternalContent));
+ }
packageHeaderEmitter.emit(definition);
+
}
@Override
@@ -958,7 +1101,8 @@
@Override
public void emitClosureStart()
{
- ICompilerProject project = getWalker().getProject();;
+ if (getDocEmitter() instanceof JSRoyaleDocEmitter && ((JSRoyaleDocEmitter) getDocEmitter()).getSuppressClosure()) return;
+ ICompilerProject project = getWalker().getProject();
if (project instanceof RoyaleJSProject)
((RoyaleJSProject)project).needLanguage = true;
getModel().needLanguage = true;
@@ -969,6 +1113,7 @@
@Override
public void emitClosureEnd(IASNode node, IDefinition nodeDef)
{
+ if (getDocEmitter() instanceof JSRoyaleDocEmitter && ((JSRoyaleDocEmitter) getDocEmitter()).getSuppressClosure()) return;
write(ASEmitterTokens.COMMA);
write(ASEmitterTokens.SPACE);
write(ASEmitterTokens.SINGLE_QUOTE);
@@ -980,7 +1125,7 @@
String ns = ((INamespaceResolvedReference)((FunctionDefinition)nodeDef).getNamespaceReference()).resolveAETNamespace(getWalker().getProject()).getName();
write(ns + "::");
}
- write(((IIdentifierNode)node).getName());
+ write(nodeDef.getBaseName());
}
else if (node.getNodeID() == ASTNodeID.MemberAccessExpressionID)
writeChainName(node);
@@ -993,11 +1138,17 @@
@Override
public void emitStatement(IASNode node)
{
- // don't emit named local functions as statements
- // they are emitted as part of the function block header
- if (node.getNodeID() == ASTNodeID.FunctionID)
+ if (node instanceof IFunctionNode)
{
- return;
+ IFunctionNode fnode = (IFunctionNode) node;
+ if(fnode.getName().length() > 0)
+ {
+ // don't emit named local functions as statements, if they have
+ // a name. these functions are emitted as part of the function
+ // block header because that is required by JS strict mode.
+ // anonymous functions (functions without a name) are allowed.
+ return;
+ }
}
super.emitStatement(node);
}
@@ -1112,10 +1263,10 @@
if (EmitterUtils.writeE4xFilterNode(getWalker().getProject(), getModel(), node))
write("node.");
write("attribute(");
- getWalker().walk(parentNode.getRightOperandNode());
+ getWalker().walk(parentNode.getRightOperandNode());
write(")");
}
-
+
return;
}
@@ -1147,7 +1298,7 @@
IDefinition rightDef = rightNode.resolveType(getWalker().getProject());
if (rightDef != null)
{
- if (IdentifierNode.isXMLish(rightDef, getWalker().getProject()))
+ if (SemanticUtils.isXMLish(rightDef, getWalker().getProject()))
{
return isLeftNodeXMLish(leftNode);
}
@@ -1167,9 +1318,9 @@
{
IDefinition leftDef = leftNode.resolveType(getWalker().getProject());
if (leftDef != null)
- return IdentifierNode.isXMLish(leftDef, getWalker().getProject());
+ return SemanticUtils.isXMLish(leftDef, getWalker().getProject());
}
- else if (leftID == ASTNodeID.MemberAccessExpressionID)
+ else if (leftID == ASTNodeID.MemberAccessExpressionID || leftID == ASTNodeID.Op_DescendantsID)
{
MemberAccessExpressionNode maen = (MemberAccessExpressionNode)leftNode;
IExpressionNode rightNode = maen.getRightOperandNode();
@@ -1179,7 +1330,7 @@
IDefinition rightDef = rightNode.resolveType(getWalker().getProject());
if (rightDef != null)
{
- return IdentifierNode.isXMLish(rightDef, getWalker().getProject());
+ return SemanticUtils.isXMLish(rightDef, getWalker().getProject());
}
}
leftNode = maen.getLeftOperandNode();
@@ -1204,7 +1355,7 @@
leftNode = (IExpressionNode)(leftNode.getChild(0));
IDefinition leftDef = leftNode.resolveType(getWalker().getProject());
if (leftDef != null)
- return IdentifierNode.isXMLish(leftDef, getWalker().getProject());
+ return SemanticUtils.isXMLish(leftDef, getWalker().getProject());
}
else if (leftID == ASTNodeID.E4XFilterID)
@@ -1301,7 +1452,14 @@
{
// See if the left side is XML or XMLList
IDefinition leftDef = obj.resolveType(getWalker().getProject());
- return IdentifierNode.isXMLish(leftDef, getWalker().getProject());
+ if (leftDef == null && obj.getNodeID() == ASTNodeID.MemberAccessExpressionID)
+ {
+ return isXML(((MemberAccessExpressionNode)obj).getLeftOperandNode());
+ }
+ else if (leftDef != null && leftDef.getBaseName().equals("*") && obj instanceof DynamicAccessNode) {
+ return isXML(((DynamicAccessNode)obj).getLeftOperandNode());
+ }
+ return SemanticUtils.isXMLish(leftDef, getWalker().getProject());
}
public MemberAccessExpressionNode getLastMAEInChain(MemberAccessExpressionNode node)
@@ -1326,21 +1484,50 @@
@Override
public void emitTypedExpression(ITypedExpressionNode node)
{
- write(JSRoyaleEmitterTokens.VECTOR);
+ ICompilerProject project = getWalker().getProject();
+ if (project instanceof RoyaleJSProject)
+ {
+ String vectorClassName = ((RoyaleJSProject)project).config == null ? null : ((RoyaleJSProject)project).config.getJsVectorEmulationClass();
+ if (vectorClassName != null)
+ {
+ if (!vectorClassName.equals("Array"))
+ write(vectorClassName);
+ return;
+ }
+ }
+ Boolean written = false;
+ if (node instanceof TypedExpressionNode) {
+ startMapping(node);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(JSRoyaleEmitterTokens.SYNTH_VECTOR);
+ write(ASEmitterTokens.PAREN_OPEN);
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ //the element type of the Vector:
+ write(formatQualifiedName(node.getTypeNode().resolve(project).getQualifiedName()));
+ write(ASEmitterTokens.SINGLE_QUOTE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ write(ASEmitterTokens.PAREN_CLOSE);
+ endMapping(node);
+ written = true;
+ }
+
+ if (!written) {
+ write(JSRoyaleEmitterTokens.VECTOR);
+ }
if (getModel().inStaticInitializer)
- staticUsedNames.add(JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken());
+ {
+ if (!staticUsedNames.contains(JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken()))
+ staticUsedNames.add(JSRoyaleEmitterTokens.LANGUAGE_QNAME.getToken());
+ }
if (project instanceof RoyaleJSProject)
((RoyaleJSProject)project).needLanguage = true;
getModel().needLanguage = true;
}
- boolean isExternal(String className)
+ boolean isGoogProvided(String className)
{
ICompilerProject project = getWalker().getProject();
- ICompilationUnit cu = project.resolveQNameToCompilationUnit(className);
- if (cu == null) return false; // unit testing
-
- return ((RoyaleJSProject)project).isExternalLinkage(cu);
+ return ((RoyaleJSProject)project).isGoogProvided(className);
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java
index 8155c0d..d0ad79f 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitterTokens.java
@@ -28,9 +28,14 @@
{
ROYALE_CLASS_INFO("ROYALE_CLASS_INFO"),
ROYALE_REFLECTION_INFO("ROYALE_REFLECTION_INFO"),
+ ROYALE_REFLECTION_INFO_GET_SET("get_set"),
+ ROYALE_REFLECTION_INFO_INITIAL_STATICS("statics"),
+ ROYALE_REFLECTION_INFO_COMPILE_TIME_FLAGS("compileFlags"),
ROYALE_CLASS_INFO_KIND("kind"),
ROYALE_CLASS_INFO_CLASS_KIND("class"),
ROYALE_CLASS_INFO_INTERFACE_KIND("interface"),
+ ROYALE_CLASS_INFO_IS_DYNAMIC("isDynamic"),
+ ROYALE_SYNTH_TAG_FIELD_NAME("SYNTH_TAG_FIELD"),
GOOG_EXPORT_PROPERTY("goog.exportProperty"),
GOOG_EXPORT_SYMBOL("goog.exportSymbol"),
INDENT(" "),
@@ -45,7 +50,12 @@
IGNORE_COERCION("@royaleignorecoercion"),
IGNORE_IMPORT("@royaleignoreimport"),
IGNORE_STRING_COERCION("@royalenoimplicitstringconversion"),
+ SUPPRESS_EXPORT("@royalesuppressexport"),
+ SUPPRESS_CLOSURE("@royalesuppressclosure"),
SUPPRESS_PUBLIC_VAR_WARNING("@royalesuppresspublicvarwarning"),
+ SUPPRESS_COMPLEX_IMPLICIT_COERCION("@royalesuppresscompleximplicitcoercion"),
+ SUPPRESS_RESOLVE_UNCERTAIN("@royalesuppressresolveuncertain"),
+ SUPPRESS_VECTOR_INDEX_CHECK("@royalesuppressvectorindexcheck"),
DEBUG_COMMENT("@royaledebug"),
DEBUG_RETURN("if(!goog.DEBUG)return;"),
PREINCREMENT("preincrement"),
@@ -61,7 +71,10 @@
SKIP_AS_COERCIONS("skipAsCoercions"),
SKIP_FUNCTION_COERCIONS("skipFunctionCoercions"),
JSX("JSX"),
- VECTOR("org.apache.royale.utils.Language.Vector"),
+ VECTOR(LANGUAGE_QNAME.getToken() + ".Vector"),
+ SYNTH_TYPE(LANGUAGE_QNAME.getToken() + ".synthType"),
+ SYNTH_VECTOR(LANGUAGE_QNAME.getToken() + ".synthVector"),
+ VECTOR_INDEX_CHECK_METHOD_NAME(LANGUAGE_QNAME.getToken() + ".CHECK_INDEX"),
;
private String token;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/DocEmitterUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/DocEmitterUtils.java
index dd9ed44..a188e76 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/DocEmitterUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/DocEmitterUtils.java
@@ -20,6 +20,7 @@
package org.apache.royale.compiler.internal.codegen.js.utils;
import java.util.ArrayList;
+import java.util.List;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter;
@@ -27,7 +28,7 @@
public class DocEmitterUtils
{
- public static void loadImportIgnores(JSRoyaleEmitter emitter, String doc)
+ public static List<String> loadImportIgnores(JSRoyaleEmitter emitter, String doc)
{
ArrayList<String> ignoreList = new ArrayList<String>();
String ignoreToken = JSRoyaleEmitterTokens.IGNORE_IMPORT.getToken();
@@ -39,11 +40,20 @@
ignorable = ignorable.substring(0, endIndex);
ignorable = ignorable.trim();
ignoreList.add(ignorable);
- System.out.println("Found ignorable: " + ignorable);
index = doc.indexOf(ignoreToken, index + endIndex);
}
// TODO (mschmalle)
((JSRoyaleDocEmitter)emitter.getDocEmitter()).setClassIgnoreList(ignoreList);
+ return ignoreList;
+ }
+
+
+ public static Boolean hasSuppressExport(JSRoyaleEmitter emitter, String doc)
+ {
+
+ String ignoreToken = JSRoyaleEmitterTokens.SUPPRESS_EXPORT.getToken();
+ int index = doc.indexOf(ignoreToken);
+ return index != -1;
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java
index 9013dee..eeec0c2 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/utils/EmitterUtils.java
@@ -22,18 +22,15 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition.FunctionClassification;
-import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.IVariableDefinition;
import org.apache.royale.compiler.internal.codegen.js.JSSessionModel;
@@ -44,14 +41,13 @@
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition.INamepaceDeclarationDirective;
import org.apache.royale.compiler.internal.definitions.ParameterDefinition;
import org.apache.royale.compiler.internal.definitions.VariableDefinition;
-import org.apache.royale.compiler.internal.projects.CompilerProject;
-import org.apache.royale.compiler.internal.scopes.TypeScope;
import org.apache.royale.compiler.internal.tree.as.ContainerNode;
import org.apache.royale.compiler.internal.tree.as.NodeBase;
import org.apache.royale.compiler.internal.tree.as.ParameterNode;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
+import org.apache.royale.compiler.tree.as.IAccessorNode;
import org.apache.royale.compiler.tree.as.IClassNode;
import org.apache.royale.compiler.tree.as.IContainerNode;
import org.apache.royale.compiler.tree.as.IDefinitionNode;
@@ -64,6 +60,7 @@
import org.apache.royale.compiler.tree.as.IScopedNode;
import org.apache.royale.compiler.tree.as.ITypeNode;
import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
+import org.apache.royale.compiler.tree.as.IVariableExpressionNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
import org.apache.royale.compiler.utils.NativeUtils;
@@ -364,6 +361,7 @@
else
{
boolean isFileOrPackageMember = false;
+ boolean isLocalFunction = false;
if(nodeDef instanceof FunctionDefinition)
{
FunctionClassification classification = ((FunctionDefinition) nodeDef).getFunctionClassification();
@@ -373,13 +371,20 @@
isFileOrPackageMember = true;
}
else if (!identifierIsMemberAccess && classification == FunctionClassification.CLASS_MEMBER &&
- isClassMember(project, nodeDef, thisClass))
- return true;
+ isClassMember(project, nodeDef, thisClass))
+ {
+ return true;
+ }
+ else if (classification == FunctionClassification.LOCAL)
+ {
+ isLocalFunction = true;
+ }
}
return parentNodeId == ASTNodeID.FunctionCallID
&& !(nodeDef instanceof AccessorDefinition)
&& !identifierIsMemberAccess
- && !isFileOrPackageMember;
+ && !isFileOrPackageMember
+ && !isLocalFunction;
}
}
else
@@ -574,25 +579,22 @@
result.setParent((NodeBase) argumentsNode.getParent());
for (int i = 0; i < originalLength; i++)
{
- if(i < originalLength)
+ if(i < index)
{
result.addItem((NodeBase) argumentsNode.getChild(i));
}
else
{
- int j = i;
- if (i >= index + extraLength)
+ if (i == index)
{
- j -= extraLength;
- result.addItem((NodeBase) argumentsNode.getChild(j));
+ for (IASNode node : nodes)
+ {
+ NodeBase n = (NodeBase) node;
+ n.setSourcePath(argumentsNode.getSourcePath());
+ result.addItem(n);
+ }
}
- else
- {
- j -= originalLength;
- NodeBase node = (NodeBase) nodes[j];
- node.setSourcePath(argumentsNode.getSourcePath());
- result.addItem(node);
- }
+ result.addItem((NodeBase) argumentsNode.getChild(i));
}
}
return result;
@@ -604,4 +606,60 @@
|| node.getContainerType() == IContainerNode.ContainerType.SYNTHESIZED;
}
+ public static boolean needsDefaultValue(IVariableNode node, boolean defaultInitializers, ICompilerProject project)
+ {
+ if (node == null)
+ {
+ return false;
+ }
+ if (node instanceof IParameterNode)
+ {
+ return false;
+ }
+ if (node instanceof IAccessorNode)
+ {
+ return false;
+ }
+ IExpressionNode assignedValueNode = node.getAssignedValueNode();
+ if (assignedValueNode != null)
+ {
+ //already has an assigned value, so it doesn't need to be
+ //hoisted
+ return false;
+ }
+ IASNode parentNode = node.getParent();
+ if (parentNode instanceof IVariableExpressionNode)
+ {
+ //ignore for-in loops
+ return false;
+ }
+ IExpressionNode variableTypeNode = node.getVariableTypeNode();
+ if (variableTypeNode == null)
+ {
+ return false;
+ }
+ IDefinition varTypeDef = variableTypeNode.resolve(project);
+ if (varTypeDef == null)
+ {
+ return false;
+ }
+ if (IASLanguageConstants.ANY_TYPE.equals(varTypeDef.getQualifiedName()))
+ {
+ return false;
+ }
+ if (project.getBuiltinType(BuiltinType.ANY_TYPE).equals(varTypeDef)
+ || project.getBuiltinType(BuiltinType.ANY_TYPE).equals(varTypeDef)
+ || project.getBuiltinType(BuiltinType.ANY_TYPE).equals(varTypeDef))
+ {
+ return false;
+ }
+ if (project.getBuiltinType(BuiltinType.INT).equals(varTypeDef)
+ || project.getBuiltinType(BuiltinType.UINT).equals(varTypeDef))
+ {
+ //always true, regardless of -js-default-initializers
+ return true;
+ }
+ return defaultInitializers;
+ }
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLWriter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLWriter.java
index 6274d53..9e45aaf 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLWriter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/MXMLWriter.java
@@ -19,9 +19,7 @@
package org.apache.royale.compiler.internal.codegen.mxml;
-import java.io.BufferedOutputStream;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
@@ -72,7 +70,7 @@
try
{
- out.write(mxmlEmitter.postProcess(writer.toString()).getBytes());
+ out.write(mxmlEmitter.postProcess(writer.toString()).getBytes("utf8"));
}
catch (IOException e)
{
@@ -82,11 +80,19 @@
if (sourceMapOut != null)
{
String sourceMapFilePath = null;
+ String sourceRoot = null;
if (sourceMapFile != null)
{
sourceMapFilePath = sourceMapFile.getAbsolutePath();
convertMappingSourcePathsToRelative((IMappingEmitter) mxmlEmitter, sourceMapFile);
}
+ else
+ {
+ sourceRoot = System.getProperty("user.dir");
+ convertMappingSourcePathsToRelative((IMappingEmitter) mxmlEmitter, new File(sourceRoot, "test.js.map"));
+ sourceRoot = convertSourcePathToURI(sourceRoot);
+ }
+ convertMappingSourcePathsToURI((IMappingEmitter) mxmlEmitter);
File compilationUnitFile = new File(compilationUnit.getAbsoluteFilename());
ISourceMapEmitter sourceMapEmitter = backend.createSourceMapEmitter((IMappingEmitter) mxmlEmitter);
@@ -94,8 +100,8 @@
{
String fileName = compilationUnitFile.getName();
fileName = fileName.replace(".mxml", ".js");
- String sourceMap = sourceMapEmitter.emitSourceMap(fileName, sourceMapFilePath, null);
- sourceMapOut.write(sourceMap.getBytes());
+ String sourceMap = sourceMapEmitter.emitSourceMap(fileName, sourceMapFilePath, sourceRoot);
+ sourceMapOut.write(sourceMap.getBytes("utf8"));
} catch (Exception e)
{
e.printStackTrace();
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleCordovaPublisher.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleCordovaPublisher.java
index 38f05a0..975ee45 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleCordovaPublisher.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleCordovaPublisher.java
@@ -19,12 +19,10 @@
package org.apache.royale.compiler.internal.codegen.mxml.royale;
-import org.apache.commons.io.FilenameUtils;
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import java.io.File;
import java.io.IOException;
public class MXMLRoyaleCordovaPublisher extends MXMLRoyalePublisher
@@ -50,12 +48,5 @@
private void createCordovaProjectIfNeeded()
{
- // The "intermediate" is the "js-debug" output.
- final File intermediateDir = outputFolder;
- final String projectName = FilenameUtils.getBaseName(configuration.getTargetFile());
-
- // The "release" is the "js-release" directory.
- File releaseDir = new File(outputParentFolder, ROYALE_RELEASE_DIR_NAME);
-
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
index 2d1baf3..e06efba 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleEmitter.java
@@ -20,10 +20,6 @@
package org.apache.royale.compiler.internal.codegen.mxml.royale;
-import static org.apache.royale.abc.ABCConstants.OP_newarray;
-import static org.apache.royale.abc.ABCConstants.OP_pushstring;
-import static org.apache.royale.abc.ABCConstants.OP_pushtrue;
-
import java.io.File;
import java.io.FilterWriter;
import java.util.ArrayList;
@@ -34,6 +30,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.Stack;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.royale.abc.semantics.MethodInfo;
@@ -50,6 +47,7 @@
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
+import org.apache.royale.compiler.internal.as.codegen.InstructionListNode;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.databinding.BindingDatabase;
import org.apache.royale.compiler.internal.codegen.databinding.BindingInfo;
@@ -80,6 +78,7 @@
import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode;
import org.apache.royale.compiler.internal.tree.mxml.MXMLDocumentNode;
import org.apache.royale.compiler.internal.tree.mxml.MXMLFileNode;
+import org.apache.royale.compiler.internal.tree.mxml.MXMLBindingNode;
import org.apache.royale.compiler.mxml.IMXMLLanguageConstants;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
@@ -184,8 +183,12 @@
{
asEmitterUsedNames.remove(usedName);
}
- System.out.println(currentClassName + " as: " + asEmitterUsedNames.toString());
- System.out.println(currentClassName + " mxml: " + usedNames.toString());
+ RoyaleJSProject fjp = (RoyaleJSProject) getMXMLWalker().getProject();
+ if (fjp.config == null || fjp.config.isVerbose())
+ {
+ System.out.println(currentClassName + " as: " + asEmitterUsedNames.toString());
+ System.out.println(currentClassName + " mxml: " + usedNames.toString());
+ }
usedNames.addAll(asEmitterUsedNames);
boolean foundXML = false;
@@ -203,14 +206,17 @@
String line = lines[i];
if (stillSearching)
{
- int c = line.indexOf(JSGoogEmitterTokens.GOOG_PROVIDE.getToken());
- if (c != -1)
+ if (provideIndex == -1 || !sawRequires)
{
- // if zero requires are found, require Language after the
- // call to goog.provide
- provideIndex = i + 1;
+ int c = line.indexOf(JSGoogEmitterTokens.GOOG_PROVIDE.getToken());
+ if (c != -1)
+ {
+ // if zero requires are found, require Language after the
+ // call to goog.provide
+ provideIndex = i + 1;
+ }
}
- c = line.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken());
+ int c = line.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken());
if (c > -1)
{
int c2 = line.indexOf(")");
@@ -243,11 +249,15 @@
if (subDocumentNames.contains(usedName)) continue;
if (royaleProject != null)
{
+ if (!isGoogProvided(usedName))
+ {
+ continue;
+ }
ICompilationUnit cu = royaleProject.resolveQNameToCompilationUnit(usedName);
- if (cu != null && royaleProject.isExternalLinkage(cu))
- continue;
- if (cu == null)
- System.out.println("didn't find CompilationUnit for " + usedName);
+ if (cu == null)
+ {
+ System.out.println("didn't find CompilationUnit for " + usedName);
+ }
}
namesToAdd.add(usedName);
}
@@ -301,14 +311,18 @@
Set<String> mixins = royaleProject.mixinClassNames;
if (mixins.size() > 0)
{
- String mixinInject = "mixins: [";
+ String mixinInject = "\"mixins\": [";
boolean firstOne = true;
for (String mixin : mixins)
{
- if (isExternal(mixin))
- continue;
- if (!firstOne)
- mixinInject += ", ";
+ if (!isGoogProvided(mixin))
+ {
+ continue;
+ }
+ if (!firstOne)
+ {
+ mixinInject += ", ";
+ }
mixinInject += mixin;
firstOne = false;
StringBuilder appendString = new StringBuilder();
@@ -330,14 +344,18 @@
Map<String, String> aliases = royaleProject.remoteClassAliasMap;
if (aliases != null && aliases.size() > 0)
{
- String aliasInject = sep + "remoteClassAliases: {";
+ String aliasInject = sep + "\"remoteClassAliases\": {";
boolean firstOne = true;
for (String className : aliases.keySet())
{
- if (isExternal(className))
- continue;
- if (!firstOne)
- aliasInject += ", ";
+ if (!isGoogProvided(className))
+ {
+ continue;
+ }
+ if (!firstOne)
+ {
+ aliasInject += ", ";
+ }
aliasInject += "\"" + className + "\": ";
String alias = aliases.get(className);
aliasInject += "\"" + alias + "\"";
@@ -361,14 +379,16 @@
Collection<String> locales = royaleProject.getLocales();
if (locales.size() > 0)
{
- String localeInject = sep + "compiledLocales: [";
+ String localeInject = sep + "\"compiledLocales\": [";
boolean firstOne = true;
String[] localeNames = new String[locales.size()];
locales.toArray(localeNames);
for (String locale : localeNames)
{
- if (!firstOne)
- localeInject += ", ";
+ if (!firstOne)
+ {
+ localeInject += ", ";
+ }
localeInject += "\"" + locale + "\"";
firstOne = false;
}
@@ -380,12 +400,14 @@
List<String> bundles = royaleProject.compiledResourceBundleNames;
if (bundles.size() > 0)
{
- String bundleInject = sep + "compiledResourceBundleNames: [";
+ String bundleInject = sep + "\"compiledResourceBundleNames\": [";
boolean firstOne = true;
for (String bundle : bundles)
{
- if (!firstOne)
- bundleInject += ", ";
+ if (!firstOne)
+ {
+ bundleInject += ", ";
+ }
bundleInject += "\"" + bundle + "\"";
firstOne = false;
}
@@ -482,19 +504,26 @@
}
if (staticUsedNames.size() > 0)
{
- StringBuilder sb = new StringBuilder();
- sb.append(JSGoogEmitterTokens.ROYALE_STATIC_DEPENDENCY_LIST.getToken());
- boolean firstDependency = true;
- for (String staticName : staticUsedNames)
+ if (staticUsedNames.size() > 1 ||
+ !staticUsedNames.get(0).equals(currentClassName))
{
- if (!firstDependency)
- sb.append(",");
- firstDependency = false;
- sb.append(staticName);
+ StringBuilder sb = new StringBuilder();
+ sb.append(JSGoogEmitterTokens.ROYALE_STATIC_DEPENDENCY_LIST.getToken());
+ boolean firstDependency = true;
+ for (String staticName : staticUsedNames)
+ {
+ if (currentClassName.equals(staticName))
+ continue;
+
+ if (!firstDependency)
+ sb.append(",");
+ firstDependency = false;
+ sb.append(staticName);
+ }
+ sb.append("*/");
+ finalLines.add(provideIndex, sb.toString());
+ addLineToMappings(provideIndex);
}
- sb.append("*/");
- finalLines.add(provideIndex, sb.toString());
- addLineToMappings(provideIndex);
}
return Joiner.on("\n").join(finalLines);
@@ -739,6 +768,7 @@
{
ArrayList<MXMLDescriptorSpecifier> oldDescriptorTree;
MXMLDescriptorSpecifier oldPropertiesTree;
+ MXMLDescriptorSpecifier oldStateOverrides;
ArrayList<MXMLEventSpecifier> oldEvents;
ArrayList<IMXMLScriptNode> oldScripts;
ArrayList<MXMLDescriptorSpecifier> oldCurrentInstances;
@@ -767,7 +797,9 @@
currentInstances = new ArrayList<MXMLDescriptorSpecifier>();
oldCurrentPropertySpecifiers = currentPropertySpecifiers;
currentPropertySpecifiers = new ArrayList<MXMLDescriptorSpecifier>();
-
+ oldStateOverrides = currentStateOverrides;
+ currentStateOverrides = new MXMLDescriptorSpecifier();
+
oldEventCounter = eventCounter;
eventCounter = 0;
oldIdCounter = idCounter;
@@ -820,6 +852,7 @@
descriptorTree = oldDescriptorTree;
propertiesTree = oldPropertiesTree;
+ currentStateOverrides = oldStateOverrides;
events = oldEvents;
scripts = oldScripts;
currentInstances = oldCurrentInstances;
@@ -1174,24 +1207,18 @@
data.isStatic = false;
data.declaredBy = cdef.getQualifiedName();
}
-
-
- for (MXMLEventSpecifier event : events)
- {
- PackageFooterEmitter.MethodData data = asEmitter.packageFooterEmitter.new MethodData();
- methodData.add(data);
- data.name = event.eventHandler;
- data.type = ASEmitterTokens.VOID.getToken();
- data.declaredBy = cdef.getQualifiedName();
- }
+
ArrayList<IMetaTagNode> metadataTagNodes = new ArrayList<IMetaTagNode>();
for (IMXMLMetadataNode metadataTag : metadataNodes)
{
IMetaTagNode[] tags = metadataTag.getMetaTagNodes();
- for (IMetaTagNode tag : tags)
- {
- metadataTagNodes.add(tag);
- }
+ //tags (MetaTagNodes) can be null if the parent node is empty (or content is commented out)
+ if (tags != null) {
+ for (IMetaTagNode tag : tags)
+ {
+ metadataTagNodes.add(tag);
+ }
+ }
}
IMetaTagNode[] metaDataTags = new IMetaTagNode[metadataTagNodes.size()];
@@ -1202,6 +1229,11 @@
accessorData,
methodData,
metadataTagNodes.toArray(metaDataTags));
+
+ asEmitter.packageFooterEmitter.emitReflectionRegisterInitialStaticFields(
+ formatQualifiedName(cdef.getQualifiedName()),
+ cdef);
+
asEmitter.packageFooterEmitter.emitExportProperties(
formatQualifiedName(cdef.getQualifiedName()),
exportProperties,
@@ -1303,8 +1335,8 @@
private void outputBindingInfoAsData(String cname, BindingDatabase bindingDataBase)
{
IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker())
- .getASEmitter();
-
+ .getASEmitter();
+
writeNewline("/**");
writeNewline(" * @export"); // must export or else GCC will remove it
writeNewline(" */");
@@ -1313,9 +1345,11 @@
Set<BindingInfo> bindingInfo = bindingDataBase.getBindingInfo();
writeNewline(bindingInfo.size() + ","); // number of bindings
-
+ boolean hadOutput = false;
for (BindingInfo bi : bindingInfo)
{
+ if (hadOutput) writeNewline(ASEmitterTokens.COMMA.getToken());
+ hadOutput = true;
String s;
IMXMLNode node = bi.node;
if (node instanceof IMXMLSingleDataBindingNode)
@@ -1325,7 +1359,7 @@
IDefinition bdef = sbdn.getExpressionNode().resolve(project);
if (bdef != null)
{
- IDefinition cdef = bdef.getParent();
+ //IDefinition cdef = bdef.getParent();
project.addExportedName(/*cdef.getQualifiedName() + "." + */bdef.getBaseName());
}
}
@@ -1362,8 +1396,11 @@
String[] parts = s.split("\\.");
write(ASEmitterTokens.SQUARE_OPEN.getToken() + ASEmitterTokens.DOUBLE_QUOTE.getToken() +
bi.classDef.getQualifiedName() + ASEmitterTokens.DOUBLE_QUOTE.getToken());
- usedNames.add(bi.classDef.getQualifiedName());
- staticUsedNames.add(bi.classDef.getQualifiedName());
+ String qname = bi.classDef.getQualifiedName();
+ if (!usedNames.contains(qname))
+ usedNames.add(qname);
+ if (!staticUsedNames.contains(qname))
+ staticUsedNames.add(qname);
int n = parts.length;
for (int i = 1; i < n; i++)
{
@@ -1391,19 +1428,19 @@
ASEmitterTokens.DOUBLE_QUOTE.getToken() + ASEmitterTokens.COMMA.getToken());
IExpressionNode destNode = bi.getExpressionNodeForDestination();
- if (destNode != null)
+ s = bi.getDestinationString();
+ if (destNode != null && s == null)
{
StringBuilder sb = new StringBuilder();
- sb.append(generateSetterFunction(destNode));
+ sb.append(generateSetterFunction(bi, destNode));
writeNewline(sb.toString() + ASEmitterTokens.COMMA.getToken());
}
else
writeNewline(ASEmitterTokens.NULL.getToken() + ASEmitterTokens.COMMA.getToken());
- s = bi.getDestinationString();
if (s == null)
{
- writeNewline(ASEmitterTokens.NULL.getToken() + ASEmitterTokens.COMMA.getToken());
+ write(ASEmitterTokens.NULL.getToken());
}
else if (s.contains("."))
{
@@ -1416,17 +1453,22 @@
String part = parts[i];
write(", " + ASEmitterTokens.DOUBLE_QUOTE.getToken() + part + ASEmitterTokens.DOUBLE_QUOTE.getToken());
}
- writeNewline(ASEmitterTokens.SQUARE_CLOSE.getToken() + ASEmitterTokens.COMMA.getToken());
+ write(ASEmitterTokens.SQUARE_CLOSE.getToken());
}
else
- writeNewline(ASEmitterTokens.DOUBLE_QUOTE.getToken() + s +
- ASEmitterTokens.DOUBLE_QUOTE.getToken() + ASEmitterTokens.COMMA.getToken());
+ write(ASEmitterTokens.DOUBLE_QUOTE.getToken() + s +
+ ASEmitterTokens.DOUBLE_QUOTE.getToken());
+
}
Set<Entry<Object, WatcherInfoBase>> watcherChains = bindingDataBase.getWatcherChains();
-
+
if (watcherChains != null)
{
int count = watcherChains.size();
+ if (hadOutput) {
+ if (count > 0) writeNewline(ASEmitterTokens.COMMA);
+ else writeNewline();
+ }
for (Entry<Object, WatcherInfoBase> entry : watcherChains)
{
count--;
@@ -1434,37 +1476,70 @@
encodeWatcher(watcherInfoBase);
if (count > 0) writeNewline(ASEmitterTokens.COMMA);
}
+ } else {
+ if (hadOutput) writeNewline();
}
writeNewline( ASEmitterTokens.SQUARE_CLOSE.getToken() + ASEmitterTokens.SEMICOLON.getToken());
}
- private String generateSetterFunction(IExpressionNode destNode) {
+ private String generateSetterFunction(BindingInfo bi, IExpressionNode destNode) {
IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker())
.getASEmitter();
- String body = asEmitter.stringifyNode(destNode);
-
StringBuilder sb = new StringBuilder();
sb.append("function (value) { ");
- int lastGet = body.lastIndexOf("get_");
- int lastDot = body.lastIndexOf(".");
- if (lastDot == lastGet - 1)
+ if (destNode instanceof InstructionListNode)
{
- String object = body.substring(0, lastDot);
- String getter = body.substring(lastDot);
- String setter = getter.replace("get_", "set_");
- setter = setter.replace("()", "(value)");
- body = object + setter;
- sb.append(body);
+ sb.append(generateDestExpression(bi));
}
else
{
+ String body = asEmitter.stringifyNode(destNode);
sb.append(body);
sb.append(" = value;");
}
- sb.append(";}");
+ sb.append("}");
return sb.toString();
}
+
+ String generateDestExpression(BindingInfo bi)
+ {
+ StringBuilder sb = new StringBuilder();
+ MXMLBindingNode node = (MXMLBindingNode)bi.node;
+ IMXMLBindingAttributeNode destNode = node.getDestinationAttributeNode();
+ Stack<IASNode> nodeStack = new Stack<IASNode>();
+ nodeStack.push(node);
+ IASNode parentNode = node.getParent();
+ while (!(parentNode instanceof IMXMLInstanceNode))
+ {
+ nodeStack.push(parentNode);
+ parentNode = parentNode.getParent();
+ }
+ boolean isXML = parentNode instanceof IMXMLXMLNode;
+ sb.append("this.");
+ sb.append(((IMXMLInstanceNode)parentNode).getEffectiveID());
+ while (nodeStack.size() > 0)
+ {
+ IASNode childNode = nodeStack.pop();
+ int n = parentNode.getChildCount();
+ int i = 0;
+ for (; i < n; i++)
+ {
+ if (childNode == parentNode.getChild(i))
+ break;
+ }
+ assert i < n;
+ sb.append("[" + new Integer(i).toString() + "]" );
+ parentNode = childNode;
+ }
+ if (isXML)
+ {
+ sb.append(".setAttribute('" + destNode.getName() + "', value);" );
+ }
+ else
+ sb.append("." + destNode.getName() + " = value;");
+ return sb.toString();
+ }
private void encodeWatcher(WatcherInfoBase watcherInfoBase)
{
@@ -1480,19 +1555,22 @@
FunctionWatcherInfo functionWatcherInfo = (FunctionWatcherInfo)watcherInfoBase;
writeNewline(ASEmitterTokens.DOUBLE_QUOTE.getToken() + functionWatcherInfo.getFunctionName() +
- ASEmitterTokens.DOUBLE_QUOTE.getToken());
+ ASEmitterTokens.DOUBLE_QUOTE.getToken() + ASEmitterTokens.COMMA.getToken());
IExpressionNode params[] = functionWatcherInfo.params;
StringBuilder sb = new StringBuilder();
sb.append("function() { return [");
boolean firstone = true;
for (IExpressionNode param : params)
{
- if (firstone)
- firstone = false;
- sb.append(ASEmitterTokens.COMMA.getToken());
+ if (!firstone)
+ {
+ sb.append(ASEmitterTokens.COMMA.getToken());
+ }
+ firstone = false;
sb.append(asEmitter.stringifyNode(param));
}
sb.append("]; },");
+ writeNewline(sb.toString());
outputEventNames(functionWatcherInfo.getEventNames());
outputBindings(functionWatcherInfo.getBindings());
}
@@ -1762,7 +1840,7 @@
int n = 0;
for (MXMLDescriptorSpecifier instance : instances)
{
- if (instance.id != null)
+ if (instance.id != null || instance.hasLocalId)
{
n++;
}
@@ -1997,7 +2075,7 @@
propertiesTree.propertySpecifiers.add(currentInstance);
}
- instances.add(currentInstance);
+ addInstanceIfNeeded(instances, currentInstance);
IMXMLPropertySpecifierNode[] pnodes = node.getPropertySpecifierNodes();
if (pnodes != null)
@@ -2092,7 +2170,17 @@
}
}
- public void emitPropertyOverride(IMXMLPropertySpecifierNode propertyNode)
+ private void addInstanceIfNeeded(
+ ArrayList<MXMLDescriptorSpecifier> instances2,
+ MXMLDescriptorSpecifier currentInstance) {
+ for (MXMLDescriptorSpecifier instance : instances2)
+ if (instance.id != null && currentInstance.id != null && instance.id.equals(currentInstance.id))
+ return;
+ instances.add(currentInstance);
+
+ }
+
+ public void emitPropertyOverride(IMXMLPropertySpecifierNode propertyNode)
{
RoyaleProject project = (RoyaleProject) getMXMLWalker().getProject();
Name propertyOverride = project.getPropertyOverrideClassName();
@@ -2720,7 +2808,7 @@
}
}
writeNewline("/**");
- writeNewline(" * Generated by Apache Royale Compiler from " + sourceName);
+ writeNewline(" * Generated by Apache Royale Compiler from " + sourceName.replace('\\', '/'));
writeNewline(" * " + cname);
writeNewline(" *");
writeNewline(" * @fileoverview");
@@ -2954,16 +3042,23 @@
if (subDocumentNames.contains(name))
return documentDefinition.getQualifiedName() + "." + name;
if (NativeUtils.isJSNative(name)) return name;
- if (inStaticInitializer)
- if (!staticUsedNames.contains(name) && !NativeUtils.isJSNative(name) && !isExternal(name))
- staticUsedNames.add(name);
+ if (inStaticInitializer)
+ {
+ if (!staticUsedNames.contains(name) && !NativeUtils.isJSNative(name) && isGoogProvided(name))
+ {
+ staticUsedNames.add(name);
+ }
+ }
- if (useName && !usedNames.contains(name) && !isExternal(name))
- usedNames.add(name);
+ if (useName && !usedNames.contains(name) && isGoogProvided(name))
+ {
+ usedNames.add(name);
+ }
return name;
}
- private void emitComplexInitializers(IASNode node)
+ @SuppressWarnings("incomplete-switch")
+ private void emitComplexInitializers(IASNode node)
{
int n = node.getChildCount();
for (int i = 0; i < n; i++)
@@ -2993,16 +3088,17 @@
write(ASEmitterTokens.MEMBER_ACCESS);
JSRoyaleEmitter fjs = (JSRoyaleEmitter) ((IMXMLBlockWalker) getMXMLWalker())
.getASEmitter();
- ICompilerProject project = getMXMLWalker().getProject();
+
+ ICompilerProject project = getMXMLWalker().getProject();
String qname = varnode.getName();
- if (varDef != null && varDef.isPrivate() && project.getAllowPrivateNameConflicts())
- qname = fjs.formatPrivateName(varDef.getParent().getQualifiedName(), qname);
+ if (varDef != null && varDef.isPrivate() && project.getAllowPrivateNameConflicts())
+ qname = fjs.formatPrivateName(varDef.getParent().getQualifiedName(), qname);
write(qname);
if (schildID == ASTNodeID.BindableVariableID && !varnode.isConst())
write("_"); // use backing variable
write(ASEmitterTokens.SPACE);
writeToken(ASEmitterTokens.EQUAL);
- fjs.getWalker().walk(vnode);
+ fjs.emitAssignmentCoercion(vnode, varnode.getVariableTypeNode().resolve(getMXMLWalker().getProject()));
write(ASEmitterTokens.SEMICOLON);
}
@@ -3121,9 +3217,15 @@
if (instanceNode instanceof IMXMLStringNode)
{
IMXMLStringNode stringNode = (IMXMLStringNode)instanceNode;
- IMXMLLiteralNode valueNode = (IMXMLLiteralNode)(stringNode.getExpressionNode());
- Object value = valueNode.getValue();
- return objectToString(value);
+ IASNode vNode = stringNode.getExpressionNode();
+ if (vNode instanceof IMXMLLiteralNode)
+ {
+ IMXMLLiteralNode valueNode = (IMXMLLiteralNode)vNode;
+ Object value = valueNode.getValue();
+ return objectToString(value);
+ }
+ else
+ return "''";
}
return "";
}
@@ -3176,14 +3278,11 @@
//System.out.println("mxml implements "+list);
interfaceList = list.toString();
}
-
- boolean isExternal(String className)
+
+ boolean isGoogProvided(String className)
{
ICompilerProject project = getMXMLWalker().getProject();
- ICompilationUnit cu = project.resolveQNameToCompilationUnit(className);
- if (cu == null) return false; // unit testing
-
- return ((RoyaleJSProject)project).isExternalLinkage(cu);
+ return ((RoyaleJSProject)project).isGoogProvided(className);
}
@Override
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyalePublisher.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyalePublisher.java
index 9cd88ad..0407b31 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyalePublisher.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyalePublisher.java
@@ -18,6 +18,7 @@
*/
package org.apache.royale.compiler.internal.codegen.mxml.royale;
+import com.google.common.io.Files;
import com.google.javascript.jscomp.SourceFile;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
@@ -29,7 +30,6 @@
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.codegen.js.IJSPublisher;
import org.apache.royale.compiler.config.Configuration;
-import org.apache.royale.compiler.css.ICSSDocument;
import org.apache.royale.compiler.css.ICSSPropertyValue;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.filespecs.IFileSpecification;
@@ -45,7 +45,6 @@
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.scopes.ASProjectScope.DefinitionPromise;
import org.apache.royale.compiler.internal.targets.ITargetAttributes;
-import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
import org.apache.royale.compiler.utils.JSClosureCompilerWrapper;
import org.apache.royale.swc.ISWC;
import org.apache.royale.swc.ISWCFileEntry;
@@ -54,6 +53,7 @@
import java.io.*;
import java.net.URL;
import java.net.URLDecoder;
+import java.nio.charset.Charset;
import java.util.*;
public class MXMLRoyalePublisher extends JSGoogPublisher implements IJSPublisher
@@ -100,6 +100,7 @@
private String outputPathParameter;
private String moduleOutput;
private boolean useStrictPublishing;
+ private List<String> additionalHTML = new ArrayList<String>();
private GoogDepsWriter getGoogDepsWriter(File intermediateDir,
String mainClassQName,
@@ -189,11 +190,17 @@
// The source directory is the source path entry containing the Main class.
List<File> sourcePaths = project.getSourcePath();
String targetFile = configuration.getTargetFile().toLowerCase();
- System.out.println("find project folder for " + targetFile);
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("find project folder for " + targetFile);
+ }
File imageSrcDir = null;
for (File sp : sourcePaths)
{
- System.out.println("checking source path " + sp.getAbsolutePath());
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("checking source path " + sp.getAbsolutePath());
+ }
String lowercasePath = sp.getAbsolutePath().toLowerCase();
if (targetFile.startsWith(lowercasePath))
imageSrcDir = sp;
@@ -201,7 +208,10 @@
if (imageSrcDir == null)
{
imageSrcDir = new File(configuration.getTargetFile()).getAbsoluteFile().getParentFile();
- System.out.println("not found on source path, using parent file " + imageSrcDir.getAbsolutePath());
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("not found on source path, using parent file " + imageSrcDir.getAbsolutePath());
+ }
}
final String projectName = FilenameUtils.getBaseName(configuration.getTargetFile());
String qName = null;
@@ -351,7 +361,7 @@
// the application will not be able to run.
for(SourceFile closureSourceFile : closureSourceFiles) {
FileUtils.write(new File(new File(intermediateDir, "library/closure"),
- closureSourceFile.getName()), closureSourceFile.getCode());
+ closureSourceFile.getName()), closureSourceFile.getCode(), Charset.forName("utf8"));
}
closureSourceFiles = closureFilesInOrder(intermediateDir + "/library/closure/", closureSourceFiles, "goog.events.EventTarget");
@@ -360,18 +370,24 @@
// Prepare the closure compilation.
/////////////////////////////////////////////////////////////////////////////////
- JSClosureCompilerWrapper compilerWrapper = new JSClosureCompilerWrapper(googConfiguration.getJSCompilerOptions());
-
-
- /////////////////////////////////////////////////////////////////////////////////
- // Add all the closure lib files to the compilation unit.
- /////////////////////////////////////////////////////////////////////////////////
-
- for (SourceFile closureSourceFile : closureSourceFiles) {
- compilerWrapper.addJSSourceFile(closureSourceFile);
+ JSClosureCompilerWrapper compilerWrapper = null;
+ if (configuration.release())
+ {
+ compilerWrapper = new JSClosureCompilerWrapper(googConfiguration.getJSCompilerOptions());
}
- writeExportedNames(compilerWrapper);
+ if (compilerWrapper != null)
+ {
+ /////////////////////////////////////////////////////////////////////////////////
+ // Add all the closure lib files to the compilation unit.
+ /////////////////////////////////////////////////////////////////////////////////
+
+ for (SourceFile closureSourceFile : closureSourceFiles) {
+ compilerWrapper.addJSSourceFile(closureSourceFile);
+ }
+
+ writeExportedNames(compilerWrapper);
+ }
/////////////////////////////////////////////////////////////////////////////////
// Add all the externs to the compilation
@@ -379,6 +395,7 @@
// Iterate over all swc dependencies and add all the externs they contain.
// (Externs are located in a "externs" directory in the root of the SWC)
+ Set<ISWC> swcExterns = project.swcExterns;
List<ISWC> swcs = project.getLibraries();
List<ISWC> allswcs = new ArrayList<ISWC>();
allswcs.addAll(swcs);
@@ -396,19 +413,27 @@
InputStream is = fileEntry.createInputStream();
String code = IOUtils.toString(is, "UTF-8");
is.close();
- JarSourceFile externFile = new JarSourceFile(key, code,true);
- System.out.println("using extern: " + key);
- compilerWrapper.addJSExternsFile(externFile);
+
+ if (compilerWrapper != null)
+ {
+ JarSourceFile externFile = new JarSourceFile(key, code,true);
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("using extern: " + key);
+ }
+ compilerWrapper.addJSExternsFile(externFile);
+ }
- // Write the extern into the filesystem.
- // FIXME: I don't know why we need to do this.
- //FileUtils.write(new File(intermediateDir, key), externFile.getCode());
+ if (swcExterns.contains(swc))
+ {
+ List<String> lines = IOUtils.readLines(new StringReader(code));
+ collectAdditionalHTML(lines, swc.getSWCFile().getAbsolutePath() + ":" + key);
+ }
}
}
}
}
-
/////////////////////////////////////////////////////////////////////////////////
// Add all files generated by the compiler to the compilation unit.
/////////////////////////////////////////////////////////////////////////////////
@@ -419,28 +444,44 @@
// js files of used dependencies.
ArrayList<String> sourceExternFiles = new ArrayList<String>();
ArrayList<String> fileList = gdw.getListOfFiles(project, sourceExternFiles, problems);
+ if (fileList == null)
+ return false; // some error occurred
+
for (String sourceExtern : project.sourceExterns)
{
- String sourceExternFileName = sourceExtern.replace(".", "/") + ".js";
- File sourceExternFile = new File(intermediateDir, sourceExternFileName);
- if (sourceExternFile.exists())
- {
- String sourceExternPath = sourceExternFile.getAbsolutePath();
- if (!sourceExternFiles.contains(sourceExternPath))
- sourceExternFiles.add(sourceExternPath);
- }
+ String sourceExternFileName = sourceExtern.replace(".", "/") + ".js";
+ File sourceExternFile = new File(intermediateDir, sourceExternFileName);
+ if (sourceExternFile.exists())
+ {
+ String sourceExternPath = sourceExternFile.getAbsolutePath();
+ if (!sourceExternFiles.contains(sourceExternPath))
+ sourceExternFiles.add(sourceExternPath);
+ }
}
- if (fileList == null)
- return false; // some error occurred
- for (String file : fileList) {
- compilerWrapper.addJSSourceFile(file);
- System.out.println("using source file: " + file);
+ if (compilerWrapper != null)
+ {
+ for (String file : fileList)
+ {
+ compilerWrapper.addJSSourceFile(file);
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("using source file: " + file);
+ }
+ }
}
- for (String file : sourceExternFiles) {
- compilerWrapper.addJSExternsFile(file);
- System.out.println("using extern file: " + file);
+ for (String file : sourceExternFiles)
+ {
+ if (compilerWrapper != null)
+ {
+ compilerWrapper.addJSExternsFile(file);
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("using extern file: " + file);
+ }
+ }
+ collectFileAdditionalHTML(file);
}
-
+ additionalHTML.addAll(gdw.additionalHTML);
/////////////////////////////////////////////////////////////////////////////////
// Generate the index.html for loading the application.
@@ -450,14 +491,23 @@
// is generated here so it can be used for outputting the html templates.
String depsFileData = gdw.generateDeps(project, problems);
+ // FOR MODULES: this generate inject_html lines for js to be added to __deps.js
+ String moduleAdditionHTML = "";
+
if (project.isModule(mainClassQName))
{
+ for (String s : additionalHTML)
+ {
+ moduleAdditionHTML += "document.head.innerHTML += '"+ s.trim() + "';";
+ }
+
// need better test someday
depsFileData += "\ngoog.require('" + mainClassQName + "');\n";
- writeFile(new File(intermediateDir, projectName + "__deps.js"), depsFileData, false);
- Set<String> provideds = computeProvideds(depsFileData);
- compilerWrapper.setProvideds(provideds);
+ writeFile(new File(intermediateDir, projectName + "__deps.js"), depsFileData + moduleAdditionHTML + "\n", false);
gdw.needCSS = true;
+ if (configuration.release()) {
+ writeFile(new File(releaseDir, projectName + ".js"), moduleAdditionHTML, false);
+ }
}
else
{
@@ -465,17 +515,17 @@
// Create the index.html for the debug-js version.
if (!((JSGoogConfiguration)configuration).getSkipTranspile()) {
if (template != null) {
- writeTemplate(template, "intermediate", projectName, mainClassQName, intermediateDir, depsFileData, gdw.additionalHTML);
+ writeTemplate(template, "intermediate", projectName, mainClassQName, intermediateDir, depsFileData, additionalHTML);
} else {
- writeHTML("intermediate", projectName, mainClassQName, intermediateDir, depsFileData, gdw.additionalHTML);
+ writeHTML("intermediate", projectName, mainClassQName, intermediateDir, depsFileData, additionalHTML);
}
}
// Create the index.html for the release-js version.
if (configuration.release()) {
if (template != null) {
- writeTemplate(template, "release", projectName, mainClassQName, releaseDir, depsFileData, gdw.additionalHTML);
+ writeTemplate(template, "release", projectName, mainClassQName, releaseDir, depsFileData, additionalHTML);
} else {
- writeHTML("release", projectName, mainClassQName, releaseDir, null, gdw.additionalHTML);
+ writeHTML("release", projectName, mainClassQName, releaseDir, null, additionalHTML);
}
}
}
@@ -500,40 +550,35 @@
// If we are doing a release build, let the closure compiler do it's job.
/////////////////////////////////////////////////////////////////////////////////
- if (configuration.release()) {
+ if (compilerWrapper != null) {
+ boolean ok = true;
final File projectReleaseMainFile = new File(releaseDir, outputFileName);
compilerWrapper.setOptions(projectReleaseMainFile.getCanonicalPath(), useStrictPublishing, !googConfiguration.getRemoveCirculars(), projectName);
compilerWrapper.targetFilePath = projectReleaseMainFile.getCanonicalPath();
compilerWrapper.setSourceMap(googConfiguration.getSourceMap());
+ compilerWrapper.setVerbose(googConfiguration.isVerbose());
- compilerWrapper.compile();
+ ok = compilerWrapper.compile();
+
+ // FOR MODULES: add moduleAdditionHTML to main js release file too
+ if (project.isModule(mainClassQName))
+ {
+ StringBuilder appendString = new StringBuilder();
+ appendString.append(moduleAdditionHTML);
+ writeFile(projectReleaseMainFile, appendString.toString(), true);
+ }
appendSourceMapLocation(projectReleaseMainFile, projectName);
+
+ if (ok)
+ System.out.println("The project '" + projectName + "' has been successfully compiled and optimized.");
}
-
- // if (ok)
- System.out.println("The project '" + projectName + "' has been successfully compiled and optimized.");
+ else
+ System.out.println("The project '" + projectName + "' has been successfully compiled.");
return true;
}
- private Set<String> computeProvideds(String data)
- {
- HashSet<String> set = new HashSet<String>();
- String[] lines = data.split("\n");
- for (String line : lines)
- {
- int c = line.indexOf("['");
- if (c != -1)
- {
- int c2 = line.indexOf("'", c + 2);
- String name = line.substring(c + 2, c2);
- set.add(name);
- }
- }
- return set;
- }
-
protected List<SourceFile> closureFilesInOrder(String path, List<SourceFile> files, String entryPoint)
{
ArrayList<String> sortedFiles = new ArrayList<String>();
@@ -545,7 +590,10 @@
if ((sourceFile.getOriginalPath().endsWith("goog/deps.js") || sourceFile.getOriginalPath().endsWith("goog\\deps.js")) &&
!(sourceFile.getOriginalPath().endsWith("third_party/goog/deps.js") || sourceFile.getOriginalPath().endsWith("third_party\\goog\\deps.js")))
depsFile = sourceFile;
- System.out.println("originalPath: " + sourceFile.getOriginalPath());
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("originalPath: " + sourceFile.getOriginalPath());
+ }
fileMap.put(sourceFile.getOriginalPath(), sourceFile);
}
@@ -557,10 +605,13 @@
while (true)
{
String line = in.readLine();
+ if (line == null)
+ break;
if (line.startsWith("//") || line.trim().length() == 0)
continue;
deps.add(line);
}
+ in.close();
}
catch (Exception e)
{
@@ -579,7 +630,10 @@
for (int i = n - 1; i >= 0; i--)
{
String fileName = sortedFiles.get(i);
- System.out.println("sorted filename: " + fileName);
+ if (googConfiguration.isVerbose())
+ {
+ System.out.println("sorted filename: " + fileName);
+ }
if (seen.contains(fileName))
continue;
seen.add(fileName);
@@ -591,6 +645,84 @@
}
return list;
}
+
+ private void collectFileAdditionalHTML(String filePath)
+ {
+ List<String> fileLines;
+ try
+ {
+ fileLines = Files.readLines(new File(filePath), Charset.forName("utf8"));
+ }
+ catch(IOException e)
+ {
+ return;
+ }
+ collectAdditionalHTML(fileLines, filePath);
+ }
+
+ private void collectAdditionalHTML(List<String> lines, String key)
+ {
+ boolean inDocComment = false;
+ boolean inConstructor = false;
+ boolean inInjectHTML = false;
+ for (int i = 0; i < lines.size(); i++)
+ {
+ String line = lines.get(i);
+ if (inDocComment)
+ {
+ if (inInjectHTML)
+ {
+ if (line.indexOf("</inject_html>") > -1)
+ {
+ inInjectHTML = false;
+ continue;
+ }
+ line = line.trim();
+ if (line.startsWith("*"))
+ line = line.substring(1);
+ additionalHTML.add(line);
+ continue;
+ }
+ int c = line.indexOf("<inject_html>");
+ if (c != -1)
+ {
+ inInjectHTML = true;
+ continue;
+ }
+ if (!inConstructor)
+ {
+ c = line.indexOf("@constructor");
+ if(c != -1)
+ {
+ inConstructor = true;
+ continue;
+ }
+ }
+ c = line.indexOf("*/");
+ if(c != -1)
+ {
+ if(inConstructor)
+ {
+ //we're done
+ break;
+ }
+ inInjectHTML = false;
+ inDocComment = false;
+ inConstructor = false;
+ }
+
+ }
+ else
+ {
+ int c = line.indexOf("/**");
+ if(c != -1)
+ {
+ inDocComment = true;
+ continue;
+ }
+ }
+ }
+ }
private void sortClosureFile(List<String> deps, String entryPoint, List<String> sortedFiles)
{
@@ -609,23 +741,23 @@
for (String dep : deps)
{
int open = dep.indexOf("[");
- int close = dep.indexOf("]");
+ int close = dep.indexOf("]", open + 1);
String list = dep.substring(open + 1, close);
String[] parts = list.split(",");
- ArrayList<String> provideds = new ArrayList<String>();
for (String part : parts)
{
part = part.trim();
- if (part.startsWith("'"))
- part = part.substring(1, part.length() - 1);
- provideds.add(part);
+ if (part.startsWith("'"))
+ {
+ part = part.substring(1, part.length() - 1);
+ }
+ if(part.equals(name))
+ {
+ open = dep.indexOf("'");
+ close = dep.indexOf("'", open + 1);
+ return dep.substring(open + 1, close);
+ }
}
- if (provideds.contains(name))
- {
- open = dep.indexOf("'");
- close = dep.indexOf("'", open + 1);
- return dep.substring(open + 1, close);
- }
}
return null;
}
@@ -635,35 +767,40 @@
for (String dep : deps)
{
int open = dep.indexOf("[");
- int close = dep.indexOf("]");
+ int close = dep.indexOf("]", open + 1);
String list = dep.substring(open + 1, close);
String[] parts = list.split(",");
- ArrayList<String> provideds = new ArrayList<String>();
for (String part : parts)
{
part = part.trim();
- if (part.startsWith("'"))
- part = part.substring(1, part.length() - 1);
- provideds.add(part);
+ if (part.startsWith("'"))
+ {
+ part = part.substring(1, part.length() - 1);
+ }
+
+ if(part.equals(name))
+ {
+ open = dep.indexOf("[", close + 1);
+ close = dep.indexOf("]", open + 1);
+ if (open + 1 == close)
+ {
+ return null;
+ }
+ String list2 = dep.substring(open + 1, close);
+ String[] parts2 = list2.split(",");
+ ArrayList<String> reqs = new ArrayList<String>();
+ for (String part2 : parts2)
+ {
+ part2 = part2.trim();
+ if (part2.startsWith("'"))
+ {
+ part2 = part2.substring(1, part2.length() - 1);
+ }
+ reqs.add(part2);
+ }
+ return reqs;
+ }
}
- if (provideds.contains(name))
- {
- open = dep.indexOf("[", close + 1);
- close = dep.indexOf("]", open + 1);
- if (open + 1 == close)
- return null;
- String list2 = dep.substring(open + 1, close);
- String[] parts2 = list2.split(",");
- ArrayList<String> reqs = new ArrayList<String>();
- for (String part : parts2)
- {
- part = part.trim();
- if (part.startsWith("'"))
- part = part.substring(1, part.length() - 1);
- reqs.add(part);
- }
- return reqs;
- }
}
return null;
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogCompcConfiguration.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogCompcConfiguration.java
index c5581b0..46af0bd 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogCompcConfiguration.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogCompcConfiguration.java
@@ -423,6 +423,26 @@
}
//
+ // 'export-protected-symbols'
+ //
+
+ private boolean exportProtectedSymbols = false;
+
+ public boolean getExportProtectedSymbols()
+ {
+ return exportProtectedSymbols;
+ }
+
+ @Config
+ @Mapping("export-protected-symbols")
+ public void setExportProtectedSymbols(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ exportProtectedSymbols = value;
+ }
+
+
+ //
// 'warn-public-vars'
//
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java
index b6c6d7b..d4e5328 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/driver/js/goog/JSGoogConfiguration.java
@@ -46,7 +46,7 @@
* configure() method of {@link MXMLJSC}.
* <p>
* This class inherits all compiler arguments from the MXMLC compiler.
- *
+ *
* @author Erik de Bruin
*/
public class JSGoogConfiguration extends JSConfiguration
@@ -428,6 +428,26 @@
//
+ // 'export-protected-symbols'
+ //
+
+ private boolean exportProtectedSymbols = false;
+
+ public boolean getExportProtectedSymbols()
+ {
+ return exportProtectedSymbols;
+ }
+
+ @Config
+ @Mapping("export-protected-symbols")
+ public void setExportProtectedSymbols(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ exportProtectedSymbols = value;
+ }
+
+
+ //
// 'warn-public-vars'
//
@@ -446,6 +466,69 @@
warnPublicVars = value;
}
+ // 'externs-report' option
+ //
+
+ private String externsReportFileName = null;
+
+ public File getExternsReport()
+ {
+ return externsReportFileName != null ? new File(externsReportFileName) : null;
+ }
+
+ /**
+ * Prints externs information to the specified output file. This file is an Google Closure Compiler externs file that contains
+ * all of the public and protected APIs in the final SWF file. The file format output
+ * by this command can be used to write a file for input to the {@code -js-compiler-options="--externs <path-to-this-file>"} option.
+ */
+ @Config(advanced = true)
+ @Mapping("externs-report")
+ @Arguments("filename")
+ public void setExternsReport(ConfigurationValue cv, String filename)
+ {
+ this.externsReportFileName = getOutputPath(cv, filename);
+ }
+
+ /**
+ * Support for reflection data output to represent selected config options
+ * that were used when compiling
+ * @return an integer representation of bit flags representing
+ */
+ public int getReflectionFlags() {
+ int ret = 0;
+ final int WITH_DEFAULT_INITIALIZERS = 1;
+ final int HAS_KEEP_AS3_METADATA = 2;
+ final int HAS_KEEP_CODE_WITH_METADATA = 4;
+ final int HAS_EXPORT_PUBLIC_SYMBOLS = 8;
+ final int EXPORT_PROTECTED_SYMBOLS = 16;
+
+ if (getJsDefaultInitializers()) ret |= WITH_DEFAULT_INITIALIZERS;
+ if (getCompilerKeepAs3Metadata().size() > 0) ret |= HAS_KEEP_AS3_METADATA;
+ if (getCompilerKeepCodeWithMetadata().size() > 0) ret |= HAS_KEEP_CODE_WITH_METADATA;
+ if (getExportPublicSymbols()) ret |= HAS_EXPORT_PUBLIC_SYMBOLS;
+ if (getExportProtectedSymbols()) ret |= EXPORT_PROTECTED_SYMBOLS;
+
+ return ret;
+ }
+
+ //
+ // 'inline-constants'
+ //
+
+ private boolean inlineConstants = false;
+
+ public boolean getInlineConstants()
+ {
+ return inlineConstants;
+ }
+
+ @Config
+ @Mapping("inline-constants")
+ public void setInlineConstants(ConfigurationValue cv, boolean value)
+ throws ConfigurationException
+ {
+ inlineConstants = value;
+ }
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/graph/GoogDepsWriter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/graph/GoogDepsWriter.java
index b538f13..7c8d1e1 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/graph/GoogDepsWriter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/graph/GoogDepsWriter.java
@@ -28,6 +28,8 @@
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -37,6 +39,7 @@
import org.apache.royale.compiler.clients.problems.ProblemQuery;
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.common.DependencyTypeSet;
+import org.apache.royale.compiler.config.CompilerDiagnosticsConstants;
import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
import org.apache.royale.compiler.internal.driver.js.JSCompilationUnit;
import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
@@ -44,8 +47,9 @@
import org.apache.royale.compiler.internal.projects.DefinitionPriority;
import org.apache.royale.compiler.internal.projects.DependencyGraph;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.problems.MainDefinitionQNameProblem;
import org.apache.royale.compiler.problems.FileNotFoundProblem;
+import org.apache.royale.compiler.problems.MainDefinitionQNameProblem;
+import org.apache.royale.compiler.problems.UnexpectedExceptionProblem;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.swc.ISWC;
import org.apache.royale.swc.ISWCFileEntry;
@@ -64,12 +68,17 @@
this.moduleOutput = config.getModuleOutput();
this.mainName = mainClassName;
removeCirculars = config.getRemoveCirculars();
+ sourceMaps = config.getSourceMap();
otherPaths = config.getSDKJSLib();
+ verbose = config.isVerbose();
otherPaths.add(new File(outputFolder.getParent(), "royale/Royale/src").getPath());
this.swcs = swcs;
- for (ISWC swc : swcs)
+ if (verbose)
{
- System.out.println("using SWC: " + swc.getSWCFile().getAbsolutePath());
+ for (ISWC swc : swcs)
+ {
+ System.out.println("using SWC: " + swc.getSWCFile().getAbsolutePath());
+ }
}
}
@@ -78,13 +87,15 @@
private String outputFolderPath;
private String mainName;
private List<String> otherPaths;
- private List<String> sourceExternFiles;
private List<ISWC> swcs;
private boolean removeCirculars = false;
+ private boolean sourceMaps = false;
+ private boolean verbose = false;
private ArrayList<GoogDep> dps;
private DependencyGraph graph;
private CompilerProject project;
private ArrayList<String> staticInitializers;
+ private ArrayList<String> staticInitializerOwners;
private HashMap<String, GoogDep> depMap = new HashMap<String,GoogDep>();
private HashMap<String, ICompilationUnit> requireMap = new HashMap<String, ICompilationUnit>();
@@ -96,7 +107,6 @@
{
this.project = project;
this.problems = problems;
- this.sourceExternFiles = sourceExternFiles;
if (dps == null)
{
@@ -143,6 +153,8 @@
return "";
dps = sort();
}
+ ArrayList<String> usedDeps = new ArrayList<String>();
+ ArrayList<String> addedDeps = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
int n = dps.size();
for (int i = n - 1; i >= 0; i--)
@@ -150,29 +162,29 @@
GoogDep gd = dps.get(i);
if (!isGoogClass(gd.className))
{
+ addedDeps.add(gd.filePath);
if (removeCirculars)
{
ArrayList <String> deps = new ArrayList<String>();
- if (gd.fileInfo.impls != null)
- deps.addAll(gd.fileInfo.impls);
- if (gd.fileInfo.staticDeps != null)
- {
- for (String dep : gd.fileInfo.staticDeps)
- {
- if (!deps.contains(dep))
- deps.add(dep);
- }
- }
- sb.append("goog.addDependency('").append(relativePath(gd.filePath)).append("', ['")
- .append(gd.className).append("'], [")
- .append(getDependencies(deps))
- .append("]);\n");
+ computeDeps(deps, gd, usedDeps);
+ sb.append("goog.addDependency('")
+ .append(relativePath(gd.filePath))
+ .append("', ['")
+ .append(gd.className)
+ .append("'], [");
+ appendDependencies(deps, sb);
+ sb.append("]);\n");
}
else
- sb.append("goog.addDependency('").append(relativePath(gd.filePath)).append("', ['")
- .append(gd.className).append("'], [")
- .append(getDependencies(gd.deps))
- .append("]);\n");
+ {
+ sb.append("goog.addDependency('")
+ .append(relativePath(gd.filePath))
+ .append("', ['")
+ .append(gd.className)
+ .append("'], [");
+ appendDependencies(gd.deps, sb);
+ sb.append("]);\n");
+ }
}
}
if (removeCirculars)
@@ -182,19 +194,40 @@
mainDeps.append("goog.addDependency('").append(relativePath(mainDep.filePath)).append("', ['")
.append(mainDep.className).append("'], [");
ArrayList<String> restOfDeps = new ArrayList<String>();
- restOfDeps.addAll(mainDep.deps);
+ for (String dep: mainDep.deps)
+ {
+ if (isGoogProvided(dep))
+ {
+ restOfDeps.add(dep);
+ }
+ }
+ if (mainDep.fileInfo.impls != null)
+ {
+ for (String dep: mainDep.fileInfo.impls)
+ {
+ if (isGoogProvided(dep))
+ {
+ restOfDeps.add(dep);
+ }
+ }
+ }
DependencyTypeSet dependencyTypes = DependencyTypeSet.allOf();
// get the list of all units not referenced by other units
for (GoogDep gd : depMap.values())
{
+ if (usedDeps.contains(gd.className))
+ continue;
+
if (gd.className.equals(mainName))
{
if (gd.fileInfo.impls != null)
{
for (String d : gd.fileInfo.impls)
{
- if (!restOfDeps.contains(d) && !gd.fileInfo.isExtern && !isExternal(d))
+ if (!restOfDeps.contains(d) && !gd.fileInfo.isExtern && isGoogProvided(d) && !usedDeps.contains(d))
+ {
restOfDeps.add(d);
+ }
}
}
continue;
@@ -202,18 +235,23 @@
ICompilationUnit unit = requireMap.get(gd.className);
if (unit == null)
{
- if (!restOfDeps.contains(gd.className) && !gd.fileInfo.isExtern && !isExternal(gd.className))
+ if (!restOfDeps.contains(gd.className) && !gd.fileInfo.isExtern && isGoogProvided(gd.className) && !usedDeps.contains(gd.className))
+ {
restOfDeps.add(gd.className);
+ }
continue;
}
Set<ICompilationUnit> deps = graph.getDirectReverseDependencies(unit, dependencyTypes);
if (deps.size() == 0)
{
- if (!restOfDeps.contains(gd.className) && !gd.fileInfo.isExtern && !isExternal(gd.className))
+ if (!restOfDeps.contains(gd.className) && !gd.fileInfo.isExtern && isGoogProvided(gd.className) && !usedDeps.contains(gd.className))
+ {
restOfDeps.add(gd.className);
+ }
}
}
- mainDeps.append(getDependencies(restOfDeps)).append("]);\n");
+ appendDependencies(restOfDeps, mainDeps);
+ mainDeps.append("]);\n");
sb.insert(0, mainDeps);
sb.insert(0, "// generated by Royale\n");
for (String dep : restOfDeps)
@@ -226,16 +264,43 @@
problems.add(new FileNotFoundProblem(dep));
continue;
}
- sb.append("goog.addDependency('").append(relativePath(gd.filePath)).append("', ['")
- .append(gd.className).append("'], [")
- .append((gd.fileInfo.impls != null) ? getDependencies(gd.fileInfo.impls) : "")
- .append("]);\n");
+ if (addedDeps.contains(gd.filePath))
+ continue;
+ ArrayList<String> deps = new ArrayList<String>();
+ computeDeps(deps, gd, usedDeps);
+ sb.append("goog.addDependency('")
+ .append(relativePath(gd.filePath))
+ .append("', ['")
+ .append(gd.className)
+ .append("'], [");
+ appendDependencies(deps, sb);
+ sb.append("]);\n");
}
addRestOfDeps(mainDep, restOfDeps);
}
return sb.toString();
}
+ private void computeDeps(ArrayList<String> deps, GoogDep gd, ArrayList<String> usedDeps) {
+ if (gd.fileInfo.impls != null)
+ {
+ deps.addAll(gd.fileInfo.impls);
+ for (String dep : gd.fileInfo.impls)
+ if (!usedDeps.contains(dep))
+ usedDeps.add(dep);
+ }
+ if (gd.fileInfo.staticDeps != null)
+ {
+ for (String dep : gd.fileInfo.staticDeps)
+ {
+ if (!deps.contains(dep))
+ deps.add(dep);
+ if (!usedDeps.contains(dep))
+ usedDeps.add(dep);
+ }
+ }
+ }
+
private boolean isGoogClass(String className)
{
return className.startsWith("goog.");
@@ -244,6 +309,7 @@
private boolean buildDB()
{
staticInitializers = new ArrayList<String>();
+ staticInitializerOwners = new ArrayList<String>();
graph = new DependencyGraph();
if (isGoogClass(mainName))
@@ -251,7 +317,7 @@
problems.add(new MainDefinitionQNameProblem("Google Closure Library", mainName));
return false;
}
- if (isExternal(mainName))
+ if (!isGoogProvided(mainName))
{
problems.add(new MainDefinitionQNameProblem("External Libraries", mainName));
return false;
@@ -259,27 +325,48 @@
addDeps(mainName);
return true;
}
-
- public ArrayList<String> additionalHTML = new ArrayList<String>();
- private HashMap<String, GoogDep> visited = new HashMap<String, GoogDep>();
+ private HashMap<String, GoogDep> visited = new HashMap<String, GoogDep>();
+
+ public ArrayList<String> additionalHTML = new ArrayList<String>();
private ArrayList<GoogDep> sort()
{
// first, promote all dependencies of classes used in static initializers to
// the level of static dependencies since their constructors will be
- // run early
- for (String staticClass: staticInitializers)
+ // run early. This may need to be a full transitive walk someday.
+ // This is because we move many goog.requires from the various classes
+ // to the main app when removing circulars. We only keep goog.requires
+ // that Closure Compiler cares about, which are requires for @extends
+ // and @implements. However, as classes required by the application get
+ // loaded, their static initializers will fail if we haven't already goog.required
+ // the classes used by these static initializers, so we have to keep goog.requires
+ // used by these static initializers in the class files.
+ int n = staticInitializers.size();
+ for (int i = 0; i < n; i++)
{
+ String staticClass = staticInitializers.get(i);
+ String staticOwner = staticInitializerOwners.get(i);
GoogDep info = depMap.get(staticClass);
- if (info != null && info.fileInfo != null && info.fileInfo.deps != null)
+ GoogDep ownerInfo = depMap.get(staticOwner);
+ if (info != null && info.fileInfo != null && info.fileInfo.deps != null &&
+ ownerInfo != null && ownerInfo.fileInfo != null)
{
- if (info.fileInfo.staticDeps == null)
- info.fileInfo.staticDeps = new ArrayList<String>();
+ if (ownerInfo.fileInfo.staticDeps == null)
+ ownerInfo.fileInfo.staticDeps = new ArrayList<String>();
for (String dep : info.fileInfo.deps)
{
- if (!info.fileInfo.staticDeps.contains(dep))
- info.fileInfo.staticDeps.add(dep);
+ if (!ownerInfo.fileInfo.staticDeps.contains(dep)
+ && !isGoogClass(dep)
+ && !dep.equals(staticOwner))
+ {
+ ownerInfo.fileInfo.staticDeps.add(dep);
+ if (verbose)
+ {
+ System.out.println(staticClass + " used in static initializer of " + staticOwner + " so make " + dep + " a static dependency");
+ }
+ // all things added here should get added to graph in sortFunction
+ }
}
}
}
@@ -294,7 +381,38 @@
roots.add(mainUnit);
requireMap.remove(mainName);
+ if ((CompilerDiagnosticsConstants.diagnostics & CompilerDiagnosticsConstants.GOOG_DEPS) == CompilerDiagnosticsConstants.GOOG_DEPS)
+ {
+ Collection<ICompilationUnit> units = graph.getCompilationUnits();
+ System.out.println("Contents of graph:");
+ for (ICompilationUnit unit : units)
+ {
+ try {
+ System.out.println(unit.getQualifiedNames().toString());
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
List<ICompilationUnit> order = graph.topologicalSort(requireMap.values());
+ if (graph.lastCircularDependencyException != null)
+ {
+ problems.add(new UnexpectedExceptionProblem(graph.lastCircularDependencyException));
+ }
+ if ((CompilerDiagnosticsConstants.diagnostics & CompilerDiagnosticsConstants.GOOG_DEPS) == CompilerDiagnosticsConstants.GOOG_DEPS)
+ {
+ System.out.println("Contents of graph in order:");
+ for (ICompilationUnit unit : order)
+ {
+ try {
+ System.out.println(unit.getQualifiedNames().toString());
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ }
ArrayList<GoogDep> depsInOrder = new ArrayList<GoogDep>();
for (ICompilationUnit unit : order)
{
@@ -303,13 +421,17 @@
GoogDep dep = depMap.get(name);
if (dep == null)
{
- System.out.println("No GoogDep for " + name);
- //added this to prevent a NullPointerException when the
- //GoogDep is null. -JT
- problems.add(new FileNotFoundProblem(name));
- continue;
+ if (isGoogProvided(name))
+ {
+ System.out.println("No GoogDep for " + name);
+ //added this to prevent a NullPointerException when the
+ //GoogDep is null. -JT
+ problems.add(new FileNotFoundProblem(name));
+ continue;
+ }
}
- depsInOrder.add(dep);
+ else
+ depsInOrder.add(dep);
}
return depsInOrder;
}
@@ -321,16 +443,17 @@
visited.put(current.className, current);
if (removeCirculars)
+ {
removeRequires(current);
- System.out.println("Dependencies calculated for '" + current.className + "'");
+ }
+ if (verbose)
+ {
+ System.out.println("Dependencies calculated for '" + current.className + "'");
+ }
ICompilationUnit unit = null;
if (removeCirculars)
- if (current.fileInfo.deps == null)
- return;
-
- if (removeCirculars)
{
unit = requireMap.get(current.className);
if (unit == null)
@@ -340,24 +463,10 @@
requireMap.put(current.className, unit);
requireMap2.put(unit, current.className);
}
- if (current.fileInfo.staticDeps != null && removeCirculars)
- {
- for (String staticDep : current.fileInfo.staticDeps)
- {
- ICompilationUnit base = requireMap.get(staticDep);
- if (base == null)
- {
- base = new JSCompilationUnit(project, staticDep, DefinitionPriority.BasePriority.SOURCE_LIST, staticDep);
- graph.addCompilationUnit(base);
- requireMap.put(staticDep, base);
- requireMap2.put(base, staticDep);
- }
- System.out.println(current.className + " static initialization depends on " + staticDep);
- graph.addDependency(unit, base, DependencyType.INHERITANCE);
-
- }
- }
+ if (current.fileInfo.deps == null)
+ return;
}
+
ArrayList<String> impls = current.fileInfo.impls != null ? current.fileInfo.impls : null;
if (impls != null)
{
@@ -378,7 +487,10 @@
requireMap.put(className, base);
requireMap2.put(base, className);
}
- System.out.println(current.className + " depends on " + className);
+ if (verbose)
+ {
+ System.out.println(current.className + " depends on " + className);
+ }
graph.addDependency(unit, base, DependencyType.INHERITANCE);
}
if (!visited.containsKey(className))
@@ -389,10 +501,32 @@
}
}
}
+ if (removeCirculars)
+ {
+ if (current.fileInfo.staticDeps != null && removeCirculars)
+ {
+ for (String staticDep : current.fileInfo.staticDeps)
+ {
+ ICompilationUnit base = requireMap.get(staticDep);
+ if (base == null)
+ {
+ base = new JSCompilationUnit(project, staticDep, DefinitionPriority.BasePriority.SOURCE_LIST, staticDep);
+ graph.addCompilationUnit(base);
+ requireMap.put(staticDep, base);
+ requireMap2.put(base, staticDep);
+ }
+ if (verbose)
+ {
+ System.out.println(current.className + " static initialization depends on " + staticDep);
+ }
+ graph.addDependency(unit, base, DependencyType.INHERITANCE);
+ }
+ }
+ }
ArrayList<String> deps = current.deps;
for (String className : deps)
{
- if (!isGoogClass(className))
+ if (!isGoogClass(className) && isGoogProvided(className))
{
GoogDep gd = depMap.get(className);
if (gd == null)
@@ -414,31 +548,62 @@
List<String> fileLines;
try {
File mainFile = new File(main.filePath);
- fileLines = Files.readLines(mainFile, Charset.defaultCharset());
+ fileLines = Files.readLines(mainFile, Charset.forName("utf8"));
SourceMapConsumerV3 sourceMapConsumer = null;
- File sourceMapFile = new File(main.filePath + ".map");
- if (sourceMapFile.exists())
+ File sourceMapFile = null;
+ if (sourceMaps)
{
- String sourceMapContents = FileUtils.readFileToString(sourceMapFile);
- sourceMapConsumer = new SourceMapConsumerV3();
- try
+ sourceMapFile = new File(main.filePath + ".map");
+ if (sourceMapFile.exists())
{
- sourceMapConsumer.parse(sourceMapContents);
- }
- catch(SourceMapParseException e)
- {
- sourceMapConsumer = null;
+ String sourceMapContents = FileUtils.readFileToString(sourceMapFile, Charset.forName("utf8"));
+ sourceMapConsumer = new SourceMapConsumerV3();
+ try
+ {
+ sourceMapConsumer.parse(sourceMapContents);
+ }
+ catch(SourceMapParseException e)
+ {
+ sourceMapConsumer = null;
+ }
}
}
+ // first scan requires in case this is a module and some have been externed
+ int j = main.fileInfo.googProvideLine + 1;
+ while (j < fileLines.size() && !fileLines.get(j).contains(JSGoogEmitterTokens.GOOG_REQUIRE.getToken()))
+ {
+ j++;
+ }
+ while (j < fileLines.size() && fileLines.get(j).contains(JSGoogEmitterTokens.GOOG_REQUIRE.getToken()))
+ {
+ String line = fileLines.get(j);
+ int c = line.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken());
+ int c2 = line.indexOf(")");
+ String s = line.substring(c + 14, c2 - 1);
+ if (!isGoogProvided(s))
+ {
+ fileLines.remove(j);
+ sourceMapConsumer = removeLineFromSourceMap(sourceMapConsumer, mainFile.getName(), j);
+ }
+ else
+ {
+ j++;
+ }
+ }
+
int n = restOfDeps.size();
for (int i = n - 1; i >= 0; i--)
{
String dep = restOfDeps.get(i);
- //if (!main.deps.contains(dep))
- fileLines.add(main.fileInfo.googProvideLine + 1, JSGoogEmitterTokens.GOOG_REQUIRE.getToken() + "('" + dep + "');");
- sourceMapConsumer = addLineToSourceMap(sourceMapConsumer, mainFile.getName(), main.fileInfo.googProvideLine + 1);
+ StringBuilder lineBuilder = new StringBuilder();
+ lineBuilder.append(JSGoogEmitterTokens.GOOG_REQUIRE.getToken())
+ .append("('")
+ .append(dep)
+ .append("');");
+ fileLines.add(main.fileInfo.googProvideLine + 1, lineBuilder.toString());
+ sourceMapConsumer = addLineToSourceMap(sourceMapConsumer, mainFile.getName(), main.fileInfo.googProvideLine + 1);
}
PrintWriter out = new PrintWriter(new FileWriter(mainFile));
@@ -446,7 +611,7 @@
{
out.println(s);
}
- out.close();
+ out.close();
if (sourceMapConsumer != null)
{
@@ -464,8 +629,10 @@
private void addDeps(String className)
{
- if (depMap.containsKey(className) || isGoogClass(className) || isExternal(className))
+ if (depMap.containsKey(className) || isGoogClass(className) || !isGoogProvided(className))
+ {
return;
+ }
// build goog dependency list
GoogDep gd = new GoogDep();
@@ -478,7 +645,7 @@
depMap.put(gd.className, gd);
List<String> fileLines;
try {
- fileLines = Files.readLines(new File(gd.filePath), Charset.defaultCharset());
+ fileLines = Files.readLines(new File(gd.filePath), Charset.forName("utf8"));
FileInfo fi = getFileInfo(fileLines, className);
gd.fileInfo = fi;
} catch (IOException e) {
@@ -504,6 +671,19 @@
gd.fileInfo.provides.contains(dep)) continue;
addDeps(dep);
}
+ if (gd.fileInfo.staticDeps != null)
+ {
+ for (String dep : gd.fileInfo.staticDeps)
+ {
+ if (!gd.deps.contains(dep))
+ {
+ gd.deps.add(dep);
+ if (gd.fileInfo.provides != null &&
+ gd.fileInfo.provides.contains(dep)) continue;
+ addDeps(dep);
+ }
+ }
+ }
}
}
@@ -516,22 +696,26 @@
{
gd = depMap.get(className);
File depFile = new File(gd.filePath);
- List<String> fileLines = Files.readLines(depFile, Charset.defaultCharset());
+ List<String> fileLines = Files.readLines(depFile, Charset.forName("utf8"));
ArrayList<String> finalLines = new ArrayList<String>();
SourceMapConsumerV3 sourceMapConsumer = null;
- File sourceMapFile = new File(gd.filePath + ".map");
- if (sourceMapFile.exists())
+ File sourceMapFile = null;
+ if (sourceMaps)
{
- String sourceMapContents = FileUtils.readFileToString(sourceMapFile);
- sourceMapConsumer = new SourceMapConsumerV3();
- try
+ sourceMapFile = new File(gd.filePath + ".map");
+ if (sourceMapFile.exists())
{
- sourceMapConsumer.parse(sourceMapContents);
- }
- catch(SourceMapParseException e)
- {
- sourceMapConsumer = null;
+ String sourceMapContents = FileUtils.readFileToString(sourceMapFile, Charset.forName("utf8"));
+ sourceMapConsumer = new SourceMapConsumerV3();
+ try
+ {
+ sourceMapConsumer.parse(sourceMapContents);
+ }
+ catch(SourceMapParseException e)
+ {
+ sourceMapConsumer = null;
+ }
}
}
@@ -539,8 +723,11 @@
StringBuilder sb = new StringBuilder();
sb.append(JSGoogEmitterTokens.ROYALE_DEPENDENCY_LIST.getToken());
+ ArrayList<String> writtenRequires = new ArrayList<String>();
+// int staticDepsLine = -1;
+ int lastRequireLine = -1;
FileInfo fi = gd.fileInfo;
- int suppressCount = 0;
+// int suppressCount = 0;
int i = 0;
int stopLine = fi.constructorLine;
if (fi.constructorLine == -1) // standalone functions
@@ -552,18 +739,26 @@
int c = line.indexOf(JSGoogEmitterTokens.ROYALE_DEPENDENCY_LIST.getToken());
if (c > -1)
return; // already been processed
+// c = line.indexOf(JSGoogEmitterTokens.ROYALE_STATIC_DEPENDENCY_LIST.getToken());
+// if (c > -1)
+// staticDepsLine = i;
c = line.indexOf(JSGoogEmitterTokens.GOOG_REQUIRE.getToken());
if (c > -1)
{
+ lastRequireLine = i;
int c2 = line.indexOf(")");
String s = line.substring(c + 14, c2 - 1);
- if ((gd.fileInfo.impls == null || !gd.fileInfo.impls.contains(s)) &&
- (gd.fileInfo.staticDeps == null || !gd.fileInfo.staticDeps.contains(s)))
+ if (((gd.fileInfo.impls == null || !gd.fileInfo.impls.contains(s)) &&
+ (gd.fileInfo.staticDeps == null || !gd.fileInfo.staticDeps.contains(s))) ||
+ !isGoogProvided(s))
{
// don't remove the require if some class needs it at static initialization
// time
- suppressCount++;
- System.out.println(gd.filePath + " removing require: " + s);
+// suppressCount++;
+ if (verbose)
+ {
+ System.out.println(gd.filePath + " removing require: " + s);
+ }
if (!firstDependency)
sb.append(",");
sb.append(s);
@@ -571,11 +766,40 @@
sourceMapConsumer = removeLineFromSourceMap(sourceMapConsumer, depFile.getName(), finalLines.size());
continue;
}
+ else
+ {
+ writtenRequires.add(s);
+ }
}
}
- finalLines.add(line);
+ finalLines.add(line);
+ //no need to call addLineToSourceMap here because we're
+ //populating finalLines for the first time
i++;
}
+ // add any static deps not already listed that were added by static initializers;
+ if (gd.fileInfo.staticDeps != null)
+ {
+ if (lastRequireLine == -1)
+ lastRequireLine = gd.fileInfo.googProvideLine + 1;
+ for (String dep : gd.fileInfo.staticDeps)
+ {
+ if (!writtenRequires.contains(dep) && isGoogProvided(dep))
+ {
+ StringBuilder lineBuilder = new StringBuilder();
+ lineBuilder.append(JSGoogEmitterTokens.GOOG_REQUIRE.getToken())
+ .append("('")
+ .append(dep)
+ .append("');");
+ finalLines.add(lastRequireLine++, lineBuilder.toString());
+ sourceMapConsumer = addLineToSourceMap(sourceMapConsumer, new File(gd.filePath).getName(), lastRequireLine);
+ if (verbose)
+ {
+ System.out.println("adding require for static dependency " + dep + " to " + className);
+ }
+ }
+ }
+ }
//if (suppressCount > 0)
//{
if (fi.suppressLine > 0)
@@ -655,7 +879,7 @@
sourceMapConsumer = addLineToSourceMap(sourceMapConsumer, depFile.getName(), gd.fileInfo.googProvideLine + 1);
PrintWriter out = new PrintWriter(new FileWriter(depFile));
- for (String s : finalLines)
+ for (String s : finalLines)
{
out.println(s);
}
@@ -708,6 +932,7 @@
{
final SourceMapGeneratorV3 generator = new SourceMapGeneratorV3();
final SourceMapEntryCounter counter = new SourceMapEntryCounter();
+ generator.setSourceRoot(consumer.getSourceRoot());
consumer.visitMappings(counter);
consumer.visitMappings(new SourceMapConsumerV3.EntryVisitor()
{
@@ -778,6 +1003,7 @@
}
final SourceMapGeneratorV3 generator = new SourceMapGeneratorV3();
final SourceMapEntryCounter counter = new SourceMapEntryCounter();
+ generator.setSourceRoot(consumer.getSourceRoot());
consumer.visitMappings(counter);
consumer.visitMappings(new SourceMapConsumerV3.EntryVisitor()
{
@@ -816,6 +1042,7 @@
}
final SourceMapGeneratorV3 generator = new SourceMapGeneratorV3();
final SourceMapEntryCounter counter = new SourceMapEntryCounter();
+ generator.setSourceRoot(consumer.getSourceRoot());
consumer.visitMappings(counter);
consumer.visitMappings(new SourceMapConsumerV3.EntryVisitor()
{
@@ -863,7 +1090,7 @@
fi.constructorLine = -1;
fi.suppressLine = -1;
fi.fileoverviewLine = -1;
- fi.googProvideLine = -1;
+ fi.googProvideLine = -1;
boolean inInjectHTML = false;
for (int i = 0; i < n; i++)
{
@@ -872,7 +1099,7 @@
int c = line.indexOf("*/");
if (c > -1 && constructorCount > 0 && constructorCount == numProvides)
{
- return fi;
+ break;
}
else
{
@@ -943,7 +1170,8 @@
fi.impls = new ArrayList<String>();
c2 = line.indexOf("}", c);
String impl = line.substring(c + 13, c2);
- fi.impls.add(impl);
+ if (!fi.impls.contains(impl) && !impl.contentEquals(className))
+ fi.impls.add(impl);
if (impl.equals("org.apache.royale.core.ICSSImpl"))
needCSS = true;
}
@@ -956,7 +1184,8 @@
fi.impls = new ArrayList<String>();
c2 = line.indexOf("}", c);
String impl = line.substring(c + 10, c2);
- fi.impls.add(impl);
+ if (!fi.impls.contains(impl) && !impl.contentEquals(className))
+ fi.impls.add(impl);
}
else
{
@@ -974,6 +1203,7 @@
if (staticDep.equals(className))
continue;
staticInitializers.add(staticDep);
+ staticInitializerOwners.add(className);
}
}
else
@@ -994,9 +1224,9 @@
fi.deps = new ArrayList<String>();
if (line.length() > 2) // don't add blank or space if no deps
fi.deps.addAll(Arrays.asList(line.split(",")));
- fi.depsLine = i;
+// fi.depsLine = i;
}
- else if (fi.depsLine == 0)
+ else /* if (fi.depsLine == 0) */
{
token = JSGoogEmitterTokens.GOOG_REQUIRE.getToken();
c = line.indexOf(token);
@@ -1020,6 +1250,14 @@
}
}
}
+ if (fi.deps != null)
+ {
+ Collections.sort(fi.deps);
+ }
+ if (fi.staticDeps != null)
+ {
+ Collections.sort(fi.staticDeps);
+ }
return fi;
}
@@ -1080,7 +1318,10 @@
File.separator + assetFileName);
FileUtils.copyFile(assetFile, destFile);
- System.out.println("Copied assets of the '" + nameOfClass + "' class");
+ if (verbose)
+ {
+ System.out.println("Copied assets of the '" + nameOfClass + "' class");
+ }
}
}
}
@@ -1092,21 +1333,9 @@
}
}
- String fwdClassPath = className.replace(".", "/");
- String bckClassPath = className.replace(".", "\\");
for (ISWC swc : swcs)
{
- ISWCFileEntry fileEntry = swc.getFile("js/src/" + fwdClassPath + ".js");
- if (fileEntry == null)
- fileEntry = swc.getFile("js/out/" + fwdClassPath + ".js");
- if (fileEntry == null)
- fileEntry = swc.getFile("js/src/" + bckClassPath + ".js");
- if (fileEntry == null)
- fileEntry = swc.getFile("js/out/" + bckClassPath + ".js");
- if (fileEntry == null)
- fileEntry = swc.getFile("js\\src\\" + bckClassPath + ".js");
- if (fileEntry == null)
- fileEntry = swc.getFile("js\\out\\" + bckClassPath + ".js");
+ ISWCFileEntry fileEntry = getFileEntry(swc, className);
if (fileEntry != null)
{
fn = outputFolderPath + File.separator + classPath + ".js";
@@ -1123,7 +1352,28 @@
}
outStream.flush();
outStream.close();
- inStream.close();
+ inStream.close();
+
+ //if source maps requested, copy from the swc, if available
+ if (sourceMaps)
+ {
+ ISWCFileEntry sourceMapFileEntry = getFileEntry(swc, className, ".js.map");
+ if (sourceMapFileEntry != null)
+ {
+ String sourceMapFn = outputFolderPath + File.separator + classPath + ".js.map";
+ File sourceMapDestFile = new File(sourceMapFn);
+ inStream = sourceMapFileEntry.createInputStream();
+ outStream = FileUtils.openOutputStream(sourceMapDestFile);
+ b = new byte[1024 * 1024];
+ while ((bytes_read = inStream.read(b)) != -1)
+ {
+ outStream.write(b, 0, bytes_read);
+ }
+ outStream.flush();
+ outStream.close();
+ inStream.close();
+ }
+ }
// (erikdebruin) copy class assets files
if (className.contains("org.apache.royale"))
@@ -1150,7 +1400,10 @@
inStream.close();
outStream.flush();
outStream.close();
- System.out.println("Copied asset " + assetName);
+ if (verbose)
+ {
+ System.out.println("Copied asset " + assetName);
+ }
}
}
}
@@ -1165,6 +1418,29 @@
problems.add(new FileNotFoundProblem(className));
return "";
}
+
+ private ISWCFileEntry getFileEntry(ISWC swc, String className)
+ {
+ return getFileEntry(swc, className, ".js");
+ }
+
+ private ISWCFileEntry getFileEntry(ISWC swc, String className, String extension)
+ {
+ String fwdClassPath = className.replace(".", "/");
+ String bckClassPath = className.replace(".", "\\");
+ ISWCFileEntry fileEntry = swc.getFile("js/src/" + fwdClassPath + extension);
+ if (fileEntry == null)
+ fileEntry = swc.getFile("js/out/" + fwdClassPath + extension);
+ if (fileEntry == null)
+ fileEntry = swc.getFile("js/src/" + bckClassPath + extension);
+ if (fileEntry == null)
+ fileEntry = swc.getFile("js/out/" + bckClassPath + extension);
+ if (fileEntry == null)
+ fileEntry = swc.getFile("js\\src\\" + bckClassPath + extension);
+ if (fileEntry == null)
+ fileEntry = swc.getFile("js\\out\\" + bckClassPath + extension);
+ return fileEntry;
+ }
/*
private ArrayList<String> getDirectDependencies(String fn)
@@ -1225,18 +1501,20 @@
{
}
- private String getDependencies(ArrayList<String> deps)
+ private void appendDependencies(ArrayList<String> deps, StringBuilder builder)
{
- String s = "";
+ boolean hasDeps = false;
for (String dep : deps)
{
- if (s.length() > 0)
+ if (hasDeps)
{
- s += ", ";
+ builder.append(", ");
}
- s += "'" + dep + "'";
+ builder.append("'");
+ builder.append(dep);
+ builder.append("'");
+ hasDeps = true;
}
- return s;
}
String relativePath(String path)
@@ -1268,6 +1546,11 @@
return path;
}
+ boolean isGoogProvided(String className)
+ {
+ return ((RoyaleJSProject)project).isGoogProvided(className);
+ }
+
boolean isExternal(String className)
{
ICompilationUnit cu = project.resolveQNameToCompilationUnit(className);
@@ -1292,7 +1575,7 @@
public ArrayList<String> staticDeps;
public ArrayList<String> provides;
public int constructorLine;
- public int depsLine;
+// public int depsLine;
public int suppressLine;
public int fileoverviewLine;
public int googProvideLine;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java
index 2c2b52c..8bf9044 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleJSProject.java
@@ -18,6 +18,7 @@
*/
package org.apache.royale.compiler.internal.projects;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -32,12 +33,14 @@
import org.apache.royale.compiler.asdoc.royale.ASDocComment;
import org.apache.royale.compiler.clients.JSConfiguration;
import org.apache.royale.compiler.common.DependencyType;
+import org.apache.royale.compiler.common.DependencyTypeSet;
import org.apache.royale.compiler.config.CompilerDiagnosticsConstants;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.config.Configurator;
import org.apache.royale.compiler.css.ICSSMediaQueryCondition;
import org.apache.royale.compiler.css.ICSSRule;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
@@ -58,14 +61,15 @@
import org.apache.royale.compiler.internal.tree.mxml.MXMLFileNode;
import org.apache.royale.compiler.internal.units.SWCCompilationUnit;
import org.apache.royale.compiler.internal.workspaces.Workspace;
-import org.apache.royale.compiler.mxml.IMXMLTypeConstants;
import org.apache.royale.compiler.targets.ITargetSettings;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IClassNode;
import org.apache.royale.compiler.tree.as.IDefinitionNode;
+import org.apache.royale.compiler.tree.as.IDocumentableDefinitionNode;
import org.apache.royale.compiler.tree.as.IInterfaceNode;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.compiler.units.ICompilationUnit.UnitType;
+import org.apache.royale.swc.ISWC;
import com.google.common.collect.ImmutableList;
@@ -100,6 +104,24 @@
public ICompilationUnit mainCU;
@Override
+ public void addDependency(ICompilationUnit from, ICompilationUnit to, DependencyTypeSet dt, String qname)
+ {
+ if (to.getCompilationUnitType() == UnitType.SWC_UNIT)
+ {
+ List<IDefinition> dp = to.getDefinitionPromises();
+ if(dp.size() > 0)
+ {
+ if (!isGoogProvided(dp.get(0).getQualifiedName()))
+ {
+ SWCCompilationUnit swcUnit = (SWCCompilationUnit) to;
+ swcExterns.add(swcUnit.getSWC());
+ }
+ }
+ }
+ super.addDependency(from, to, dt, qname);
+ }
+
+ @Override
public void addDependency(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
@@ -110,24 +132,34 @@
IDefinition def = dp.get(0);
IDefinition actualDef = ((DefinitionPromise) def).getActualDefinition();
- IDefinitionNode defNode = actualDef != null ? actualDef.getNode() : null;
- if (to.getCompilationUnitType() == UnitType.AS_UNIT && (defNode instanceof IClassNode || defNode instanceof IInterfaceNode))
+ if (to.getCompilationUnitType() == UnitType.AS_UNIT)
{
- String defname = def.getQualifiedName();
- IASDocComment asDoc = (defNode instanceof IClassNode) ?
- (IASDocComment) ((IClassNode)defNode).getASDocComment() :
- (IASDocComment) ((IInterfaceNode)defNode).getASDocComment();
- if (asDoc != null && (asDoc instanceof ASDocComment))
- {
- String asDocString = ((ASDocComment)asDoc).commentNoEnd();
- if (asDocString.contains(JSRoyaleEmitterTokens.EXTERNS.getToken()))
- {
- if (!sourceExterns.contains(defname))
- sourceExterns.add(defname);
- }
- }
+ IDefinitionNode defNode = actualDef != null ? actualDef.getNode() : null;
+ if (defNode instanceof IClassNode || defNode instanceof IInterfaceNode)
+ {
+ String defname = def.getQualifiedName();
+ IASDocComment asDoc = (defNode instanceof IClassNode) ?
+ (IASDocComment) ((IClassNode)defNode).getASDocComment() :
+ (IASDocComment) ((IInterfaceNode)defNode).getASDocComment();
+ if (asDoc != null && (asDoc instanceof ASDocComment))
+ {
+ String asDocString = ((ASDocComment)asDoc).commentNoEnd();
+ if (asDocString.contains(JSRoyaleEmitterTokens.EXTERNS.getToken()))
+ {
+ if (!sourceExterns.contains(defname))
+ sourceExterns.add(defname);
+ }
+ }
+ }
}
- // IDefinition def = to.getDefinitionPromises().get(0);
+ if (to.getCompilationUnitType() == UnitType.SWC_UNIT)
+ {
+ if (!isGoogProvided(def.getQualifiedName()))
+ {
+ SWCCompilationUnit swcUnit = (SWCCompilationUnit) to;
+ swcExterns.add(swcUnit.getSWC());
+ }
+ }
boolean isInterface = (actualDef instanceof InterfaceDefinition) && (dt == DependencyType.INHERITANCE);
if (!isInterface)
{
@@ -160,7 +192,7 @@
super.addDependency(from, to, dt, qname);
}
- private synchronized void updateRequiresMap(ICompilationUnit from, ICompilationUnit to,
+ private synchronized void updateRequiresMap(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
HashMap<String, DependencyType> reqs;
@@ -176,19 +208,23 @@
// inheritance is important so remember it
if (reqs.get(qname) != DependencyType.INHERITANCE)
{
- if (!isExternalLinkage(to))
+ if (isGoogProvided(qname))
+ {
reqs.put(qname, dt);
+ }
}
}
- else if (!isExternalLinkage(to) || qname.equals("Namespace"))
+ else if (isGoogProvided(qname) || qname.equals("Namespace"))
{
if (qname.equals("XML"))
+ {
needXML = true;
+ }
reqs.put(qname, dt);
- }
+ }
}
- private synchronized void updateJSModulesMap(ICompilationUnit from, ICompilationUnit to,
+ private synchronized void updateJSModulesMap(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
HashMap<String, DependencyType> reqs;
@@ -216,7 +252,7 @@
}
}
- private synchronized void updateInterfacesMap(ICompilationUnit from, ICompilationUnit to,
+ private synchronized void updateInterfacesMap(ICompilationUnit from, ICompilationUnit to,
DependencyType dt, String qname)
{
HashMap<String, String> interfacesArr;
@@ -232,10 +268,13 @@
if (!interfacesArr.containsKey(qname))
{
- if (!isExternalLinkage(to))
- interfacesArr.put(qname, qname);
+ if (isGoogProvided(qname))
+ {
+ interfacesArr.put(qname, qname);
+ }
}
}
+
public boolean needLanguage;
public boolean needCSS;
public boolean needXML;
@@ -245,6 +284,9 @@
// definitions that had @externs in the source
public ArrayList<String> sourceExterns = new ArrayList<String>();
+
+ // swcs that contain referenced externs
+ public Set<ISWC> swcExterns = new HashSet<ISWC>();
// definitions that should be considered external linkage
public Collection<String> unitTestExterns;
@@ -270,6 +312,65 @@
return null;
}
+ public boolean isExterns(String qname)
+ {
+ ICompilationUnit cu = resolveQNameToCompilationUnit(qname);
+ if (cu == null)
+ {
+ return false;
+ }
+ if (cu.getCompilationUnitType().equals(ICompilationUnit.UnitType.SWC_UNIT))
+ {
+ return !isGoogProvided(qname);
+ }
+ else if (!cu.getCompilationUnitType().equals(ICompilationUnit.UnitType.AS_UNIT))
+ {
+ return false;
+ }
+
+ IDefinition def = resolveQNameToDefinition(qname);
+ if (def == null)
+ {
+ return false;
+ }
+
+ IDefinitionNode node = def.getNode();
+ if (!(node instanceof IDocumentableDefinitionNode))
+ {
+ return false;
+ }
+
+ IDocumentableDefinitionNode docNode = (IDocumentableDefinitionNode) node;
+ IASDocComment comment = docNode.getASDocComment();
+ if (!(comment instanceof ASDocComment))
+ {
+ return false;
+ }
+ ASDocComment royaleComment = (ASDocComment) comment;
+ return royaleComment.commentNoEnd().contains(JSRoyaleEmitterTokens.EXTERNS.getToken());
+ }
+
+ public boolean isGoogProvided(String qname)
+ {
+ ICompilationUnit cu = resolveQNameToCompilationUnit(qname);
+ if (cu == null)
+ {
+ //TODO: maybe this this should be false because we can't actually
+ //check whether it's a goog.provide() object or not
+ return true;
+ }
+
+ if (cu.getCompilationUnitType().equals(ICompilationUnit.UnitType.SWC_UNIT))
+ {
+ SWCCompilationUnit swcUnit = (SWCCompilationUnit) cu;
+ ISWC swc = swcUnit.getSWC();
+ String qnameFilePath = "js/out/" + qname.replace('.', '/') + ".js";
+ return swc.getFile(qnameFilePath) != null;
+ }
+
+ return !isExterns(qname);
+ }
+
public boolean isExternalLinkage(ICompilationUnit cu)
{
if (linkageChecker == null)
@@ -298,7 +399,11 @@
try {
qnames = cu.getQualifiedNames();
String qname = qnames.get(0);
- if (qname.equals("QName") || qname.equals("XML") || qname.equals("XMLList"))
+ // if compiling against airglobal/playerglobal, we have to keep QName, XML, XMLList from being seens
+ // as external otherwise theJS implementations won't get added to the output. But if the definitions
+ // come from XML.SWC assume the linkage is right in case these files get excluded from modules
+ if ((cu.getAbsoluteFilename().contains("airglobal") || cu.getAbsoluteFilename().contains("playerglobal")) &&
+ (qname.equals("QName") || qname.equals("XML") || qname.equals("XMLList")))
return false;
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
@@ -523,6 +628,15 @@
}
return false;
}
+
+ @Override
+ public boolean isParameterCountMismatchAllowed(IFunctionDefinition func,
+ int formalCount, int actualCount) {
+ if ((func.getBaseName().equals("int") || func.getBaseName().equals("uint")) && func.isConstructor()) {
+ if (actualCount == 1) return true;
+ }
+ return super.isParameterCountMismatchAllowed(func, formalCount, actualCount);
+ }
/**
* List of compiler defines so it can be overridden
@@ -534,4 +648,23 @@
return list;
}
+
+ @Override
+ public File getLinkReport(Configuration config) {
+ File f = config.getLinkReport();
+ if (f != null)
+ {
+ String baseName = f.getName();
+ String suffix = "";
+ int c = baseName.indexOf(".");
+ if (c != -1)
+ {
+ suffix = baseName.substring(c);
+ baseName = baseName.substring(0, c);
+ }
+ baseName += "-js" + suffix;
+ f = new File(f.getParentFile(), baseName);
+ }
+ return f;
+ }
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/JSTarget.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/JSTarget.java
index 1297aa1..2525bd8 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/JSTarget.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/JSTarget.java
@@ -149,7 +149,7 @@
// }
// }
//
- // createLinkReport(problems);
+ createLinkReport(problems);
return application;
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleJSTarget.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleJSTarget.java
index 22cddfd..0fea71d 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleJSTarget.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleJSTarget.java
@@ -28,11 +28,13 @@
import java.util.Set;
import java.util.TreeSet;
+import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.css.ICSSDocument;
import org.apache.royale.compiler.css.ICSSManager;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.css.semantics.ActivatedStyleSheets;
import org.apache.royale.compiler.internal.driver.js.royale.JSCSSCompilationSession;
+import org.apache.royale.compiler.internal.projects.DependencyGraph;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.units.SWCCompilationUnit;
import org.apache.royale.compiler.problems.FileNotFoundProblem;
@@ -147,7 +149,6 @@
{
JSCSSCompilationSession cssCompilationSession = (JSCSSCompilationSession) royaleProject.getCSSCompilationSession();
cssCompilationSession.setKeepAllTypeSelectors(targetSettings.keepAllTypeSelectors());
- cssCompilationSession.setExcludeDefaultsCSSFiles(targetSettings.getExcludeDefaultsCSSFiles());
// Performance heuristic: let's start compilation on all of the compilation
// units we know about up front. This is particularly useful on SWC projects where
@@ -234,6 +235,14 @@
// If there's more dependencies introduced by CSS, the loop continues.
done = !allCompilationUnitsInTarget.addAll(cssDependencies);
+ if (done)
+ {
+ DependencyGraph graph = royaleProject.getDependencyGraph();
+ for (ICompilationUnit cu : cssDependencies)
+ {
+ graph.addDependency(mainCU, cu, DependencyType.EXPRESSION);
+ }
+ }
}
// add to front so user specified css overrides defaults
@@ -302,7 +311,9 @@
final File swcFile = new File(compilationUnit.getAbsoluteFilename());
final ICSSDocument defaultCSS = cssManager.getDefaultCSS(swcFile);
if (defaultCSS != null)
+ {
result.put(defaultCSS, swcFile);
+ }
}
}
return result;
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java
index 2207985..ae3d614 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/JSClosureCompilerWrapper.java
@@ -19,19 +19,13 @@
package org.apache.royale.compiler.utils;
-import java.io.BufferedReader;
import java.io.File;
-import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
-import java.util.Set;
import java.util.logging.Level;
import com.google.javascript.jscomp.CheckLevel;
@@ -42,9 +36,11 @@
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.jscomp.DependencyOptions;
+import com.google.javascript.jscomp.DependencyOptions.DependencyMode;
import com.google.javascript.jscomp.DiagnosticGroups;
+import com.google.javascript.jscomp.Result;
+import com.google.javascript.jscomp.RoyaleClosurePassConfig;
import com.google.javascript.jscomp.RoyaleDiagnosticGroups;
-import com.google.javascript.jscomp.ModuleIdentifier;
import com.google.javascript.jscomp.ShowByPathWarningsGuard;
import com.google.javascript.jscomp.SourceFile;
import com.google.javascript.jscomp.SourceMap;
@@ -54,11 +50,14 @@
public class JSClosureCompilerWrapper
{
- public JSClosureCompilerWrapper(List<String> args)
+ public JSClosureCompilerWrapper(List<String> args) throws IOException
{
Compiler.setLoggingLevel(Level.INFO);
compiler_ = new Compiler();
+ jsSourceFiles_ = new ArrayList<SourceFile>();
+ jsExternsFiles_ = new ArrayList<SourceFile>();
+
filterOptions(args);
ArrayList<String> splitArgs = new ArrayList<String>();
@@ -76,9 +75,6 @@
splitArgs.toArray(stringArgs);
options_ = new CompilerOptionsParser(stringArgs).getOptions();
- jsSourceFiles_ = new ArrayList<SourceFile>();
- jsExternsFiles_ = new ArrayList<SourceFile>();
-
initOptions(args);
initExterns();
@@ -93,8 +89,8 @@
private String variableMapInputPath;
private String propertyMapInputPath;
private boolean skipTypeInference;
- private Set<String> provideds;
private boolean sourceMap = false;
+ private boolean verbose = false;
public String targetFilePath;
@@ -118,22 +114,25 @@
jsSourceFiles_.add(file);
}
- public void setProvideds(Set<String> set)
- {
- provideds = set;
- }
-
public void setSourceMap(boolean enabled)
{
sourceMap = enabled;
}
-
- public void compile()
+
+ public void setVerbose(boolean enabled)
{
- System.out.println("list of source files");
- for (SourceFile file : jsSourceFiles_)
- System.out.println(file.getName());
- System.out.println("end of list of source files");
+ verbose = enabled;
+ }
+
+ public boolean compile()
+ {
+ if (verbose)
+ {
+ System.out.println("list of source files");
+ for (SourceFile file : jsSourceFiles_)
+ System.out.println(file.getName());
+ System.out.println("end of list of source files");
+ }
File outputFolder = new File(targetFilePath).getParentFile();
if (variableMapInputPath != null)
{
@@ -141,8 +140,6 @@
try {
VariableMap map = VariableMap.load(inputFile.getAbsolutePath());
CompilerMapFetcher.setVariableMap(options_, map);
- Set<String> usedVars = getUsedVars(inputFile);
- compiler_.addExportedNames(usedVars);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
@@ -161,9 +158,11 @@
}
}
-
- compiler_.compile(jsExternsFiles_, jsSourceFiles_, options_);
-
+ compiler_.setPassConfig(new RoyaleClosurePassConfig(options_,
+ jsSourceFiles_.get(jsSourceFiles_.size() - 1).getName(),
+ variableMapInputPath == null ? null : new File(outputFolder, variableMapInputPath)));
+ Result result = compiler_.compile(jsExternsFiles_, jsSourceFiles_, options_);
+
try
{
FileWriter targetFile = new FileWriter(targetFilePath);
@@ -223,65 +222,8 @@
System.err.println("Error message: " + message.toString());
}
*/
- }
-
- private Set<String> getUsedVars(File file)
- {
- HashMap<String, String> vars = new HashMap<String, String>();
-
- try
- {
- BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF8"));
-
- String line = in.readLine();
-
- while (line != null)
- {
- int c = line.indexOf(":");
- if (c != -1)
- {
- String name = line.substring(0, c);
-
- String var = line.substring(c + 1).trim();
- vars.put(name, var);
- }
- line = in.readLine();
- }
-
- // remove all vars that are used by this module
- // that way they will re-use the names in the
- // loader
- for (String name : provideds)
- {
- name = name.replace('.', '$');
- Set<String> keys = vars.keySet();
- ArrayList<String> remKeys = new ArrayList<String>();
- for (String key : keys)
- {
- if (key.contains(name))
- {
- remKeys.add(key);
- }
- }
- for (String key : remKeys)
- {
- vars.remove(key);
- }
- }
- in.close();
- }
- catch (Exception e)
- {
- // nothing to see, move along...
- }
- HashSet<String> usedVars = new HashSet<String>();
- Set<String> keys = vars.keySet();
- for (String key : keys)
- {
- usedVars.add(vars.get(key));
- }
- return usedVars;
- }
+ return result.success;
+ }
@SuppressWarnings( "deprecation" )
private void initExterns()
@@ -307,11 +249,13 @@
final String VARIABLE_MAP = "--variable_map_output_file ";
final String PROPERTY_INPUT_MAP = "--property_map_input_file ";
final String VARIABLE_INPUT_MAP = "--variable_map_input_file ";
+ final String EXTERNS = "--externs ";
String propEntry = null;
String varEntry = null;
String skipEntry = null;
String propInputEntry = null;
String varInputEntry = null;
+ ArrayList<String> removeArgs = new ArrayList<String>();
for (String s : args)
{
@@ -344,6 +288,13 @@
skipEntry = s;
skipTypeInference = true;
}
+
+ if (s.startsWith(EXTERNS))
+ {
+ String fileName = s.substring(EXTERNS.length());
+ addJSExternsFile(fileName);
+ removeArgs.add(s);
+ }
}
if (varEntry != null)
args.remove(varEntry);
@@ -355,6 +306,10 @@
args.remove(propInputEntry);
if (skipEntry != null)
args.remove(skipEntry);
+ for (String s : removeArgs)
+ {
+ args.remove(s);
+ }
}
@@ -407,14 +362,17 @@
WarningLevel.VERBOSE.setOptionsForWarningLevel(options_);
String[] asdocTags = new String[] {"productversion",
- "playerversion", "langversion", "copy",
- "asparam", "asreturn", "asprivate",
+ "playerversion", "langversion", "copy", "span", "para", "throw", "tiptext",
+ "asparam", "asreturn", "asreturns", "asprivate",
"royaleignoreimport", "royaleignorecoercion", "royaleemitcoercion",
+ "royalesuppresscompleximplicitcoercion","royalesuppressresolveuncertain",
+ "royalesuppressvectorindexcheck","royalesuppressexport", "royalesuppressclosure",
"royalenoimplicitstringconversion","royaledebug"};
options_.setExtraAnnotationNames(Arrays.asList(asdocTags));
}
- public void setOptions(String sourceMapPath, boolean useStrictPublishing, boolean manageDependencies, String projectName)
+ @SuppressWarnings("deprecation")
+ public void setOptions(String sourceMapPath, boolean useStrictPublishing, boolean manageDependencies, String projectName)
{
if (useStrictPublishing)
{
@@ -432,10 +390,10 @@
options_.setDeadAssignmentElimination(true);
options_.setInlineConstantVars(true);
options_.setInlineFunctions(true);
- options_.setInlineLocalFunctions(true);
- options_.setCrossModuleCodeMotion(true);
+ options_.setInlineLocalVariables(true);
+ options_.setCrossChunkCodeMotion(true);
options_.setCoalesceVariableNames(true);
- options_.setCrossModuleMethodMotion(true);
+ options_.setCrossChunkMethodMotion(true);
options_.setInlineProperties(true);
options_.setInlineVariables(true);
options_.setSmartNameRemoval(true);
@@ -450,8 +408,6 @@
options_.setAliasAllStrings(true);
options_.setConvertToDottedProperties(true);
options_.setRewriteFunctionExpressions(true);
- options_.setOptimizeParameters(true);
- options_.setOptimizeReturns(true);
options_.setOptimizeCalls(true);
options_.setOptimizeArgumentsArray(true);
options_.setGenerateExports(true);
@@ -460,14 +416,11 @@
new String[] { "goog/", "externs/svg.js" },
ShowByPathWarningsGuard.ShowType.EXCLUDE));
- DependencyOptions dopts = new DependencyOptions();
- ArrayList<ModuleIdentifier> entryPoints = new ArrayList<ModuleIdentifier>();
- entryPoints.add(ModuleIdentifier.forClosure(projectName));
- dopts.setDependencyPruning(manageDependencies)
- .setDependencySorting(manageDependencies)
- .setMoocherDropping(manageDependencies)
- .setEntryPoints(entryPoints);
- options_.setDependencyOptions(dopts);
+ ArrayList<String> entryPoints = new ArrayList<String>();
+ if (manageDependencies)
+ entryPoints.add(projectName);
+ options_.setDependencyOptions(DependencyOptions.fromFlags(manageDependencies ? DependencyMode.PRUNE_LEGACY : DependencyMode.NONE,
+ entryPoints, new ArrayList<String>(), null, manageDependencies, false));
// warnings already activated in previous incarnation
options_.setWarningLevel(DiagnosticGroups.ACCESS_CONTROLS, CheckLevel.WARNING);
@@ -537,14 +490,16 @@
private static class CompilerOptionsParser extends CommandLineRunner
{
- public CompilerOptionsParser(String[] args)
- {
- super(args);
- }
-
- public CompilerOptions getOptions()
- {
- return createOptions();
- }
+ public CompilerOptionsParser(String[] args)
+ {
+ super(args);
+ }
+
+ public CompilerOptions getOptions() throws IOException
+ {
+ CompilerOptions options = createOptions();
+ setRunOptions(options);
+ return options;
+ }
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java
index 0653542..8ff320a 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/NativeUtils.java
@@ -122,8 +122,8 @@
unescape("unescape"),
window("window"),
- // (erikdebruin) These aren't strictly 'native' to JS, but the
- // Publisher provides global functions, so, for all
+ // (erikdebruin) These aren't strictly 'native' to JS, but the
+ // Publisher provides global functions, so, for all
// intends and purposes they behave like they are.
_int("int"),
trace("trace"),
@@ -154,6 +154,26 @@
}
}
+ public enum SyntheticJSType
+ {
+ _int("int"),
+ uint("uint"),
+ Vector("Vector"),
+ Class("Class");
+
+ private final String value;
+
+ SyntheticJSType(String value)
+ {
+ this.value = value;
+ }
+
+ public String getValue()
+ {
+ return value;
+ }
+ }
+
public static boolean isNative(String type)
{
for (NativeASType test : NativeASType.values())
@@ -175,5 +195,24 @@
}
return false;
}
+
+ public static boolean isSyntheticJSType(String type)
+ {
+ for (SyntheticJSType test : SyntheticJSType.values())
+ {
+ if (test.getValue().equals(type)) {
+ return true;
+ }
+ }
+ if (type.startsWith("Vector.<")) {
+ return true;
+ }
+ return false;
+ }
+
+ public static boolean isVector(String type)
+ {
+ return type != null && type.startsWith("Vector.<");
+ }
}
diff --git a/compiler-jx/src/main/resources/downloads.xml b/compiler-jx/src/main/resources/downloads.xml
index ac44d0a..1a4a382 100644
--- a/compiler-jx/src/main/resources/downloads.xml
+++ b/compiler-jx/src/main/resources/downloads.xml
@@ -88,17 +88,17 @@
<get src="https://raw.githubusercontent.com/kohsuke/args4j/master/LICENSE" dest="${lib.dir}/args4j-LICENSE.txt" ignoreerrors="true"/>
<!-- closure -->
- <property name="closure.version" value="20170626"/>
+ <property name="closure.version" value="20181210"/>
<property name="closure.name" value="closure-compiler-v${closure.version}"/>
<property name="closure.dest.name" value="compiler"/>
<property name="closure.dest.folder" value="google/closure-compiler"/>
<property name="closure.dest.filename" value="${closure.dest.name}.jar"/>
<antcall target="download-dependency-closure">
<param name="name" value="${closure.name}"/>
- <param name="src.server" value="http://dl.google.com"/>
+ <param name="src.server" value="https://dl.google.com"/>
<param name="src.folder" value="closure-compiler"/>
<param name="src.filename" value="compiler-${closure.version}.zip"/>
- <param name="src.checksum" value="c565b5a1e12aefa5968b42ea83ea6c28"/>
+ <param name="src.checksum" value="c67fdbf6512d1de6bbb84a69ed3d5b87"/>
</antcall>
<!-- commons-io -->
@@ -116,13 +116,13 @@
<!-- guava -->
<property name="guava.name" value="guava"/>
- <property name="guava.version" value="20.0"/>
+ <property name="guava.version" value="25.1-jre"/>
<antcall target="download-dependency">
<param name="name" value="${guava.name}"/>
<param name="src.server" value="${maven.search.url}"/>
<param name="src.folder" value="com/google/guava/guava/${guava.version}"/>
<param name="src.filename" value="guava-${guava.version}.jar"/>
- <param name="src.checksum" value="f32a8a2524620dbecc9f6bf6a20c293f"/>
+ <param name="src.checksum" value="da3838847d109ac435f0d3ed4ae1c794"/>
<param name="dest.folder" value=""/>
<param name="dest.filename" value="${guava.name}.jar"/>
</antcall>
diff --git a/compiler-jx/src/test/build.xml b/compiler-jx/src/test/build.xml
index c484c04..532436e 100644
--- a/compiler-jx/src/test/build.xml
+++ b/compiler-jx/src/test/build.xml
@@ -31,11 +31,33 @@
<property name="maxmem" value="512" />
<property name="compiler" value="${compiler.tests}/../.."/>
+ <property name="compiler-externc" value="${compiler}/../compiler-externc"/>
<target name="download" description="Downloads third-party JARs">
<ant antfile="${compiler.tests}/downloads.xml" dir="${compiler.tests}"/>
<delete dir="${compiler.tests}/in"/>
</target>
+
+ <target name="js.swc">
+ <copy file="${compiler-externc}/src/test/config/compile-as-config.xml"
+ todir="${compiler-externc}/target" />
+ <java jar="${compiler}/lib/compc.jar" fork="true"
+ failonerror="true">
+ <arg value="-targets=SWF"/>
+ <arg value="-load-config=${compiler-externc}/target/compile-as-config.xml" />
+ <arg value="-output=${compiler-externc}/target/js.swc" />
+ </java>
+ </target>
+
+ <target name="custom.swc">
+ <copy file="config/compile-js-config.xml"
+ todir="${compiler}/target" />
+ <java jar="${compiler}/lib/compc.jar" fork="true"
+ failonerror="true">
+ <arg value="-load-config=${compiler}/target/compile-js-config.xml" />
+ <arg value="-output=${compiler}/target/custom.swc" />
+ </java>
+ </target>
<target name="compile.unit.tests">
<delete dir="${compiler}/target/test-classes"/>
@@ -181,26 +203,9 @@
</assertions>
</junit>
</target>
-
- <target name="copyLastSuccessfulBuild" depends="check_asjs, get_asjs" />
- <target name="check_asjs" >
- <available file="${env.ASJS_HOME}/frameworks/libs/Network.swc"
- type="file"
- property="asjs.ok"
- value="true" />
- </target>
- <target name="get_asjs" unless="asjs.ok" >
- <get src="http://apacheflexbuild.cloudapp.net:8080/job/royale-asjs/lastSuccessfulBuild/artifact/out/apache-royale-flexjs-0.9.0-bin.zip" dest="${compiler}/target/junit-temp/royale.zip"/>
- <unzip src="${compiler}/target/junit-temp/royale.zip" dest="${env.ASJS_HOME}">
- <patternset>
- <include name="frameworks/libs/*.swc"/>
- </patternset>
- </unzip>
- <delete file="${compiler}/target/junit-temp/royale.zip" />
- </target>
-
- <target name="main" depends="unit.tests, integration.tests"/>
- <target name="all" depends="unit.tests, integration.tests, typedef.tests, integration.tests.asjs"/>
+
+ <target name="main" depends="js.swc, custom.swc, unit.tests, integration.tests"/>
+ <target name="all" depends="main, typedef.tests, integration.tests.asjs"/>
<target name="clean">
<delete dir="${compiler.tests}/bin"/>
diff --git a/compiler-jx/src/test/config/compile-js-config.xml b/compiler-jx/src/test/config/compile-js-config.xml
new file mode 100644
index 0000000..68a3341
--- /dev/null
+++ b/compiler-jx/src/test/config/compile-js-config.xml
@@ -0,0 +1,46 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<royale-config>
+
+ <compiler>
+ <accessible>true</accessible>
+
+ <targets>
+ <target>SWF</target>
+ <target>JSRoyale</target>
+ </targets>
+
+ <source-path>
+ <path-element>../../compiler/src/test/royale</path-element>
+ </source-path>
+
+ <external-library-path>
+ <path-element>../../compiler-externc/target/js.swc</path-element>
+ </external-library-path>
+
+ <warn-no-constructor>false</warn-no-constructor>
+ </compiler>
+
+ <warn-public-vars>false</warn-public-vars>
+
+ <include-sources>
+ <path-element>../../compiler/src/test/royale</path-element>
+ </include-sources>
+
+</royale-config>
diff --git a/compiler-jx/src/test/downloads.xml b/compiler-jx/src/test/downloads.xml
index b6b334f..310810c 100644
--- a/compiler-jx/src/test/downloads.xml
+++ b/compiler-jx/src/test/downloads.xml
@@ -119,7 +119,7 @@
<target name="junit-download-jar" depends="junit-jar-check" unless="junit.jar.exists"
description="Downloads the JUnit jar.">
<antcall target="download-jar">
- <param name="srcUrl" value="http://search.maven.org/remotecontent?filepath=junit/junit/4.10"/>
+ <param name="srcUrl" value="https://search.maven.org/remotecontent?filepath=junit/junit/4.10"/>
<param name="srcJarFile" value="junit-4.10.jar"/>
<param name="destDir" value="${lib.dir}"/>
<param name="destJarFile" value="junit-4.10.jar"/>
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/as/TestExpressions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/as/TestExpressions.java
index 0333265..e516bb9 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/as/TestExpressions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/as/TestExpressions.java
@@ -25,6 +25,7 @@
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IFunctionCallNode;
+import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IIterationFlowNode;
import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
import org.apache.royale.compiler.tree.as.INamespaceAccessExpressionNode;
@@ -518,6 +519,22 @@
asBlockWalker.visitFunctionCall(node);
assertOut("addListener('foo', function(event:Object):void {\n\tdoit();\n})");
}
+
+ @Test
+ public void testVisitLocalNamedFunction()
+ {
+ IFunctionNode node = (IFunctionNode) getLocalFunction("function a() {};");
+ asBlockWalker.visitFunction(node);
+ assertOut("function a() {\n}");
+ }
+
+ @Test
+ public void testVisitLocalNamedFunctionWithParamsReturn()
+ {
+ IFunctionNode node = (IFunctionNode) getLocalFunction("function a(foo:int, bar:String = 'goo'):int{return -1;};");
+ asBlockWalker.visitFunction(node);
+ assertOut("function a(foo:int, bar:String = 'goo'):int {\n\treturn -1;\n}");
+ }
@Test
public void testVisitDynamicAccessNode_1()
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogAccessorMembers.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogAccessorMembers.java
index 3fd051d..69ae550 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogAccessorMembers.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogAccessorMembers.java
@@ -98,10 +98,10 @@
@Test
public void testSetAccessor_withBody()
{
- ISetterNode node = (ISetterNode) getAccessor("function set foo(value:int):void{trace('haai');}");
+ ISetterNode node = (ISetterNode) getAccessor("function set foo(value:int):void{'haai';}");
asBlockWalker.visitSetter(node);
assertOut("Object.defineProperty(\n\tRoyaleTest_A.prototype, \n\t'foo', "
- + "\n\t{set:function(value) {\n\t\tvar self = this;\n\t\ttrace('haai');\n\t}, configurable:true}\n)");
+ + "\n\t{set:function(value) {\n\t\tvar self = this;\n\t\t'haai';\n\t}, configurable:true}\n)");
}
@Override
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogClass.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogClass.java
index be3bfbd..67c4caa 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogClass.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogClass.java
@@ -19,16 +19,11 @@
package org.apache.royale.compiler.internal.codegen.js.goog;
-import java.io.File;
-import java.util.List;
-
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.internal.codegen.as.TestClass;
import org.apache.royale.compiler.internal.driver.js.goog.GoogBackend;
-import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.tree.as.IClassNode;
import org.apache.royale.compiler.tree.as.IFileNode;
-import org.apache.royale.utils.FilenameNormalization;
import org.junit.Test;
/**
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogEmitter.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogEmitter.java
index 42e58e3..c40adb9 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogEmitter.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogEmitter.java
@@ -19,15 +19,11 @@
package org.apache.royale.compiler.internal.codegen.js.goog;
-import java.io.File;
-import java.util.List;
-
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.internal.driver.js.goog.GoogBackend;
import org.apache.royale.compiler.internal.test.ASTestBase;
import org.apache.royale.compiler.tree.as.IFileNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
-import org.apache.royale.utils.FilenameNormalization;
import org.junit.Test;
/**
@@ -115,7 +111,7 @@
@Test
public void testDefaultParameter()
{
- IFunctionNode node = getMethodWithPackage("function method1(p1:int, p2:int, p3:int = 3, p4:int = 4):int{return p1 + p2 + p3 + p4;}");
+ IFunctionNode node = getMethodWithPackage("function method1(p1:Number, p2:Number, p3:Number = 3, p4:Number = 4):Number{return p1 + p2 + p3 + p4;}");
asBlockWalker.visitFunction(node);
assertOut("/**\n * @param {number} p1\n * @param {number} p2\n * @param {number=} p3\n * @param {number=} p4\n * @return {number}\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(p1, p2, p3, p4) {\n"
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogExpressions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogExpressions.java
index d7c2072..a377574 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogExpressions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogExpressions.java
@@ -150,6 +150,15 @@
asBlockWalker.visitFunctionCall(node);
assertOut("addListener('foo', function(event) {\n\tdoit();\n})");
}
+
+ @Override
+ @Test
+ public void testVisitLocalNamedFunctionWithParamsReturn()
+ {
+ IFunctionNode node = (IFunctionNode) getLocalFunction("function a(foo:int, bar:String = 'goo'):int{return -1;};");
+ asBlockWalker.visitFunction(node);
+ assertOut("function a(foo, bar) {\n\tbar = typeof bar !== 'undefined' ? bar : 'goo';\n\treturn -1;\n}");
+ }
@Override
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogFieldMembers.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogFieldMembers.java
index 9bb864d..a1318d4 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogFieldMembers.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogFieldMembers.java
@@ -97,7 +97,7 @@
{
IVariableNode node = getField("protected var foo:Vector.<Foo>;");
asBlockWalker.visitVariable(node);
- assertOut("/**\n * @protected\n * @type {Vector.<Foo>}\n */\nRoyaleTest_A.prototype.foo");
+ assertOut("/**\n * @protected\n * @type {Array.<Foo>}\n */\nRoyaleTest_A.prototype.foo");
}
@Override
@@ -106,7 +106,7 @@
{
IVariableNode node = getField("protected var foo:Vector.<Vector.<Vector.<Foo>>>;");
asBlockWalker.visitVariable(node);
- assertOut("/**\n * @protected\n * @type {Vector.<Vector.<Vector.<Foo>>>}\n */\nRoyaleTest_A.prototype.foo");
+ assertOut("/**\n * @protected\n * @type {Array.<Array.<Array.<Foo>>>}\n */\nRoyaleTest_A.prototype.foo");
}
@Override
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalClasses.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalClasses.java
index 0bf0f4a..28aab2a 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalClasses.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalClasses.java
@@ -271,7 +271,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Vector.<string>} */ a = new Array(['Hello', 'World'])");
+ assertOut("var /** @type {Array.<string>} */ a = new Array(['Hello', 'World'])");
}
@Override
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalFunctions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalFunctions.java
index 5b54916..f979f20 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalFunctions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogGlobalFunctions.java
@@ -24,6 +24,7 @@
import org.apache.royale.compiler.internal.driver.js.goog.GoogBackend;
import org.apache.royale.compiler.tree.as.IFunctionCallNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
+import org.junit.Ignore;
import org.junit.Test;
/**
@@ -121,6 +122,8 @@
assertOut("var /** @type {boolean} */ a = isNaN(NaN)");
}
+ //isXMLName is in E4X, which is not supported by JavaScript
+ @Ignore
@Override
@Test
public void testIsXMLName()
@@ -209,7 +212,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Vector.<string>} */ a = Array(['Hello', 'World'])");
+ assertOut("var /** @type {Array.<string>} */ a = Array(['Hello', 'World'])");
}
@Override
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java
index 4247a29..9df4078 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/goog/TestGoogStatements.java
@@ -25,6 +25,7 @@
import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode;
import org.apache.royale.compiler.tree.as.IFileNode;
import org.apache.royale.compiler.tree.as.IForLoopNode;
+import org.apache.royale.compiler.tree.as.IIfNode;
import org.apache.royale.compiler.tree.as.ISwitchNode;
import org.apache.royale.compiler.tree.as.ITryNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
@@ -310,6 +311,16 @@
assertOut("goog.provide('RoyaleTest_A');\n\n/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\nRoyaleTest_A.prototype.royaleTest_a = function() {\n\tvar self = this;\n\ttry {\n\t\ta;\n\t} catch (e) {\n\t\tif (a) {\n\t\t\tif (b) {\n\t\t\t\tif (c)\n\t\t\t\t\tb;\n\t\t\t\telse if (f)\n\t\t\t\t\ta;\n\t\t\t\telse\n\t\t\t\t\te;\n\t\t\t}\n\t\t}\n\t} finally {\n\t}\n\tif (d)\n\t\tfor (var /** @type {number} */ i = 0; i < len; i++)\n\t\t\tbreak;\n\tif (a) {\n\t\twith (ab) {\n\t\t\tc();\n\t\t}\n\t\tdo {\n\t\t\ta++;\n\t\t\tdo\n\t\t\t\ta++;\n\t\t\twhile (a > b);\n\t\t} while (c > d);\n\t}\n\tif (b) {\n\t\ttry {\n\t\t\ta;\n\t\t\tthrow new Error('foo');\n\t\t} catch (e) {\n\t\t\tswitch (i) {\n\t\t\t\tcase 1:\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\treturn;\n\t\t\t}\n\t\t} finally {\n\t\t\td;\n\t\t\tvar /** @type {Object} */ a = function(foo, bar) {\n\t\t\t\tbar = typeof bar !== 'undefined' ? bar : 'goo';\n\t\t\t\treturn -1;\n\t\t\t};\n\t\t\teee.dd;\n\t\t\teee.dd;\n\t\t\teee.dd;\n\t\t\teee.dd;\n\t\t}\n\t}\n\tfoo : goog.array.forEach(obj, function (i) {\n\t\tbreak foo;\n\t});\n};");
}
+ @Test
+ public void testVisitIf_NoClauses()
+ {
+ IIfNode node = (IIfNode) getNode(
+ "if (a) ;", IIfNode.class);
+ asBlockWalker.visitIf(node);
+ assertOut("if (a)\n{}\n");
+ }
+
+
@Override
protected IBackend createBackend()
{
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestDefaultInitializers.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestDefaultInitializers.java
index 6129bfd..963d2cf 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestDefaultInitializers.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestDefaultInitializers.java
@@ -25,6 +25,7 @@
import org.apache.royale.compiler.internal.driver.js.royale.RoyaleBackend;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.test.ASTestBase;
+import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
import org.junit.Test;
@@ -35,16 +36,20 @@
{
backend = createBackend();
project = new RoyaleJSProject(workspace, backend);
+ super.setUp();
+ }
+
+ protected void createConfig(boolean defaultInitializers)
+ {
JSGoogConfiguration config = new JSGoogConfiguration();
try {
- config.setJsDefaultInitializers(null, true);
+ config.setJsDefaultInitializers(null, defaultInitializers);
} catch (ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
project.config = config;
- super.setUp();
- }
+ }
protected IBackend createBackend()
{
@@ -52,121 +57,312 @@
}
@Test
- public void testVarDeclaration_withNumberType()
+ public void testVarDeclaration_defaultInitializers_withNumberType()
{
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Number;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = NaN;\n //var /** @type {number} */ a = NaN;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_noDefaultInitializers_withNumberType()
+ {
+ createConfig(false);
IVariableNode node = (IVariableNode) getNode("var a:Number;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {number} */ a = NaN");
+ assertOut("var /** @type {number} */ a");
}
@Test
- public void testVarDeclaration_withBooleanType()
+ public void testVarDeclaration_defaultInitializers_withBooleanType()
{
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Boolean;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {boolean} */ a = false;\n //var /** @type {boolean} */ a = false;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_noDefaultInitializers_withBooleanType()
+ {
+ createConfig(false);
IVariableNode node = (IVariableNode) getNode("var a:Boolean;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {boolean} */ a = false");
+ assertOut("var /** @type {boolean} */ a");
}
@Test
- public void testVarDeclaration_withIntType()
+ public void testVarDeclaration_defaultInitializers_withIntType()
{
- IVariableNode node = (IVariableNode) getNode("var a:int;",
- IVariableNode.class);
- asBlockWalker.visitVariable(node);
- assertOut("var /** @type {number} */ a = 0");
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:int;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = 0;\n //var /** @type {number} */ a = 0;\n}");
}
@Test
- public void testVarDeclaration_withUintType()
+ public void testVarDeclaration_noDefaultInitializers_withIntType()
{
- IVariableNode node = (IVariableNode) getNode("var a:uint;",
- IVariableNode.class);
- asBlockWalker.visitVariable(node);
- assertOut("var /** @type {number} */ a = 0");
+ createConfig(false);
+ IFunctionNode node = (IFunctionNode) getNode("var a:int;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ //an exception that always has an initializer
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = 0;\n //var /** @type {number} */ a = 0;\n}");
}
@Test
- public void testVarDeclaration_withStringType()
+ public void testVarDeclaration_defaultInitializers_withUintType()
{
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:uint;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = 0;\n //var /** @type {number} */ a = 0;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_noDefaultInitializers_withUintType()
+ {
+ createConfig(false);
+ IFunctionNode node = (IFunctionNode) getNode("var a:uint;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ //an exception that always has an initializer
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = 0;\n //var /** @type {number} */ a = 0;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_defaultInitializers_withStringType()
+ {
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:String;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {string} */ a = null;\n //var /** @type {string} */ a = null;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_noDefaultInitializers_withStringType()
+ {
+ createConfig(false);
IVariableNode node = (IVariableNode) getNode("var a:String;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {string} */ a = null");
+ assertOut("var /** @type {string} */ a");
}
@Test
- public void testVarDeclaration_withObjectType()
+ public void testVarDeclaration_defaultInitializers_withObjectType()
{
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Object;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {Object} */ a = null;\n //var /** @type {Object} */ a = null;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_noDefaultInitializers_withObjectType()
+ {
+ createConfig(false);
IVariableNode node = (IVariableNode) getNode("var a:Object;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Object} */ a = null");
+ assertOut("var /** @type {Object} */ a");
}
@Test
- public void testVarDeclaration_withArrayType()
+ public void testVarDeclaration_defaultInitializers_withArrayType()
{
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Array;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {Array} */ a = null;\n //var /** @type {Array} */ a = null;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_noDefaultInitializers_withArrayType()
+ {
+ createConfig(false);
IVariableNode node = (IVariableNode) getNode("var a:Array;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = null");
+ assertOut("var /** @type {Array} */ a");
}
@Test
- public void testFieldDeclaration_withNumberType()
+ public void testVarDeclaration_defaultInitializers_withChainedAndAllInitialized()
{
+ createConfig(true);
+ IVariableNode node = (IVariableNode) getNode("var a:Number = 0, b:Number = 0, c:Number = 0;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 0, /** @type {number} */ b = 0, /** @type {number} */ c = 0");
+ }
+
+ @Test
+ public void testVarDeclaration_defaultInitializers_withChainedAndNoneInitialized()
+ {
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Number, b:Number, c:Number;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = NaN;\n var /** @type {number} */ b = NaN;\n var /** @type {number} */ c = NaN;\n //var /** @type {number} */ a = NaN;\n //var /** @type {number} */ b = NaN;\n //var /** @type {number} */ c = NaN;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_defaultInitializers_withChainedAndFirstInitialized()
+ {
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Number = 1, b:Number, c:Number;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ b = NaN;\n var /** @type {number} */ c = NaN;\n var /** @type {number} */ a = 1;\n //var /** @type {number} */ b = NaN;\n //var /** @type {number} */ c = NaN;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_defaultInitializers_withChainedAndLastInitialized()
+ {
+ createConfig(true);
+ IFunctionNode node = (IFunctionNode) getNode("var a:Number, b:Number, c:Number = 1;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = NaN;\n var /** @type {number} */ b = NaN;\n //var /** @type {number} */ a = NaN;\n //var /** @type {number} */ b = NaN;\n var /** @type {number} */ c = 1;\n}");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withNumberType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:Number;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = NaN");
}
@Test
- public void testFieldDeclaration_withBooleanType()
+ public void testFieldDeclaration_noDefaultInitializers_withNumberType()
{
+ createConfig(false);
+ IVariableNode node = getField("private var foo:Number;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @private\n * @type {number}\n */\nRoyaleTest_A.prototype.foo");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withBooleanType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:Boolean;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {boolean}\n */\nRoyaleTest_A.prototype.foo = false");
}
@Test
- public void testFieldDeclaration_withIntType()
+ public void testFieldDeclaration_noDefaultInitializers_withBooleanType()
{
+ createConfig(false);
+ IVariableNode node = getField("private var foo:Boolean;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @private\n * @type {boolean}\n */\nRoyaleTest_A.prototype.foo");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withIntType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:int;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = 0");
}
@Test
- public void testFieldDeclaration_withUintType()
+ public void testFieldDeclaration_noDefaultInitializers_withIntType()
{
+ createConfig(false);
+ IVariableNode node = getField("private var foo:int;");
+ asBlockWalker.visitVariable(node);
+ //an exception that always has an initializer
+ assertOut("/**\n * @private\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = 0");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withUintType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:uint;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = 0");
}
@Test
- public void testFieldDeclaration_withStringType()
+ public void testFieldDeclaration_noDefaultInitializers_withUintType()
{
+ createConfig(false);
+ IVariableNode node = getField("private var foo:uint;");
+ asBlockWalker.visitVariable(node);
+ //an exception that always has an initializer
+ assertOut("/**\n * @private\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = 0");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withStringType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:String;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype.foo = null");
}
@Test
- public void testFieldDeclaration_withObjectType()
+ public void testFieldDeclaration_noDefaultInitializers_withStringType()
{
+ createConfig(false);
+ IVariableNode node = getField("private var foo:String;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype.foo");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withObjectType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:Object;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {Object}\n */\nRoyaleTest_A.prototype.foo = null");
}
@Test
- public void testFieldDeclaration_withArrayType()
+ public void testFieldDeclaration_noDefaultInitializers_withObjectType()
{
+ createConfig(false);
+ IVariableNode node = getField("private var foo:Object;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @private\n * @type {Object}\n */\nRoyaleTest_A.prototype.foo");
+ }
+
+ @Test
+ public void testFieldDeclaration_defaultInitializers_withArrayType()
+ {
+ createConfig(true);
IVariableNode node = getField("private var foo:Array;");
asBlockWalker.visitVariable(node);
assertOut("/**\n * @private\n * @type {Array}\n */\nRoyaleTest_A.prototype.foo = null");
}
+
+ @Test
+ public void testFieldDeclaration_noDefaultInitializers_withArrayType()
+ {
+ createConfig(false);
+ IVariableNode node = getField("private var foo:Array;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @private\n * @type {Array}\n */\nRoyaleTest_A.prototype.foo");
+ }
}
\ No newline at end of file
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleAccessors.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleAccessors.java
index af854af..917f615 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleAccessors.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleAccessors.java
@@ -46,7 +46,7 @@
"public function doStuff():void {label = 'hello, bye'; var theLabel:String = label;}; private var _label:String; public function get label():String {return _label}; public function set label(value:String):void {_label = value}; ",
IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = 'hello, bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label;\n\n\n" +
+ String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = 'hello, bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label = null;\n\n\n" +
"RoyaleTest_A.prototype.get__label = function() {\n return this._label;\n};\n\n\n" +
"RoyaleTest_A.prototype.set__label = function(value) {\n this._label = value;\n};\n\n\n" +
"Object.defineProperties(RoyaleTest_A.prototype, /** @lends {RoyaleTest_A.prototype} */ {\n/**\n * @export\n * @type {string} */\n" +
@@ -61,7 +61,7 @@
"public class B { public function B() {}; public function doStuff():void {this.label = label + 'bye'; var theLabel:String = label;}; private var _label:String; public function get label():String {return _label}; public function set label(value:String):void {_label = value};}",
IClassNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nB = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('B', B);\n\n\n/**\n * @export\n */\nB.prototype.doStuff = function() {\n this.label = this.label + 'bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nB.prototype._label;\n\n\n" +
+ String expected = "/**\n * @constructor\n */\nB = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('B', B);\n\n\n/**\n * @export\n */\nB.prototype.doStuff = function() {\n this.label = this.label + 'bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nB.prototype._label = null;\n\n\n" +
"B.prototype.get__label = function() {\n return this._label;\n};\n\n\n" +
"B.prototype.set__label = function(value) {\n this._label = value;\n};\n\n\n" +
"Object.defineProperties(B.prototype, /** @lends {B.prototype} */ {\n/**\n * @export\n * @type {string} */\nlabel: {\n" +
@@ -76,7 +76,7 @@
"public function doStuff():void {label = label + 'bye'; var theLabel:String = label;}; private var _label:String; public function get label():String {return _label}; public function set label(value:String):void {_label = value}; ",
IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = this.label + 'bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label;\n\n\n" +
+ String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = this.label + 'bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label = null;\n\n\n" +
"RoyaleTest_A.prototype.get__label = function() {\n return this._label;\n};\n\n\n" +
"RoyaleTest_A.prototype.set__label = function(value) {\n this._label = value;\n};\n\n\n" +
"Object.defineProperties(RoyaleTest_A.prototype, /** @lends {RoyaleTest_A.prototype} */ {\n/**\n * @export\n * @type {string} */\nlabel: {\n" +
@@ -91,7 +91,7 @@
"public class B { public function B() {}; public function doStuff():void {label = this.label; var theLabel:String = label;}; private var _label:String; public function get label():String {return _label}; public function set label(value:String):void {_label = value};}",
IClassNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nB = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('B', B);\n\n\n/**\n * @export\n */\nB.prototype.doStuff = function() {\n this.label = this.label;\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nB.prototype._label;\n\n\n" +
+ String expected = "/**\n * @constructor\n */\nB = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('B', B);\n\n\n/**\n * @export\n */\nB.prototype.doStuff = function() {\n this.label = this.label;\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nB.prototype._label = null;\n\n\n" +
"B.prototype.get__label = function() {\n return this._label;\n};\n\n\n" +
"B.prototype.set__label = function(value) {\n this._label = value;\n};\n\n\n" +
"Object.defineProperties(B.prototype, /** @lends {B.prototype} */ {\n/**\n * @export\n * @type {string} */\nlabel: {\n" +
@@ -106,10 +106,10 @@
"import custom.custom_namespace;use namespace custom_namespace;public class B { public function B() {}; public function doStuff():void {var theLabel:String = label; label = theLabel;}; private var _label:String; custom_namespace function get label():String {return _label}; custom_namespace function set label(value:String):void {_label = value};}",
IClassNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nB = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('B', B);\n\n\n/**\n * @export\n */\nB.prototype.doStuff = function() {\n var /** @type {string} */ theLabel = this[\"http://ns.apache.org/2017/custom/namespace::label\"];\n this[\"http://ns.apache.org/2017/custom/namespace::label\"] = theLabel;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nB.prototype._label;\n\n\n" +
- "B.prototype[\"http://ns.apache.org/2017/custom/namespace::get__label\"] = function() {\n return this._label;\n};\n\n\n" +
- "B.prototype[\"http://ns.apache.org/2017/custom/namespace::set__label\"] = function(value) {\n this._label = value;\n};\n\n\n" +
- "Object.defineProperties(B.prototype, /** @lends {B.prototype} */ {\n/**\n * @export\n * @type {string} */\n\"http://ns.apache.org/2017/custom/namespace::label\": {\nget: B.prototype[\"http://ns.apache.org/2017/custom/namespace::get__label\"],\nset: B.prototype[\"http://ns.apache.org/2017/custom/namespace::set__label\"]}}\n);";
+ String expected = "/**\n * @constructor\n */\nB = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('B', B);\n\n\n/**\n * @export\n */\nB.prototype.doStuff = function() {\n var /** @type {string} */ theLabel = this.http_$$ns_apache_org$2017$custom$namespace__label;\n this.http_$$ns_apache_org$2017$custom$namespace__label = theLabel;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nB.prototype._label = null;\n\n\n" +
+ "B.prototype.http_$$ns_apache_org$2017$custom$namespace__get__label = function() {\n return this._label;\n};\n\n\n" +
+ "B.prototype.http_$$ns_apache_org$2017$custom$namespace__set__label = function(value) {\n this._label = value;\n};\n\n\n" +
+ "Object.defineProperties(B.prototype, /** @lends {B.prototype} */ {\n/**\n * @export\n * @type {string} */\nhttp_$$ns_apache_org$2017$custom$namespace__label: {\nget: B.prototype.http_$$ns_apache_org$2017$custom$namespace__get__label,\nset: B.prototype.http_$$ns_apache_org$2017$custom$namespace__set__label}}\n);";
assertOut(expected);
}
@@ -120,7 +120,7 @@
"public function doStuff():void {label = 'hello, bye'; var theLabel:String = label;}; private var _label:String; [Bindable] public function get label():String {return _label}; public function set label(value:String):void {_label = value}; ",
IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = 'hello, bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label;\n\n\n" +
+ String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = 'hello, bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label = null;\n\n\n" +
"RoyaleTest_A.prototype.get__label = function() {\n return this._label;\n};\n\n\n" +
"RoyaleTest_A.prototype.bindable__set__label = function(value) {\n this._label = value;\n};\n\n\n" +
"RoyaleTest_A.prototype.set__label = function(value) {\nvar oldValue = this.get__label();\nif (oldValue != value) {\nthis.bindable__set__label(value);\n" +
@@ -138,7 +138,7 @@
"public function doStuff():void {label = 'hello, bye'; var theLabel:String = label;}; private var _label:String; [Bindable(\"change\")] public function get label():String {return _label}; public function set label(value:String):void {_label = value}; ",
IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = 'hello, bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label;\n\n\n" +
+ String expected = "/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n */\nRoyaleTest_A.prototype.doStuff = function() {\n this.label = 'hello, bye';\n var /** @type {string} */ theLabel = this.label;\n};\n\n\n/**\n * @private\n * @type {string}\n */\nRoyaleTest_A.prototype._label = null;\n\n\n" +
"RoyaleTest_A.prototype.get__label = function() {\n return this._label;\n};\n\n\n" +
"RoyaleTest_A.prototype.set__label = function(value) {\n this._label = value;\n};\n\n\n" +
"Object.defineProperties(RoyaleTest_A.prototype, /** @lends {RoyaleTest_A.prototype} */ {\n/**\n * @export\n * @type {string} */\n" +
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleClass.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleClass.java
index f223030..788cfda 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleClass.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleClass.java
@@ -149,6 +149,87 @@
}
@Test
+ public void testMethod_returnIntWithVariableNoCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():int { var a:int = 123; return a; };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n var a /** @type {number} */ = 123.4;\n return a;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnIntWithVariableCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():int { var a:Number = 123.4; return a; };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n var a /** @type {number} */ = 123.4;\n return (a) >> 0;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnIntWithLiteralCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():int { return 123.4 };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n return (123.4) >> 0;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnUintWithVariableNoCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():uint { var a:uint = 123; return a; };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n var a /** @type {number} */ = 123.4;\n return a;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnUintWithVariableCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():uint { var a:Number = 123.4; return a; };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n var a /** @type {number} */ = 123.4;\n return (a) >>> 0;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnUintWithLiteralCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():uint { return 123.4 };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n return (123.4) >>> 0;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnBooleanWithVariableNoCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():Boolean { var a:Boolean = true; return a; };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n var a /** @type {number} */ = 123.4;\n return a;\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnBooleanWithVariableCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():Boolean { var a:Number = 123.4; return a; };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n var a /** @type {number} */ = 123.4;\n return !!(a);\n};";
+ assertOut(expected);
+ }
+
+ @Test
+ public void testMethod_returnBooleanWithLiteralNoCoercion()
+ {
+ IClassNode node = getClassNode("public class B {public function B() {}; public function foo():Boolean { return 123.4 };}");
+ asBlockWalker.visitClass(node);
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.foo = function() {\n return true;\n};";
+ assertOut(expected);
+ }
+
+ @Test
public void testMethod_override()
{
IClassNode node = getClassNode("public class B {public function B() {}; override public function foo():void {};}");
@@ -198,10 +279,113 @@
{
IClassNode node = getClassNode("import custom.custom_namespace; use namespace custom_namespace; public class B {public function B() {}; custom_namespace function foo():void {};}");
asBlockWalker.visitClass(node);
- String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n */\norg.apache.royale.B.prototype[\"http://ns.apache.org/2017/custom/namespace::foo\"] = function() {\n};";
+ String expected = "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);\n\n\n/**\n * @export\n */\norg.apache.royale.B.prototype.http_$$ns_apache_org$2017$custom$namespace__foo = function() {\n};";
assertOut(expected);
}
+ @Test
+ public void testInnerClassReferencingInnerClass()
+ {
+ FileNode node = (FileNode)getNode("package org.apache.royale {\npublic class B {public function B() {}; }} class A {public function get a():A {return null}}", FileNode.class, 0);
+ asBlockWalker.visitFile(node);
+ String expected = "/**\n * org.apache.royale.B\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('org.apache.royale.B');\ngoog.provide('org.apache.royale.B.A');\n\n\n\n" +
+ "/**\n * @constructor\n */\norg.apache.royale.B = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.B', org.apache.royale.B);" +
+ "\n\n\n/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "org.apache.royale.B.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'B', qName: 'org.apache.royale.B', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "org.apache.royale.B.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {return {};},\n" +
+ " accessors: function () {return {};},\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'B': { type: '', declaredBy: 'org.apache.royale.B'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "org.apache.royale.B.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "org.apache.royale.B.A = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('org.apache.royale.B.A', org.apache.royale.B.A);\n" +
+ "\n" +
+ "\n" +
+ "org.apache.royale.B.A.prototype.get__a = function() {\n" +
+ " return null;\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "Object.defineProperties(org.apache.royale.B.A.prototype, /** @lends {org.apache.royale.B.A.prototype} */ {\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @type {org.apache.royale.B.A} */\n" +
+ "a: {\n" +
+ "get: org.apache.royale.B.A.prototype.get__a}}\n" +
+ ");\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "org.apache.royale.B.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'org.apache.royale.B.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "org.apache.royale.B.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {return {};},\n" +
+ " accessors: function () {\n" +
+ " return {\n" +
+ " 'a': { type: 'org.apache.royale.B.A', access: 'readonly', declaredBy: 'org.apache.royale.B.A'}\n" +
+ " };\n" +
+ " },\n" +
+ " methods: function () {return {};}\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "org.apache.royale.B.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n" +
+ "";
+ assertOutWithMetadata(expected);
+ }
+
@Override
@Test
public void testExtendsConstructor_withArguments()
@@ -509,15 +693,15 @@
"org.apache.royale.A.prototype.set__foo3 = function(value) {\n};\n\n\n" +
"org.apache.royale.A.prototype.get__foo5 = function() {\n return null;\n};\n\n\n" +
"org.apache.royale.A.prototype.set__foo5 = function(value) {\n};\n\n\n" +
- "org.apache.royale.A.prototype[\"http://ns.apache.org/2017/custom/namespace::get__foo6\"] = function() {\n return null;\n};\n\n\n" +
- "org.apache.royale.A.prototype[\"http://ns.apache.org/2017/custom/namespace::set__foo6\"] = function(value) {\n};\n\n\n" +
+ "org.apache.royale.A.prototype.http_$$ns_apache_org$2017$custom$namespace__get__foo6 = function() {\n return null;\n};\n\n\n" +
+ "org.apache.royale.A.prototype.http_$$ns_apache_org$2017$custom$namespace__set__foo6 = function(value) {\n};\n\n\n" +
"Object.defineProperties(org.apache.royale.A.prototype, /** @lends {org.apache.royale.A.prototype} */ {\n/**\n * @export\n * @type {Object} */\n" +
"foo1: {\nget: org.apache.royale.A.prototype.get__foo1,\nset: org.apache.royale.A.prototype.set__foo1},\n/**\n * @export\n * @type {Object} */\n" +
"foo2: {\nget: org.apache.royale.A.prototype.get__foo2,\nset: org.apache.royale.A.prototype.set__foo2},\n/**\n * @export\n * @type {Object} */\n" +
"foo3: {\nget: org.apache.royale.A.prototype.get__foo3,\nset: org.apache.royale.A.prototype.set__foo3},\n/**\n * @export\n * @type {Object} */\n" +
"foo5: {\nget: org.apache.royale.A.prototype.get__foo5,\nset: org.apache.royale.A.prototype.set__foo5},\n/**\n * @export\n * @type {Object} */\n" +
- "\"http://ns.apache.org/2017/custom/namespace::foo6\": {\nget: org.apache.royale.A.prototype[\"http://ns.apache.org/2017/custom/namespace::get__foo6\"],\n" +
- "set: org.apache.royale.A.prototype[\"http://ns.apache.org/2017/custom/namespace::set__foo6\"]}}\n);");
+ "http_$$ns_apache_org$2017$custom$namespace__foo6: {\nget: org.apache.royale.A.prototype.http_$$ns_apache_org$2017$custom$namespace__get__foo6,\n" +
+ "set: org.apache.royale.A.prototype.http_$$ns_apache_org$2017$custom$namespace__set__foo6}}\n);");
}
@Override
@@ -535,7 +719,7 @@
+ "public static function foo7(value:Object):void{}"
+ "custom_namespace static function foo7(value:Object):void{}" + "}");
asBlockWalker.visitClass(node);
- assertOut("/**\n * @constructor\n */\norg.apache.royale.A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.A', org.apache.royale.A);\n\n\n/**\n * @export\n * @return {Object}\n */\norg.apache.royale.A.prototype.foo1 = function() {\n return null;\n};\n\n\n/**\n * @export\n * @return {Object}\n */\norg.apache.royale.A.prototype.foo1a = function() {\n return null;\n};\n\n\n/**\n * @export\n * @override\n */\norg.apache.royale.A.prototype.foo1b = function() {\n return org.apache.royale.A.superClass_.foo1b.apply(this);\n};\n\n\n/**\n * @protected\n * @param {Object} value\n */\norg.apache.royale.A.prototype.foo2 = function(value) {\n};\n\n\n/**\n * @private\n * @param {Object} value\n */\norg.apache.royale.A.prototype.foo3 = function(value) {\n};\n\n\n/**\n * @param {Object} value\n */\norg.apache.royale.A.prototype.foo5 = function(value) {\n};\n\n\n/**\n * @param {Object} value\n */\norg.apache.royale.A.prototype[\"http://ns.apache.org/2017/custom/namespace::foo6\"] = function(value) {\n};\n\n\n/**\n * @export\n * @param {Object} value\n */\norg.apache.royale.A.foo7 = function(value) {\n};\n\n\n/**\n * @param {Object} value\n */\norg.apache.royale.A[\"http://ns.apache.org/2017/custom/namespace::foo7\"] = function(value) {\n};");
+ assertOut("/**\n * @constructor\n */\norg.apache.royale.A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('org.apache.royale.A', org.apache.royale.A);\n\n\n/**\n * @export\n * @return {Object}\n */\norg.apache.royale.A.prototype.foo1 = function() {\n return null;\n};\n\n\n/**\n * @export\n * @return {Object}\n */\norg.apache.royale.A.prototype.foo1a = function() {\n return null;\n};\n\n\n/**\n * @export\n * @override\n */\norg.apache.royale.A.prototype.foo1b = function() {\n return org.apache.royale.A.superClass_.foo1b.apply(this);\n};\n\n\n/**\n * @protected\n * @param {Object} value\n */\norg.apache.royale.A.prototype.foo2 = function(value) {\n};\n\n\n/**\n * @private\n * @param {Object} value\n */\norg.apache.royale.A.prototype.foo3 = function(value) {\n};\n\n\n/**\n * @export\n * @param {Object} value\n */\norg.apache.royale.A.prototype.foo5 = function(value) {\n};\n\n\n/**\n * @export\n * @param {Object} value\n */\norg.apache.royale.A.prototype.http_$$ns_apache_org$2017$custom$namespace__foo6 = function(value) {\n};\n\n\n/**\n * @export\n * @param {Object} value\n */\norg.apache.royale.A.foo7 = function(value) {\n};\n\n\n/**\n * @export\n * @param {Object} value\n */\norg.apache.royale.A.http_$$ns_apache_org$2017$custom$namespace__foo7 = function(value) {\n};");
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleEmitter.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleEmitter.java
index e8c40a8..94d39f5 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleEmitter.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleEmitter.java
@@ -59,92 +59,98 @@
IFileNode node = compileAS(code);
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * com.example.components.MyEventTarget\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('com.example.components.MyEventTarget');\n" +
- "\n" +
- "goog.require('custom.TestImplementation');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " * @extends {custom.TestImplementation}\n" +
- " */\n" +
- "com.example.components.MyEventTarget = function() {\n" +
- " com.example.components.MyEventTarget.base(this, 'constructor');\n" +
- " if (foo() != 42) {\n" +
- " bar();\n" +
- " }\n" +
- "};\n" +
- "goog.inherits(com.example.components.MyEventTarget, custom.TestImplementation);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Prevent renaming of class. Needed for reflection.\n" +
- " */\n" +
- "goog.exportSymbol('com.example.components.MyEventTarget', com.example.components.MyEventTarget);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @private\n" +
- " * @type {string}\n" +
- " */\n" +
- "com.example.components.MyEventTarget.prototype._privateVar = \"do \";\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " * @type {number}\n" +
- " */\n" +
- "com.example.components.MyEventTarget.prototype.publicProperty = 100;\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " * @param {string} value\n" +
- " * @return {string}\n" +
- " */\n" +
- "com.example.components.MyEventTarget.prototype.myFunction = function(value) {\n" +
- " return \"Don't \" + this._privateVar + value;\n" +
- "};\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "com.example.components.MyEventTarget.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'MyEventTarget', qName: 'com.example.components.MyEventTarget', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "com.example.components.MyEventTarget.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
- " variables: function () {\n" +
- " return {\n" +
- " 'publicProperty': { type: 'Number'}\n" +
- " };\n" +
- " },\n" +
- " accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'MyEventTarget': { type: '', declaredBy: 'com.example.components.MyEventTarget'},\n" +
- " 'myFunction': { type: 'String', declaredBy: 'com.example.components.MyEventTarget', parameters: function () { return [ { index: 1, type: 'String', optional: false } ]; }}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n");
+ " * com.example.components.MyEventTarget\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('com.example.components.MyEventTarget');\n" +
+ "\n" +
+ "goog.require('custom.TestImplementation');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " * @extends {custom.TestImplementation}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget = function() {\n" +
+ " com.example.components.MyEventTarget.base(this, 'constructor');\n" +
+ " if (foo() != 42) {\n" +
+ " bar();\n" +
+ " }\n" +
+ "};\n" +
+ "goog.inherits(com.example.components.MyEventTarget, custom.TestImplementation);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('com.example.components.MyEventTarget', com.example.components.MyEventTarget);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @private\n" +
+ " * @type {string}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget.prototype._privateVar = \"do \";\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget.prototype.publicProperty = 100;\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @param {string} value\n" +
+ " * @return {string}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget.prototype.myFunction = function(value) {\n" +
+ " return \"Don't \" + this._privateVar + value;\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'MyEventTarget', qName: 'com.example.components.MyEventTarget', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {\n" +
+ " return {\n" +
+ " 'publicProperty': { type: 'Number', get_set: function (/** com.example.components.MyEventTarget */ inst, /** * */ v) {return v !== undefined ? inst.publicProperty = v : inst.publicProperty;}}\n" +
+ " };\n" +
+ " },\n" +
+ " accessors: function () {return {};},\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'MyEventTarget': { type: '', declaredBy: 'com.example.components.MyEventTarget'},\n" +
+ " 'myFunction': { type: 'String', declaredBy: 'com.example.components.MyEventTarget', parameters: function () { return [ { index: 1, type: 'String', optional: false } ]; }}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "com.example.components.MyEventTarget.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n");
}
@Override
@@ -156,49 +162,55 @@
IFileNode node = compileAS(code);
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * com.example.components.TestInterface\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('com.example.components.TestInterface');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @interface\n" +
- " */\ncom.example.components.TestInterface = function() {\n" +
- "};\n" +
- "\n" +
+ " * com.example.components.TestInterface\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('com.example.components.TestInterface');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @interface\n" +
+ " */\ncom.example.components.TestInterface = function() {\n" +
+ "};\n" +
+ "\n" +
"\n" +
"/**\n" +
" * Prevent renaming of class. Needed for reflection.\n" +
" */\n" +
"goog.exportSymbol('com.example.components.TestInterface', com.example.components.TestInterface);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "com.example.components.TestInterface.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'TestInterface', qName: 'com.example.components.TestInterface', kind: 'interface' }] };\n" +
"\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "com.example.components.TestInterface.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
- " accessors: function () {return {};},\n" +
- " methods: function () {return {};}\n" +
- " };\n" +
- "};\n");
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "com.example.components.TestInterface.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'TestInterface', qName: 'com.example.components.TestInterface', kind: 'interface' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "com.example.components.TestInterface.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " accessors: function () {return {};},\n" +
+ " methods: function () {return {};}\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "com.example.components.TestInterface.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n");
}
@Override
@@ -254,7 +266,13 @@
" accessors: function () {return {};},\n" +
" methods: function () {return {};}\n" +
" };\n" +
- "};\n");
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "com.example.components.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n");
}
@Test
@@ -283,9 +301,9 @@
"\n" +
"\n" +
"/**\n" +
- " * <inject_html>\n" +
+ " * <inject_html>\n" +
" * This will be injected.\n" +
- " * </inject_html>\n" +
+ " * </inject_html>\n" +
" * @constructor\n" +
" */\n" +
"com.example.components.TestClass = function() {\n" +
@@ -322,7 +340,13 @@
" };\n" +
" }\n" +
" };\n" +
- "};\n");
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "com.example.components.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n");
}
@@ -330,9 +354,9 @@
@Test
public void testDefaultParameter()
{
- IFunctionNode node = getMethodWithPackage("function method1(p1:int, p2:int, p3:int = 3, p4:int = 4):int{return p1 + p2 + p3 + p4;}");
+ IFunctionNode node = getMethodWithPackage("function method1(p1:Number, p2:Number, p3:Number = 3, p4:Number = 4):Number{return p1 + p2 + p3 + p4;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {number} p1\n * @param {number} p2\n * @param {number=} p3\n * @param {number=} p4\n * @return {number}\n */\n"
+ assertOut("/**\n * @export\n * @param {number} p1\n * @param {number} p2\n * @param {number=} p3\n * @param {number=} p4\n * @return {number}\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(p1, p2, p3, p4) {\n"
+ " p3 = typeof p3 !== 'undefined' ? p3 : 3;\n"
+ " p4 = typeof p4 !== 'undefined' ? p4 : 4;\n"
@@ -345,7 +369,7 @@
{
IFunctionNode node = getMethodWithPackage("function method1(bar:int = 42, bax:int = 4):void{if (a) foo();}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {number=} bar\n * @param {number=} bax\n */\n"
+ assertOut("/**\n * @export\n * @param {number=} bar\n * @param {number=} bax\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(bar, bax) {\n"
+ " bar = typeof bar !== 'undefined' ? bar : 42;\n"
+ " bax = typeof bax !== 'undefined' ? bax : 4;\n"
@@ -358,7 +382,7 @@
{
IFunctionNode node = getMethodWithPackage("function method1(p1:int, p2:int, p3:int = 3, p4:int = 4):int{}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {number} p1\n * @param {number} p2\n * @param {number=} p3\n * @param {number=} p4\n * @return {number}\n */\n"
+ assertOut("/**\n * @export\n * @param {number} p1\n * @param {number} p2\n * @param {number=} p3\n * @param {number=} p4\n * @return {number}\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(p1, p2, p3, p4) {\n"
+ " p3 = typeof p3 !== 'undefined' ? p3 : 3;\n"
+ " p4 = typeof p4 !== 'undefined' ? p4 : 4;\n}");
@@ -370,7 +394,7 @@
{
IFunctionNode node = getMethodWithPackage("function method1(bar:int):int{\n}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {number} bar\n * @return {number}\n */\n"
+ assertOut("/**\n * @export\n * @param {number} bar\n * @return {number}\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(bar) {\n}");
}
@@ -380,7 +404,7 @@
{
IFunctionNode node = getMethodWithPackage("function method1(bar:int, baz:String, goo:Array):void{\n}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {number} bar\n * @param {string} baz\n * @param {Array} goo\n */\n"
+ assertOut("/**\n * @export\n * @param {number} bar\n * @param {string} baz\n * @param {Array} goo\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(bar, baz, goo) {\n}");
}
@@ -390,7 +414,7 @@
{
IFunctionNode node = getMethodWithPackage("/**\n * This is copied from ASDoc.\n */\nfunction method1(bar:int, baz:String, goo:Array):void{\n}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * This is copied from ASDoc.\n * @param {number} bar\n * @param {string} baz\n * @param {Array} goo\n */\n"
+ assertOut("/**\n * This is copied from ASDoc.\n * @export\n * @param {number} bar\n * @param {string} baz\n * @param {Array} goo\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(bar, baz, goo) {\n}");
}
@@ -399,7 +423,7 @@
{
IFunctionNode node = getMethodWithPackage("/** This is copied from ASDoc. */\nfunction method1(bar:int, baz:String, goo:Array):void{\n}");
asBlockWalker.visitFunction(node);
- assertOut("/** This is copied from ASDoc. \n * @param {number} bar\n * @param {string} baz\n * @param {Array} goo\n */\n"
+ assertOut("/** This is copied from ASDoc. \n * @export\n * @param {number} bar\n * @param {string} baz\n * @param {Array} goo\n */\n"
+ "foo.bar.RoyaleTest_A.prototype.method1 = function(bar, baz, goo) {\n}");
}
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
index 399c93e..8ee8ab9 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleExpressions.java
@@ -32,11 +32,12 @@
import org.apache.royale.compiler.internal.tree.as.NodeBase;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.IClassNode;
+import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IFileNode;
import org.apache.royale.compiler.tree.as.IFunctionCallNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
-import org.apache.royale.compiler.tree.as.IGetterNode;
import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
+import org.apache.royale.compiler.tree.as.IReturnNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
import org.junit.Ignore;
import org.junit.Test;
@@ -63,6 +64,33 @@
super.setUp();
}
+ @Test
+ public void testVisitDynamicAccessString()
+ {
+ IDynamicAccessNode node = (IDynamicAccessNode) getNode(
+ "public class KnownMember { public function KnownMember() { this[\"knownMember\"] = 4; } public var knownMember:Number; }", IDynamicAccessNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitDynamicAccess(node);
+ assertOut("this[\"knownMember\"]");
+ }
+
+ @Test
+ public void testVisitDynamicAccessQName()
+ {
+ IDynamicAccessNode node = (IDynamicAccessNode) getNode(
+ "public class KnownMember { public function KnownMember() { var q:QName; this[q] = 4; } public var knownMember:Number; }", IDynamicAccessNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitDynamicAccess(node);
+ assertOut("this[q.objectAccessFormat()]");
+ }
+
+ @Test
+ public void testVisitDynamicAccessQName2()
+ {
+ IDynamicAccessNode node = (IDynamicAccessNode) getNode(
+ "public class KnownMember { public function KnownMember() { this[new QName(new Namespace('ns'), 'knownMember')] = 4; } public var knownMember:Number; }", IDynamicAccessNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitDynamicAccess(node);
+ assertOut("this[new QName(new Namespace('ns'), 'knownMember').objectAccessFormat()]");
+ }
+
@Ignore
@Override
@Test
@@ -78,9 +106,9 @@
@Test
public void testVisitLanguageIdentifierNode_SuperGetter()
{
- IClassNode node = (IClassNode)getNode("public function get defaultPrevented():Boolean " +
+ IClassNode node = (IClassNode)getNode("public function get defaultPrevented():Object " +
"{ return super.isDefaultPrevented(); }" +
- "override public function isDefaultPrevented():Boolean" +
+ "override public function isDefaultPrevented():Object" +
"{ return defaultPrevented; }", IClassNode.class);
// getters and setters don't get output until the class is output so you can't just visit the accessorNode
asBlockWalker.visitClass(node);
@@ -95,14 +123,13 @@
" var self = this;\n" +
" ;\n" +
" function isDefaultPrevented() {\n" +
- " return defaultPrevented;\n };\n" +
- " ;\n \n" +
+ " return defaultPrevented;\n };\n \n" +
"};\n\n\n" +
"RoyaleTest_A.prototype.get__defaultPrevented = function() {\n" +
" return RoyaleTest_A.superClass_.isDefaultPrevented.apply(this);\n" +
"};\n\n\n" +
"Object.defineProperties(RoyaleTest_A.prototype, /** @lends {RoyaleTest_A.prototype} */ {\n" +
- "/**\n * @export\n * @type {boolean} */\n" +
+ "/**\n * @export\n * @type {Object} */\n" +
"defaultPrevented: {\nget: RoyaleTest_A.prototype.get__defaultPrevented}}\n);");
}
@@ -130,7 +157,7 @@
IFunctionNode node = (IFunctionNode)getNode("import custom.TestProxy;import custom.custom_namespace;use namespace custom_namespace;public class RoyaleTest_A extends TestProxy { custom_namespace function foo(){if (a) super.setProperty(a, b);}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitFunction(node);
- assertOut("/**\n */\nRoyaleTest_A.prototype[\"http://ns.apache.org/2017/custom/namespace::foo\"] = function() {\n if (a)\n RoyaleTest_A.superClass_['http://ns.apache.org/2017/custom/namespace::setProperty'].apply(this, [ a, b] );\n}");
+ assertOut("/**\n * @export\n */\nRoyaleTest_A.prototype.http_$$ns_apache_org$2017$custom$namespace__foo = function() {\n if (a)\n RoyaleTest_A.superClass_.http_$$ns_apache_org$2017$custom$namespace__setProperty.apply(this, [ a, b] );\n}");
}
@Test
@@ -151,7 +178,7 @@
@Test
public void testVisitLanguageIdentifierNode_SuperMethodAsVarFunctionReference()
{
- IFileNode node = (IFileNode)getNode("package { public class RoyaleTest_A extends Base { override public function foo() {var f:Function; f = super.foo;} } }\n" +
+ IFileNode node = (IFileNode)getNode("package { public class RoyaleTest_A extends Base { override public function foo() {var f:Function = null; f = super.foo;} } }\n" +
"class Base { public function foo(){} }", IFileNode.class, 0, false);
IFunctionNode fnode = (IFunctionNode) findFirstDescendantOfType(
node, IFunctionNode.class);
@@ -160,7 +187,7 @@
IClassDefinition def = classnode.getDefinition();
((JSRoyaleEmitter)asEmitter).getModel().setCurrentClass(def);
asBlockWalker.visitFunction(fnode);
- assertOut("/**\n * @export\n * @override\n */\nRoyaleTest_A.prototype.foo = function() {\n var /** @type {Function} */ f;\n f = org.apache.royale.utils.Language.closure(RoyaleTest_A.superClass_.foo, this, 'foo');\n}");
+ assertOut("/**\n * @export\n * @override\n */\nRoyaleTest_A.prototype.foo = function() {\n var /** @type {Function} */ f = null;\n f = org.apache.royale.utils.Language.closure(RoyaleTest_A.superClass_.foo, this, 'foo');\n}");
}
@Test
@@ -243,10 +270,266 @@
}
@Test
+ public void testVisitBinaryOperatorNode_AssignmentBooleanVarToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool1:Boolean;var bool2:Boolean;bool1 = bool2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool1 = bool2");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNumberVarToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var boolean:Boolean;var number:Number;boolean = number");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("boolean = !!(number)");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentBooleanLiteralToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = true");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = true");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentPositiveNumberLiteralToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = 123.4");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = true");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNegativeNumberLiteralToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = -123");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = true");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentZeroNumberLiteralToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = 0");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = false");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentDecimalNumberLiteralToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = 0.123");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = true");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNullToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = null");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = false");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentUndefinedToBoolean()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var bool:Boolean;bool = undefined");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("bool = false");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentIntVarToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var integer1:int;var integer2:int;integer1 = integer2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("integer1 = integer2");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNumberVarToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var integer:int;var number:Number;integer = number");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("integer = (number) >> 0");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentUintVarToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var integer:int;var unsigned_integer:uint;integer = unsigned_integer");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("integer = (unsigned_integer) >> 0");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNumberLiteralToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToInt:int;numToInt = 123.4");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToInt = 123");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentIntLiteralToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToInt:int;numToInt = 321");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToInt = 321");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentHexIntLiteralToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToInt:int;numToInt = 0xabc");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToInt = 0xabc");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNegativeIntLiteralToInt()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToInt:int;numToInt = -321");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToInt = -321");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentUintVarToUint()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var unsigned_integer1:uint;var unsigned_integer2:uint;unsigned_integer1 = unsigned_integer2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("unsigned_integer1 = unsigned_integer2");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNumberVarToUint()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var unsigned_integer:uint;var number:Number;unsigned_integer = number");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("unsigned_integer = (number) >>> 0");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentIntVarToUint()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var unsigned_integer:uint;var integer:int;unsigned_integer = integer");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("unsigned_integer = (integer) >>> 0");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNumberLiteralToUint()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToUint:uint;numToUint = 123.4");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToUint = 123");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNegativeIntLiteralToUint()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToUint:uint;numToUint = -123");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToUint = 4294967173");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentHexLiteralToUint()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var numToUint:uint;numToUint = 0xabc");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("numToUint = 0xabc");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentStringVarToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var var2:String;var1 = var2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = var2");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentAnyTypeVarToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var var2:*;var1 = var2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = org.apache.royale.utils.Language.string(var2)");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentAnyTypeVarToStringSuppressed()
+ {
+ IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
+ "public class B {public var b:String; public var c:Object; /**\n * @royalenoimplicitstringconversion\n */\npublic function d() { b = c; }}",
+ IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
+ JSRoyaleDocEmitter docEmitter = (JSRoyaleDocEmitter)(asBlockWalker.getEmitter().getDocEmitter());
+ IFunctionNode methodNode = (IFunctionNode)(node.getAncestorOfType(IFunctionNode.class));
+
+ // this adds '/**\n * @royalenoimplicitstringconversion\n * @export\n */' to the output but parses
+ // the asdoc so the emitter will suppress the output
+ docEmitter.emitMethodDoc(methodNode, asBlockWalker.getProject());
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("/**\n * @royalenoimplicitstringconversion\n * @export\n */\nthis.b = this.c");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentXMLChildToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var var2:XML;var1 = var2.child");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = org.apache.royale.utils.Language.string(var2.child('child'))");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentStringLiteralToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var1 = \"hi\"");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = \"hi\"");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentNullToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var1 = null");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = null");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentUndefinedToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var1 = undefined");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = null");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentToStringFunctionCallToString()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:String;var var2:Object;var1 = var2.toString()");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = var2.toString()");
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentDatePropertyToNumber()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var var1:Number;var var2:Date;var1 = var2.month");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("var1 = var2.getMonth()");
+ }
+
+ @Test
public void testVisitBinaryOperatorNode_setterAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function c() { b = 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function c() { b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -256,7 +539,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentWithThis()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function c() { this.b = 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function c() { this.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -266,7 +549,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentPrivate()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function get b():int { return 0; } private function set b(value:int):void {}; public function test() { this.b = 1; }}",
+ "public class B {public function get b():Number { return 0; } private function set b(value:Number):void {}; public function test() { this.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -276,7 +559,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentPrivateWithNamespace()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function get b():int { return 0; } private function set b(value:int):void {}; public function test() { this.private::b = 1; }}",
+ "public class B {public function get b():Number { return 0; } private function set b(value:Number):void {}; public function test() { this.private::b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -290,7 +573,7 @@
// disconnect fileNode from parent
// set thisclass on emitter to class def
IFileNode node = (IFileNode) getNode(
- "public class B { public function c() { this.b = 1; }; public function set b(value:int):void {}}",
+ "public class B { public function c() { this.b = 1; }; public function set b(value:Number):void {}}",
IFileNode.class, WRAP_LEVEL_PACKAGE, true);
IFunctionNode fnode = (IFunctionNode) findFirstDescendantOfType(
node, IFunctionNode.class);
@@ -314,7 +597,7 @@
// disconnect fileNode from parent
// set thisclass on emitter to class def
IFileNode node = (IFileNode) getNode(
- "public class B { public function c() { b = 1; }; public function set b(value:int):void {}}",
+ "public class B { public function c() { b = 1; }; public function set b(value:Number):void {}}",
IFileNode.class, WRAP_LEVEL_PACKAGE, true);
IFunctionNode fnode = (IFunctionNode) findFirstDescendantOfType(
node, IFunctionNode.class);
@@ -334,7 +617,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentOtherInstance()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function c(other:B) { other.b = 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function c(other:B) { other.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("other.b = 1");
@@ -344,7 +627,7 @@
public void testVisitBinaryOperatorNode_nestedSetterAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function get d():B {}; public function c(other:B) { d.d.b = 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function get d():B {}; public function c(other:B) { d.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.d.d.b = 1");
@@ -354,7 +637,7 @@
public void testVisitBinaryOperatorNode_nestedSetterAssignmentOtherInstance()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function get d():B {}; public function c(other:B) { other.d.b = 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function get d():B {}; public function c(other:B) { other.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("other.d.b = 1");
@@ -364,7 +647,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentFromGetter()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function c() { b = b + 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function c() { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = this.b + 1");
@@ -374,7 +657,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentFromGetterMaskedByLocal()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function c() { var b:int; b = b + 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function c() { var b:Number; b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("b = b + 1");
@@ -384,7 +667,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentFromGetterMaskedByParam()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public function set b(value:int):void {}; public function c(b:int) { b = b + 1; }}",
+ "public class B {public function set b(value:Number):void {}; public function c(b:Number) { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("b = b + 1");
@@ -394,7 +677,7 @@
public void testVisitBinaryOperatorNode_setterAssignmentFromInternalVar()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {var b:int; public function c() { b = b + 1; }}",
+ "public class B {var b:Number; public function c() { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = this.b + 1");
@@ -404,7 +687,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignmentFromInternalVar()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {static var b:int; public function c() { b = b + 1; }}",
+ "public class B {static var b:Number; public function c() { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("B.b = B.b + 1");
@@ -414,7 +697,7 @@
public void testVisitBinaryOperatorNode_bindableAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public function c() { b = 1; }}",
+ "public class B {[Bindable] public var b:Number; public function c() { b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -424,7 +707,7 @@
public void testVisitBinaryOperatorNode_bindableAssignmentWithThis()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public function c() { this.b = 1; }}",
+ "public class B {[Bindable] public var b:Number; public function c() { this.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -434,7 +717,7 @@
public void testVisitBinaryOperatorNode_bindableAssignmentOtherInstance()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public function c(other:B) { other.b = 1; }}",
+ "public class B {[Bindable] public var b:Number; public function c(other:B) { other.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("other.b = 1");
@@ -444,7 +727,7 @@
public void testVisitBinaryOperatorNode_bindableSetterAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; [Bindable] public var d:B; public function c(other:B) { d.d.b = 1; }}",
+ "public class B {[Bindable] public var b:Number; [Bindable] public var d:B; public function c(other:B) { d.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.d.d.b = 1");
@@ -454,7 +737,7 @@
public void testVisitBinaryOperatorNode_bindableSetterAssignmentOtherInstance()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; [Bindable] public var d:B; public function c(other:B) { other.d.b = 1; }}",
+ "public class B {[Bindable] public var b:Number; [Bindable] public var d:B; public function c(other:B) { other.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("other.d.b = 1");
@@ -464,7 +747,7 @@
public void testVisitBinaryOperatorNode_bindableAssignmentFromGetter()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public function c() { b = b + 1; }}",
+ "public class B {[Bindable] public var b:Number; public function c() { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = this.b + 1");
@@ -474,7 +757,7 @@
public void testVisitBinaryOperatorNode_bindableAssignmentFromGetterMaskedByLocal()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public function c() { var b:int; b = b + 1; }}",
+ "public class B {[Bindable] public var b:Number; public function c() { var b:Number; b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("b = b + 1");
@@ -484,7 +767,7 @@
public void testVisitBinaryOperatorNode_bindableAssignmentFromGetterMaskedByParam()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public function c(b:int) { b = b + 1; }}",
+ "public class B {[Bindable] public var b:Number; public function c(b:Number) { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("b = b + 1");
@@ -494,7 +777,7 @@
public void testVisitBinaryOperatorNode_varAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public function c() { b = 1; }}",
+ "public class B {public var b:Number; public function c() { b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -504,7 +787,7 @@
public void testVisitBinaryOperatorNode_varAssignmentWithThis()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public function c() { this.b = 1; }}",
+ "public class B {public var b:Number; public function c() { this.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = 1");
@@ -514,7 +797,7 @@
public void testVisitBinaryOperatorNode_varAssignmentOtherInstance()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public function c(other:B) { other.b = 1; }}",
+ "public class B {public var b:Number; public function c(other:B) { other.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("other.b = 1");
@@ -524,7 +807,7 @@
public void testVisitBinaryOperatorNode_varSetterAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public var d:B; public function c(other:B) { d.d.b = 1; }}",
+ "public class B {[Bindable] public var b:Number; public var d:B; public function c(other:B) { d.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.d.d.b = 1");
@@ -534,7 +817,7 @@
public void testVisitBinaryOperatorNode_varVarAssignment()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public var d:B; public function c(other:B) { d.d.b = 1; }}",
+ "public class B {public var b:Number; public var d:B; public function c(other:B) { d.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.d.d.b = 1");
@@ -544,7 +827,7 @@
public void testVisitBinaryOperatorNode_varSetterAssignmentOtherInstance()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {[Bindable] public var b:int; public var d:B; public function c(other:B) { other.d.b = 1; }}",
+ "public class B {[Bindable] public var b:Number; public var d:B; public function c(other:B) { other.d.b = 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("other.d.b = 1");
@@ -554,7 +837,7 @@
public void testVisitBinaryOperatorNode_varAssignmentFromVar()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public function c() { b = b + 1; }}",
+ "public class B {public var b:Number; public function c() { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("this.b = this.b + 1");
@@ -564,7 +847,7 @@
public void testVisitBinaryOperatorNode_varAssignmentFromVarMaskedByLocal()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public function c() { var b:int; b = b + 1; }}",
+ "public class B {public var b:Number; public function c() { var b:Number; b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("b = b + 1");
@@ -574,7 +857,7 @@
public void testVisitBinaryOperatorNode_varAssignmentFromVarMaskedByParam()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:int; public function c(b:int) { b = b + 1; }}",
+ "public class B {public var b:Number; public function c(b:Number) { b = b + 1; }}",
IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitBinaryOperator(node);
assertOut("b = b + 1");
@@ -584,7 +867,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignment()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function c() { b = 1; }; public static function set b(value:int):void {}}",
+ "public class B {public function c() { b = 1; }; public static function set b(value:Number):void {}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
IBinaryOperatorNode bnode = (IBinaryOperatorNode) findFirstDescendantOfType(
node, IBinaryOperatorNode.class);
@@ -596,7 +879,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignmentWithPath()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function c() { foo.bar.B.b = 1; }; public static function set b(value:int):void {}}",
+ "public class B {public function c() { foo.bar.B.b = 1; }; public static function set b(value:Number):void {}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
IBinaryOperatorNode bnode = (IBinaryOperatorNode) findFirstDescendantOfType(
node, IBinaryOperatorNode.class);
@@ -608,7 +891,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignmentOtherInstance()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function c() { d.b = 1; }; public function set b(value:int):void {}; public static function get d():B {}}",
+ "public class B {public function c() { d.b = 1; }; public function set b(value:Number):void {}; public static function get d():B {}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
IBinaryOperatorNode bnode = (IBinaryOperatorNode) findFirstDescendantOfType(
node, IBinaryOperatorNode.class);
@@ -624,7 +907,7 @@
// disconnect fileNode from parent
// set thisclass on emitter to class def
IFileNode node = (IFileNode) getNode(
- "public class B {public function c() { d.b = 1; }; public function set b(value:int):void {}; public static function get d():B {}}",
+ "public class B {public function c() { d.b = 1; }; public function set b(value:Number):void {}; public static function get d():B {}}",
IFileNode.class, WRAP_LEVEL_PACKAGE, true);
IFunctionNode fnode = (IFunctionNode) findFirstDescendantOfType(
node, IFunctionNode.class);
@@ -644,7 +927,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignmentFromGetter()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function c() { b = b + 1; }; public static function set b(value:int):void {}; public static function get b():int {}}",
+ "public class B {public function c() { b = b + 1; }; public static function set b(value:Number):void {}; public static function get b():Number {}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
IBinaryOperatorNode bnode = (IBinaryOperatorNode) findFirstDescendantOfType(
node, IBinaryOperatorNode.class);
@@ -656,7 +939,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignmentFromGetterMaskedByLocal()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function c() { var b:int; b = b + 1; }; public static function set b(value:int):void {}; public static function get b():int {}}",
+ "public class B {public function c() { var b:Number; b = b + 1; }; public static function set b(value:Number):void {}; public static function get b():Number {}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
IBinaryOperatorNode bnode = (IBinaryOperatorNode) findFirstDescendantOfType(
node, IBinaryOperatorNode.class);
@@ -668,7 +951,7 @@
public void testVisitBinaryOperatorNode_staticSetterAssignmentFromGetterMaskedByParam()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function c(b:int) { b = b + 1; }; public static function set b(value:int):void {}; public static function get b():int {}}",
+ "public class B {public function c(b:Number) { b = b + 1; }; public static function set b(value:Number):void {}; public static function get b():Number {}}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
IBinaryOperatorNode bnode = (IBinaryOperatorNode) findFirstDescendantOfType(
node, IBinaryOperatorNode.class);
@@ -711,32 +994,6 @@
}
@Test
- public void testVisitBinaryOperatorNode_StringVarAssignmentFromObject()
- {
- IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:String; public var c:Object; public function d() { b = c; }}",
- IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
- asBlockWalker.visitBinaryOperator(node);
- assertOut("this.b = org.apache.royale.utils.Language.string(this.c)");
- }
-
- @Test
- public void testVisitBinaryOperatorNode_StringVarAssignmentFromObjectSupressed()
- {
- IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:String; public var c:Object; /**\n * @royalenoimplicitstringconversion\n */\npublic function d() { b = c; }}",
- IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
- JSRoyaleDocEmitter docEmitter = (JSRoyaleDocEmitter)(asBlockWalker.getEmitter().getDocEmitter());
- IFunctionNode methodNode = (IFunctionNode)(node.getAncestorOfType(IFunctionNode.class));
-
- // this adds '/**\n * @royalenoimplicitstringconversion\n * @export\n */' to the output but parses
- // the asdoc so the emitter will suppress the output
- docEmitter.emitMethodDoc(methodNode, asBlockWalker.getProject());
- asBlockWalker.visitBinaryOperator(node);
- assertOut("/**\n * @royalenoimplicitstringconversion\n * @export\n */\nthis.b = this.c");
- }
-
- @Test
public void testVisitBinaryOperatorNode_StringVarCompareWithObject()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
@@ -767,16 +1024,6 @@
}
@Test
- public void testVisitBinaryOperatorNode_StringAssignFromStarToString()
- {
- IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
- "public class B {public var b:String; public var c:*; public function d() { b = c.toString(); }}",
- IBinaryOperatorNode.class, WRAP_LEVEL_PACKAGE);
- asBlockWalker.visitBinaryOperator(node);
- assertOut("this.b = this.c.toString()");
- }
-
- @Test
public void testVisitBinaryOperatorNode_NumberPlusString()
{
IBinaryOperatorNode node = (IBinaryOperatorNode) getNode(
@@ -897,13 +1144,43 @@
}
@Test
+ public void testCustomNamespaceMethodAsParameter()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "import custom.custom_namespace; use namespace custom_namespace;public class B {custom_namespace function b() { function c(f:Function):void {}; c(b); }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @export\n */\nB.prototype.http_$$ns_apache_org$2017$custom$namespace__b = function() {\n var self = this;\n function c(f) {\n };\n c(org.apache.royale.utils.Language.closure(this.http_$$ns_apache_org$2017$custom$namespace__b, this, 'http://ns.apache.org/2017/custom/namespace::b'));\n}");
+ }
+
+ @Test
+ public void testCustomNamespaceMethodAsParameterWithoutUse()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "import custom.custom_namespace;public class B {custom_namespace function b() { function c(f:Function):void {}; c(custom_namespace::b); }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @export\n */\nB.prototype.http_$$ns_apache_org$2017$custom$namespace__b = function() {\n var self = this;\n function c(f) {\n };\n c(org.apache.royale.utils.Language.closure(this.http_$$ns_apache_org$2017$custom$namespace__b, this, 'http://ns.apache.org/2017/custom/namespace::b'));\n}");
+ }
+
+ @Test
public void testCustomNamespaceMethodAsVariable()
{
IFunctionNode node = (IFunctionNode) getNode(
"import custom.custom_namespace; use namespace custom_namespace;public class B {custom_namespace function b() { function c(f:Function):void {}; var f:Function = b; c(f); }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitFunction(node);
- assertOut("/**\n */\nB.prototype[\"http://ns.apache.org/2017/custom/namespace::b\"] = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Function} */ f = org.apache.royale.utils.Language.closure(this[\"http://ns.apache.org/2017/custom/namespace::b\"], this, 'http://ns.apache.org/2017/custom/namespace::b');\n c(f);\n}");
+ assertOut("/**\n * @export\n */\nB.prototype.http_$$ns_apache_org$2017$custom$namespace__b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Function} */ f = org.apache.royale.utils.Language.closure(this.http_$$ns_apache_org$2017$custom$namespace__b, this, 'http://ns.apache.org/2017/custom/namespace::b');\n c(f);\n}");
+ }
+
+ @Test
+ public void testCustomNamespaceMethodAsVariableWithoutUse()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "import custom.custom_namespace;;public class B {custom_namespace function b() { function c(f:Function):void {}; var f:Function = this.custom_namespace::b; c(f); }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @export\n */\nB.prototype.http_$$ns_apache_org$2017$custom$namespace__b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Function} */ f = org.apache.royale.utils.Language.closure(this[new QName(custom.custom_namespace, 'b').objectAccessFormat()], this, 'http://ns.apache.org/2017/custom/namespace::b');\n c(f);\n}");
}
@Test
@@ -913,7 +1190,7 @@
"import custom.custom_namespace; use namespace custom_namespace;public class B {custom_namespace function b():int { return this.b(); }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @return {number}\n */\nB.prototype[\"http://ns.apache.org/2017/custom/namespace::b\"] = function() {\n return this[\"http://ns.apache.org/2017/custom/namespace::b\"]();\n}");
+ assertOut("/**\n * @export\n * @return {number}\n */\nB.prototype.http_$$ns_apache_org$2017$custom$namespace__b = function() {\n return this.http_$$ns_apache_org$2017$custom$namespace__b();\n}");
}
@Test
@@ -940,20 +1217,20 @@
public void testMethodAsAssign()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function b() { function c(f:Function):void {}; var f:Function; f = b; c(f); }}",
+ "public class B {public function b() { function c(f:Function):void {}; var f:Function = null; f = b; c(f); }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n */\nB.prototype.b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Function} */ f;\n f = org.apache.royale.utils.Language.closure(this.b, this, 'b');\n c(f);\n}");
+ assertOut("/**\n * @export\n */\nB.prototype.b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Function} */ f = null;\n f = org.apache.royale.utils.Language.closure(this.b, this, 'b');\n c(f);\n}");
}
@Test
public void testStaticMethodAsAssign()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {static public function b() { function c(f:Function):void {}; var f:Function; f = b; c(f); }}",
+ "public class B {static public function b() { function c(f:Function):void {}; var f:Function = null; f = b; c(f); }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n */\nfoo.bar.B.b = function() {\n function c(f) {\n };\n var /** @type {Function} */ f;\n f = foo.bar.B.b;\n c(f);\n}");
+ assertOut("/**\n * @export\n */\nfoo.bar.B.b = function() {\n function c(f) {\n };\n var /** @type {Function} */ f = null;\n f = foo.bar.B.b;\n c(f);\n}");
}
@Test
@@ -963,7 +1240,7 @@
"public class B {public function b() { function c(f:Function):void {}; var f:Array = [b]; c(f[0]); }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n */\nB.prototype.b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Array} */ f = [org.apache.royale.utils.Language.closure(this.b, this, 'b')];\n c(f[0]);\n}");
+ assertOut("/**\n * @export\n */\nB.prototype.b = function() {\n var self = this;\n function c(f) {\n };\n var /** @type {Array} */ f = [org.apache.royale.utils.Language.closure(this.b, this, 'b')];\n c(/* implicit cast */ org.apache.royale.utils.Language.as(f[0], Function, true));\n}");
}
@Test
@@ -1000,22 +1277,22 @@
public void testNativeGetter()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function b():int { var s:String; return s.length; }}",
+ "public class B {public function b():Number { var s:String = null; return s.length; }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
// String.length is a getter but is a property in JS, so don't generate set_length() call.
- assertOut("/**\n * @export\n * @return {number}\n */\nfoo.bar.B.prototype.b = function() {\n var /** @type {string} */ s;\n return s.length;\n}");
+ assertOut("/**\n * @export\n * @return {number}\n */\nfoo.bar.B.prototype.b = function() {\n var /** @type {string} */ s = null;\n return s.length;\n}");
}
@Test
public void testNativeVectorGetter()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function b():int { var a:Vector.<String>; return a.length; }}",
+ "public class B {public function b():Number { var a:Vector.<String> = null; return a.length; }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
// String.length is a getter but is a property in JS, so don't generate set_length() call.
- assertOut("/**\n * @export\n * @return {number}\n */\nfoo.bar.B.prototype.b = function() {\n var /** @type {Array} */ a;\n return a.length;\n}");
+ assertOut("/**\n * @export\n * @return {number}\n */\nfoo.bar.B.prototype.b = function() {\n var /** @type {Array.<string>} */ a = null;\n return a.length;\n}");
}
//----------------------------------
@@ -1057,6 +1334,16 @@
}
@Test
+ public void testFunctionCallCustomNamespace()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "import custom.custom_namespace; public class B {custom_namespace function b() { custom_namespace::b(); }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @export\n */\nfoo.bar.B.prototype.http_$$ns_apache_org$2017$custom$namespace__b = function() {\n this.http_$$ns_apache_org$2017$custom$namespace__b();\n}");
+ }
+
+ @Test
public void testFunctionMemberFullyQualified()
{
IFunctionNode node = (IFunctionNode) getNode(
@@ -1069,9 +1356,9 @@
@Test
public void testComplexBooleanExpression()
{
- IFunctionNode node = getMethod("function foo(b:Boolean):Boolean {var c:String; var d:String; if (!(b ? c : d)) { return b;}}");
+ IFunctionNode node = getMethod("function foo(b:Boolean):Boolean {var c:String = null; var d:String = null; if (!(b ? c : d)) { return b;}}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {boolean} b\n * @return {boolean}\n */\nRoyaleTest_A.prototype.foo = function(b) {\n var /** @type {string} */ c;\n var /** @type {string} */ d;\n if (!(b ? c : d)) {\n return b;\n }\n}");
+ assertOut("/**\n * @export\n * @param {boolean} b\n * @return {boolean}\n */\nRoyaleTest_A.prototype.foo = function(b) {\n var /** @type {string} */ c = null;\n var /** @type {string} */ d = null;\n if (!(b ? c : d)) {\n return b;\n }\n}");
}
@Override
@@ -1082,11 +1369,10 @@
IFunctionNode.class);
asBlockWalker.visitFunction(node);
assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
- " var self = this;\n" +
- " var /** @type {Function} */ __localFn0__ = function() {\n" +
- " }\n" +
- " var /** @type {*} */ a = __localFn0__;\n" +
- "}");
+ " var self = this;\n" +
+ " var /** @type {*} */ a = function() {\n" +
+ " };\n" +
+ "}");
}
@Override
@@ -1099,11 +1385,10 @@
asBlockWalker.visitFunction(node);
assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
" var self = this;\n" +
- " var /** @type {Function} */ __localFn0__ = function(foo, bar) {\n" +
+ " var /** @type {Object} */ a = function(foo, bar) {\n" +
" bar = typeof bar !== 'undefined' ? bar : 'goo';\n" +
" return -1;\n" +
- " }\n" +
- " var /** @type {Object} */ a = __localFn0__;\n" +
+ " };\n" +
"}");
}
@@ -1117,12 +1402,41 @@
asBlockWalker.visitFunction(node);
assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
" var self = this;\n" +
- " var /** @type {Function} */ __localFn0__ = function(event) {\n" +
+ " addListener('foo', function(event) {\n" +
" doit();\n" +
- " }\n" +
- " addListener('foo', __localFn0__);\n" +
+ " });\n" +
"}");
}
+
+ @Override
+ @Test
+ public void testVisitLocalNamedFunction()
+ {
+ IFunctionNode node = (IFunctionNode) getNode("function a() {};", IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
+ " var self = this;\n" +
+ " function a() {\n" +
+ " };\n" +
+ " \n" +
+ "}");
+ }
+
+ @Override
+ @Test
+ public void testVisitLocalNamedFunctionWithParamsReturn()
+ {
+ IFunctionNode node = (IFunctionNode) getNode("function a(foo:int, bar:String = 'goo'):int{return -1;};", IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
+ " var self = this;\n" +
+ " function a(foo, bar) {\n" +
+ " bar = typeof bar !== 'undefined' ? bar : 'goo';\n" +
+ " return -1;\n" +
+ " };\n" +
+ " \n" +
+ "}");
+ }
@Test
public void testES5StrictAnonymousFunctions()
@@ -1133,9 +1447,8 @@
asBlockWalker.visitFunction(node);
assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
" var self = this;\n" +
- " var /** @type {Function} */ __localFn0__ = function(foo) {\n foo.bar = 10;\n }\n" +
" var /** @type {Object} */ a = {};\n" +
- " var /** @type {Function} */ b = __localFn0__;\n" +
+ " var /** @type {Function} */ b = function(foo) {\n foo.bar = 10;\n };\n" +
" var /** @type {Object} */ c = b(a);\n}");
}
@@ -1154,6 +1467,22 @@
}
@Test
+ public void testES5StrictNamedLocalFunctionsAsParameter()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "public function foo() { var a:Array = []; a.filter(function isEven(element: int, index: int, arr: Array) : Boolean {\n" +
+ " return element % 2 == 0;\n" +
+ "});}",
+ IFunctionNode.class, WRAP_LEVEL_CLASS);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @export\n */\n" +
+ "RoyaleTest_A.prototype.foo = function() {\n" +
+ " var self = this;\n" +
+ " function isEven(element, index, arr) {\n return element % 2 == 0;\n };\n var /** @type {Array} */ a = [];\n"
+ + " a.filter(isEven);\n}");
+ }
+
+ @Test
public void testParametersInInnerFunctions()
{
IFunctionNode node = (IFunctionNode) getNode(
@@ -1192,10 +1521,10 @@
public void testVisitAs2()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {public function b(o:Object):int { var a:B; a = o as B; }}",
+ "public class B {public function b(o:Object):int { var a:B = null; a = o as B; }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a;\n a = org.apache.royale.utils.Language.as(o, foo.bar.B);\n}");
+ assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = org.apache.royale.utils.Language.as(o, foo.bar.B);\n}");
}
@Test
@@ -1203,7 +1532,7 @@
{
IBinaryOperatorNode node = getBinaryNode("a as int");
asBlockWalker.visitBinaryOperator(node);
- assertOut("org.apache.royale.utils.Language.as(a, Number)");
+ assertOut("org.apache.royale.utils.Language.as(a, org.apache.royale.utils.Language.synthType('int'))");
}
@Test
@@ -1211,27 +1540,92 @@
{
IBinaryOperatorNode node = getBinaryNode("a as uint");
asBlockWalker.visitBinaryOperator(node);
- assertOut("org.apache.royale.utils.Language.as(a, Number)");
+ assertOut("org.apache.royale.utils.Language.as(a, org.apache.royale.utils.Language.synthType('uint'))");
}
@Test
public void testVisitAsMemberVariable()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class B {private var memberVar:Class; public function b(o:Object):int { var a:B; a = o as memberVar; }}",
+ "public class B {private var memberVar:Class; public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a;\n a = org.apache.royale.utils.Language.as(o, this.memberVar);\n}");
+ assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = /* implicit cast */ org.apache.royale.utils.Language.as(org.apache.royale.utils.Language.as(o, this.memberVar), foo.bar.B, true);\n}");
}
+
+ @Test
+ public void testVisitAsMemberVariableSuppressComplexImplicitCoercionA()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "public class B {private var memberVar:Class; /**\n * @royalesuppresscompleximplicitcoercion\n */\n public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @royalesuppresscompleximplicitcoercion\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = org.apache.royale.utils.Language.as(o, this.memberVar);\n}");
+ }
+
+ @Test
+ public void testVisitAsMemberVariableSuppressComplexImplicitCoercionB()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "public class B {private var memberVar:Class; /**\n * @royalesuppresscompleximplicitcoercion true\n */\n public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @royalesuppresscompleximplicitcoercion true\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = org.apache.royale.utils.Language.as(o, this.memberVar);\n}");
+ }
+
+ @Test
+ public void testVisitAsMemberVariableSuppressComplexImplicitCoercionC()
+ {
+ IFunctionNode node = (IFunctionNode) getNode(
+ "public class B {private var memberVar:Class; /**\n * @royalesuppresscompleximplicitcoercion foo.bar.B\n */\n public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @royalesuppresscompleximplicitcoercion foo.bar.B\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = org.apache.royale.utils.Language.as(o, this.memberVar);\n}");
+ }
+
+
+ @Test
+ public void testVisitAsMemberVariableSuppressComplexImplicitCoercionD()
+ {
+ //using config level setting to suppress the output by default
+ try{
+ project.config.setJsComplexImplicitCoercions(null,false);
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ }
+
+ IFunctionNode node = (IFunctionNode) getNode(
+ "public class B {private var memberVar:Class; public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = org.apache.royale.utils.Language.as(o, this.memberVar);\n}");
+ }
+
+ @Test
+ public void testVisitAsMemberVariableSuppressComplexImplicitCoercionE()
+ {
+ //using config level setting to suppress the output by default
+ try{
+ project.config.setJsComplexImplicitCoercions(null,false);
+ } catch (ConfigurationException e) {
+ e.printStackTrace();
+ }
+ //reverse the config level suppression (with 'false')
+ IFunctionNode node = (IFunctionNode) getNode(
+ "public class B {private var memberVar:Class; /**\n * @royalesuppresscompleximplicitcoercion false\n */\n public function b(o:Object):int { var a:B = null; a = o as memberVar; }}",
+ IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
+ asBlockWalker.visitFunction(node);
+ assertOut("/**\n * @royalesuppresscompleximplicitcoercion false\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.B.prototype.b = function(o) {\n var /** @type {foo.bar.B} */ a = null;\n a = /* implicit cast */ org.apache.royale.utils.Language.as(org.apache.royale.utils.Language.as(o, this.memberVar), foo.bar.B, true);\n}");
+ }
@Test
public void testVisitJSDoc()
{
IFunctionNode node = (IFunctionNode) getNode(
- "public class LinkableString {public function b(o:Object):int { var a:LinkableString; a = o as LinkableString; }}",
+ "public class LinkableString {public function b(o:Object):int { var a:LinkableString = null; a = o as LinkableString; }}",
IFunctionNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.LinkableString.prototype.b = function(o) {\n var /** @type {foo.bar.LinkableString} */ a;\n a = org.apache.royale.utils.Language.as(o, foo.bar.LinkableString);\n}");
+ assertOut("/**\n * @export\n * @param {Object} o\n * @return {number}\n */\nfoo.bar.LinkableString.prototype.b = function(o) {\n var /** @type {foo.bar.LinkableString} */ a = null;\n a = org.apache.royale.utils.Language.as(o, foo.bar.LinkableString);\n}");
}
@Override
@@ -1356,7 +1750,7 @@
@Test
public void testVisitCallFunctionReturnedFromFunction()
{
- IFunctionCallNode node = (IFunctionCallNode) getNode("function foo(a:String, b:String):Function { return null }; return foo(3, 4)(1, 2);",
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function foo(a:int, b:int):Function { return null }; return foo(3, 4)(1, 2);",
IFunctionCallNode.class);
asBlockWalker.visitFunctionCall(node);
assertOut("foo(3, 4)(1, 2)");
@@ -1380,6 +1774,350 @@
assertOut("new Fn(\"a\", \"b\", \"return a + b;\")(1, 2)");
}
+ @Test
+ public void testVisitReturnBoolean()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return true; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return true");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithBooleanLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return true; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return true");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithPositiveNumberLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return 123.4; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return true");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithNegativeNumberLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return -123; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return true");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithZeroLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return 0; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return false");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithDecimalLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return 0.01; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return true");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithNull()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return null; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return false");
+ }
+
+ @Test
+ public void testVisitReturnBooleanWithUndefined()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Boolean { return undefined; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return false");
+ }
+
+ @Test
+ public void testVisitReturnIntWithIntLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():int { return 123; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return 123");
+ }
+
+ @Test
+ public void testVisitReturnIntWithHexIntLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():int { return 0xabc; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return 0xabc");
+ }
+
+ @Test
+ public void testVisitReturnIntWithDecimalValue()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():int { return -123.4; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return -123");
+ }
+
+ @Test
+ public void testVisitReturnUintWithDecimalValue()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():uint { return 123.4; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return 123");
+ }
+
+ @Test
+ public void testVisitReturnUintWithNegativeValue()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():uint { return -123; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return 4294967173");
+ }
+
+ @Test
+ public void testVisitReturnUintWithHexLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():uint { return 0xabc; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return 0xabc");
+ }
+
+ @Test
+ public void testVisitReturnStringWithLiteral()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { return \"hi\"; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return \"hi\"");
+ }
+
+ @Test
+ public void testVisitReturnStringWithNull()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { return null; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return null");
+ }
+
+ @Test
+ public void testVisitReturnStringWithUndefined()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { return undefined; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return null");
+ }
+
+ @Test
+ public void testVisitReturnStringWithStringVar()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { var a:String; return a; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return a");
+ }
+
+ @Test
+ public void testVisitReturnStringWithAnyTypeVar()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { var a:*; return a; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return org.apache.royale.utils.Language.string(a)");
+ }
+
+ @Test
+ public void testVisitReturnStringWithToStringFunctionCall()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { var a:Object; return a.toString(); }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return a.toString()");
+ }
+
+ @Test
+ public void testVisitReturnStringWithXMLChild()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():String { var a:XML; return a.child; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return org.apache.royale.utils.Language.string(a.child('child'))");
+ }
+
+ @Test
+ public void testVisitReturnNumberWithDateProperty()
+ {
+ IReturnNode node = (IReturnNode) getNode("function():Number { var a:Date; return a.month; }", IReturnNode.class);
+ asBlockWalker.visitReturn(node);
+ assertOut("return a.getMonth()");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithIntParameterHex()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:int):void {}; a(0xabc)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(0xabc)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithIntParameterNegative()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:int):void {}; a(-123)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(-123)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithIntParameterDecimal()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:int):void {}; a(123.4)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(123)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithUintParameterHex()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:uint):void {}; a(0xabc)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(0xabc)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithUintParameterNegative()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:uint):void {}; a(-123)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(4294967173)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithUintParameterDecimal()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:uint):void {}; a(123.4)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(123)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterBoolean()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(false)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(false)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterPositiveNumberLiteral()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(123.4)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(true)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterNegativeNumberLiteral()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(-123)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(true)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterZeroNumberLiteral()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(0.0)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(false)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterLessThanOneNumberLiteral()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(0.5)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(true)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterNull()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(null)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(false)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithBooleanParameterUndefined()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Boolean):void {}; a(undefined)", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(false)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterLiteral()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; a(\"hi\");", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(\"hi\")");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterNull()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; a(null);", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(null)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterUndefined()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; a(undefined);", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(null)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterStringVar()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; var b:String; a(b);", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(b)");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterAnyTypeVar()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; var b:*; a(b);", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(org.apache.royale.utils.Language.string(b))");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterToStringFunctionCall()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; var b:Object; a(b.toString());", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(b.toString())");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithStringParameterXMLVarChild()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:String):void {}; var b:XML; a(b.child);", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(org.apache.royale.utils.Language.string(b.child('child')))");
+ }
+
+ @Test
+ public void testVisitFunctionCallWithNumberParameterDateProperty()
+ {
+ IFunctionCallNode node = (IFunctionCallNode) getNode("function a(foo:Number):void {}; var b:Date; a(b.month);", IFunctionCallNode.class);
+ asBlockWalker.visitFunctionCall(node);
+ assertOut("a(b.getMonth())");
+ }
+
protected IBackend createBackend()
{
return new RoyaleBackend();
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleFieldMembers.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleFieldMembers.java
index ea844f8..5a8af9a 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleFieldMembers.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleFieldMembers.java
@@ -82,6 +82,30 @@
}
@Test
+ public void testField_withTypeValue_IntDecimal()
+ {
+ IVariableNode node = getField("var foo:int = -123.4;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @export\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = -123");
+ }
+
+ @Test
+ public void testField_withTypeValue_UintDecimal()
+ {
+ IVariableNode node = getField("var foo:uint = 123.4;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @export\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = 123");
+ }
+
+ @Test
+ public void testField_withTypeValue_UintNegative()
+ {
+ IVariableNode node = getField("var foo:uint = -123;");
+ asBlockWalker.visitVariable(node);
+ assertOut("/**\n * @export\n * @type {number}\n */\nRoyaleTest_A.prototype.foo = 4294967173");
+ }
+
+ @Test
public void testVariable_withTypeValue_ArrayElementType()
{
IVariableNode node = (IVariableNode)getNode("public class A { function foobar():void {var foo:Number = bar[0];var bar:B;}}\n[ArrayElementType(\"Number\")]\nclass B {}",
@@ -115,7 +139,7 @@
{
IVariableNode node = getField("protected var foo:Vector.<Foo>;");
asBlockWalker.visitVariable(node);
- assertOut("/**\n * @protected\n * @type {Array}\n */\nRoyaleTest_A.prototype.foo");
+ assertOut("/**\n * @protected\n * @type {Array.<Foo>}\n */\nRoyaleTest_A.prototype.foo");
}
@Override
@@ -124,7 +148,7 @@
{
IVariableNode node = getField("protected var foo:Vector.<Vector.<Vector.<Foo>>>;");
asBlockWalker.visitVariable(node);
- assertOut("/**\n * @protected\n * @type {Array}\n */\nRoyaleTest_A.prototype.foo");
+ assertOut("/**\n * @protected\n * @type {Array.<Array.<Array.<Foo>>>}\n */\nRoyaleTest_A.prototype.foo");
}
@Override
@@ -185,7 +209,7 @@
IClassNode node = (IClassNode) getNode("import custom.custom_namespace;use namespace custom_namespace;public static var foo:Object = initFoo(); custom_namespace static function initFoo():Object { return null; }",
IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- assertOut("/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n * @type {Object}\n */\nRoyaleTest_A.foo;\n\n\n/**\n * @return {Object}\n */\nRoyaleTest_A[\"http://ns.apache.org/2017/custom/namespace::initFoo\"] = function() {\n return null;\n};\n\nRoyaleTest_A.foo = RoyaleTest_A[\"http://ns.apache.org/2017/custom/namespace::initFoo\"]();\n\n");
+ assertOut("/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @export\n * @type {Object}\n */\nRoyaleTest_A.foo;\n\n\n/**\n * @export\n * @return {Object}\n */\nRoyaleTest_A.http_$$ns_apache_org$2017$custom$namespace__initFoo = function() {\n return null;\n};\n\nRoyaleTest_A.foo = RoyaleTest_A.http_$$ns_apache_org$2017$custom$namespace__initFoo();\n\n");
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
index 4489082..23d50fa 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java
@@ -19,6 +19,8 @@
package org.apache.royale.compiler.internal.codegen.js.royale;
+import java.io.File;
+
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.internal.codegen.js.goog.TestGoogGlobalClasses;
import org.apache.royale.compiler.internal.driver.js.royale.RoyaleBackend;
@@ -122,27 +124,59 @@
assertOut("var /** @type {number} */ a = 16");
}
- @Ignore
+ @Test
public void testArrayRemoveAt()
{
- // requires FP19 or newer
- IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array(); a.removeAt(2)");
- IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
- asBlockWalker.visitFunctionCall(parentNode);
- assertOut("a.splice(2, 1)");
- }
-
- @Ignore
- public void testArrayInsertAt()
- {
- // requires FP19 or newer
- IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array(); a.insertAt(2, 'foo')");
- IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
- asBlockWalker.visitFunctionCall(parentNode);
- assertOut("a.splice(2, 0, 'foo')");
+ File pg = testAdapter.getPlayerglobal();
+ if (arrayHasInsertAtRemoveAt(pg))
+ {
+ // requires FP19 or newer
+ IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array(); a.removeAt(2)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.splice(2, 1)");
+ }
}
@Test
+ public void testArrayInsertAt()
+ {
+ File pg = testAdapter.getPlayerglobal();
+ if (arrayHasInsertAtRemoveAt(pg))
+ {
+ // requires FP19 or newer
+ IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array(); a.insertAt(2, 'foo')");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.splice(2, 0, 'foo')");
+ }
+ }
+
+ private boolean arrayHasInsertAtRemoveAt(File pg) {
+ if (pg == null) return true;
+ String path = pg.getAbsolutePath();
+ String[] parts = path.split("/");
+ if (path.contains("\\"))
+ parts = path.split("\\\\");
+ for (String part : parts)
+ {
+ if (part.contains("."))
+ {
+ // see if it is the playerglobal version string
+ String[] versionParts = part.split("\\.");
+ if (versionParts.length != 2) return false;
+ try {
+ int major = Integer.parseInt(versionParts[0]);
+ if (major >= 19) return true;
+ } catch (NumberFormatException e)
+ {
+ }
+ }
+ }
+ return false;
+ }
+
+ @Test
public void testArraySortNoArgs()
{
IBinaryOperatorNode node = getBinaryNode("var a:Array = new Array();a.sort()");
@@ -253,6 +287,16 @@
asBlockWalker.visitVariable(node);
assertOut("var /** @type {number} */ a = Math[\"PI\"]");
}
+
+ @Override
+ @Test
+ public void testClass()
+ {
+ IVariableNode node = getVariable("var a:Class = String; var b:* = new a('test')");
+ node = (IVariableNode)(node.getParent().getChild(1));
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {*} */ b = org.apache.royale.utils.Language.resolveUncertain(new a('test'))");
+ }
@Test
public void testDateSetSeconds()
@@ -345,7 +389,7 @@
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(['Hello', 'World'], 'String')");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(['Hello', 'World'])");
}
@Test
@@ -353,7 +397,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = new <String>[];");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = []");
+ assertOut("var /** @type {Array.<string>} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce']([])");
}
@Test
@@ -361,7 +405,7 @@
{
IVariableNode node = getVariable("var a:Vector.<int> = new <int>[0, 1, 2, 3];");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = [0, 1, 2, 3]");
+ assertOut("var /** @type {Array.<number>} */ a = org.apache.royale.utils.Language.synthVector('int')['coerce']([0, 1, 2, 3])");
}
@Test
@@ -369,7 +413,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = new <String>[\"one\", \"two\", \"three\";");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = [\"one\", \"two\", \"three\"]");
+ assertOut("var /** @type {Array.<string>} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce']([\"one\", \"two\", \"three\"])");
}
@Test
@@ -377,7 +421,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>();");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector()");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))()");
}
@Test
@@ -386,7 +430,7 @@
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>('Hello', 'World');");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector('Hello', 'String')");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))('Hello', 'World')");
}
@Test
@@ -395,7 +439,7 @@
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>('Hello', 'World', 'Three');");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector('Hello', 'String')");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))('Hello', 'World', 'Three')");
}
@Test
@@ -403,7 +447,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(30, 'String')");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(30)");
}
@Test
@@ -412,7 +456,7 @@
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30, 40);");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(30, 'String')");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(30, 40)");
}
@Test
@@ -421,10 +465,357 @@
IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
//MXMLC does not report an error. Should we?
- assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.Vector(['Hello', 'World'], 'String')");
+ assertOut("var /** @type {Array.<string>} */ a = new (org.apache.royale.utils.Language.synthVector('String'))(['Hello', 'World'])");
+ }
+
+ @Test
+ public void testVectorSetLength()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.length = 20)");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("a[org.apache.royale.utils.Language.SYNTH_TAG_FIELD].length = 20");
+ }
+
+ @Test
+ public void testCustomVectorSetLength()
+ {
+ project.config.setJsVectorEmulationClass(null, "Anything");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.length = 20)");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("a.length = 20");
+ }
+
+ @Test
+ public void testVectorRemoveAt()
+ {
+ File pg = testAdapter.getPlayerglobal();
+ if (arrayHasInsertAtRemoveAt(pg))
+ {
+ // requires FP19 or newer
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.removeAt(2)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a['removeAt'](2)");
+ }
+ }
+
+ @Test
+ public void testCustomVectorRemoveAt()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.removeAt(2)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.removeAt(2)");
+ }
+
+ @Test
+ public void testCustomVectorAsArrayRemoveAt()
+ {
+
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.removeAt(2)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.splice(2, 1)[0]");
}
@Test
+ public void testVectorInsertAt()
+ {
+ File pg = testAdapter.getPlayerglobal();
+ if (arrayHasInsertAtRemoveAt(pg))
+ {
+ // requires FP19 or newer
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.insertAt(2, 'foo')");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a['insertAt'](2, 'foo')");
+ }
+ }
+
+ @Test
+ public void testCustomVectorInsertAt()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.insertAt(2, 'foo')");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.insertAt(2, 'foo')");
+ }
+
+ @Test
+ public void testCustomVectorAsArrayInsertAt()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<String> = new Vector.<String>(); a.insertAt(2, 'foo')");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.splice(2, 0, 'foo')");
+ }
+
+ @Test
+ public void testCustomVector()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(['Hello', 'World'], 'String')");
+ }
+
+ @Test
+ public void testCustomVectorLiteral_1()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new <String>[];");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector([], 'String')");
+ }
+
+ @Test
+ public void testCustomVectorLiteral_1a()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new <String>[];");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array} */ a = []");
+ }
+
+ @Test
+ public void testCustomVectorLiteral_2()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<int> = new <int>[0, 1, 2, 3];");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector([0, 1, 2, 3], 'int')");
+ }
+
+ @Test
+ public void testCustomVectorLiteral_2a()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<int> = new <int>[0, 1, 2, 3];");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array} */ a = [0, 1, 2, 3]");
+ }
+
+ @Test
+ public void testCustomVectorLiteral_3()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new <String>[\"one\", \"two\", \"three\"];");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector([\"one\", \"two\", \"three\"], 'String')");
+ }
+
+ @Test
+ public void testCustomVectorLiteral_3a()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new <String>[\"one\", \"two\", \"three\"];");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array} */ a = [\"one\", \"two\", \"three\"]");
+ }
+
+ @Test
+ public void testCustomVectorNoArgs()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>();");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector([], 'String')");
+ }
+
+ @Test
+ public void testCustomVectorNoArgs2()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>();");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array} */ a = []");
+ }
+
+ @Test
+ public void testCustomVectorStringArgs()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>('Hello', 'World');");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector('Hello', 'String')");
+ }
+
+ @Test
+ public void testCustomVectorStringArgs3()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>('Hello', 'World', 'Three');");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector('Hello', 'String')");
+ }
+
+ @Test
+ public void testCustomVectorSizeArg()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(30, 'String')");
+ }
+
+ @Test
+ public void testCustomVectorSizeArg2()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.arrayAsVector(30, 'String')");
+ }
+
+ @Test
+ public void testCustomVectorSizeAndFixedArgs()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30, true);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(30, 'String', true)");
+ }
+
+ @Test
+ public void testCustomVectorSizeAndFixedArgs2()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30, true);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.arrayAsVector(30, 'String')");
+ }
+
+ @Test
+ public void testCustomVectorNumberArgs()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30, 40);");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(30, 'String')");
+ }
+
+ @Test
+ public void testCustomVectorNumberArgs2()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(30, 40);");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.arrayAsVector(30, 'String')");
+ }
+
+ @Test
+ public void testCustomVectorArrayArg()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(['Hello', 'World'], 'String')");
+ }
+
+ @Test
+ public void testCustomVectorArrayArg2()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = new Vector.<String>(['Hello', 'World']);");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {Array} */ a = org.apache.royale.utils.Language.arrayAsVector(['Hello', 'World'], 'String')");
+ }
+
+ @Test
+ public void testDefaultVectorClassRepresentation()
+ {
+ IVariableNode node = getVariable("var a:Class = Vector.<String>;");
+ asBlockWalker.visitVariable(node);
+ //MXMLC does not report an error. Should we?
+ assertOut("var /** @type {Object} */ a = org.apache.royale.utils.Language.synthVector('String')");
+ }
+
+ @Test
+ public void testCustomVectorClassRepresentation()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Class = Vector.<String>;");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Object} */ a = CustomVector");
+ }
+
+ @Test
+ public void testCustomVectorClassRepresentation2()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Class = Vector.<String>;");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Object} */ a = Array");
+ }
+
+ @Test
+ public void testDefaultVectorSortNumericArg()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<Number> = new Vector.<Number>();a.sort(Array.NUMERIC)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("org.apache.royale.utils.Language.sort(a, 16)");
+ }
+
+ @Test
+ public void testCustomVectorRepresentationSortNumericArg()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<Number> = new Vector.<Number>();a.sort(Array.NUMERIC)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("a.sort(16)");
+ }
+
+ @Test
+ public void testCustomVectorAsArrayRepresentationSortNumericArg()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IBinaryOperatorNode node = getBinaryNode("var a:Vector.<Number> = new Vector.<Number>();a.sort(Array.NUMERIC)");
+ IFunctionCallNode parentNode = (IFunctionCallNode)(node.getParent());
+ asBlockWalker.visitFunctionCall(parentNode);
+ assertOut("org.apache.royale.utils.Language.sort(a, 16)");
+ }
+
+ @Override
+ @Test
+ public void testBoolean()
+ {
+ IVariableNode node = getVariable("var a:Boolean = new Boolean(1);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = Boolean(1)");
+ }
+
+ @Override
+ @Test
+ public void testNumber()
+ {
+ IVariableNode node = getVariable("var a:Number = new Number(\"1\");");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = Number(\"1\")");
+ }
+
+ @Override
+ @Test
+ public void testString()
+ {
+ IVariableNode node = getVariable("var a:String = new String(\"100\");");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = String(\"100\")");
+ }
+
+ @Test
public void testXML()
{
IVariableNode node = getVariable("var a:XML = new XML(\"<top attr1='cat'><child attr2='dog'><grandchild attr3='fish'>text</grandchild></child></top>\");");
@@ -675,7 +1066,7 @@
IASNode parentNode = node.getParent();
node = (IVariableNode) parentNode.getChild(1);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {number} */ b = a.child('child').length()");
+ assertOut("var /** @type {number} */ b = (a.child('child').length()) >> 0");
}
@Test
@@ -688,6 +1079,16 @@
assertOut("var /** @type {XMLList} */ b = a.descendants('child')");
}
+ @Test
+ public void testXMLDoubleDotTwice()
+ {
+ IVariableNode node = getVariable("var a:XML = new XML(\"<top attr1='cat'><child attr2='dog'><grandchild attr3='fish'>text</grandchild></child></top>\");var b:XMLList = a..child..grandchild;");
+ IASNode parentNode = node.getParent();
+ node = (IVariableNode) parentNode.getChild(1);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {XMLList} */ b = a.descendants('child').descendants('grandchild')");
+ }
+
@Ignore
public void testXMLDoubleDotLiteral()
{
@@ -835,6 +1236,14 @@
}
@Test
+ public void testXMLSetChildAttributeBracketProp()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var z:String = 'prop';var a:XML = new XML(\"<top attr1='cat'><child attr2='dog'><grandchild attr3='fish'>text</grandchild></child></top>\");a.child.@['attr3'] = 'foo'");
+ asBlockWalker.visitBinaryOperator(node);
+ assertOut("a.child('child').setAttribute('attr3', 'foo')");
+ }
+
+ @Test
public void testXMLListSetAttribute()
{
IBinaryOperatorNode node = getBinaryNode("var a:XMLList;a[1].@bar = 'foo'");
@@ -921,7 +1330,7 @@
{
IForLoopNode node = getForLoopNode("var a:XML = new XML(\"<top attr1='cat'><child attr2='dog'><grandchild attr3='fish'>text</grandchild></child></top>\");for each (var p:XMLList in a) var i:int = p.length();");
asBlockWalker.visitForLoop(node);
- assertOut("var foreachiter0_target = a;\nfor (var foreachiter0 in foreachiter0_target.elementNames()) \n{\nvar p = foreachiter0_target[foreachiter0];\n\n var /** @type {number} */ i = p.length();}\n");
+ assertOut("var foreachiter0_target = a;\nfor (var foreachiter0 in foreachiter0_target.elementNames()) \n{\nvar p = foreachiter0_target[foreachiter0];\n\n var /** @type {number} */ i = (p.length()) >> 0;}\n");
}
@Test
@@ -929,7 +1338,7 @@
{
IForLoopNode node = getForLoopNode("var a:*;for each (var p:XML in (a as XMLList)) var i:int = p.length();");
asBlockWalker.visitForLoop(node);
- assertOut("var foreachiter0_target = org.apache.royale.utils.Language.as(a, XMLList);\nfor (var foreachiter0 in foreachiter0_target.elementNames()) \n{\nvar p = foreachiter0_target[foreachiter0];\n\n var /** @type {number} */ i = p.length();}\n");
+ assertOut("var foreachiter0_target = org.apache.royale.utils.Language.as(a, XMLList);\nfor (var foreachiter0 in foreachiter0_target.elementNames()) \n{\nvar p = foreachiter0_target[foreachiter0];\n\n var /** @type {number} */ i = (p.length()) >> 0;}\n");
}
@Test
@@ -937,7 +1346,7 @@
{
IForLoopNode node = getForLoopNode("var a:*;for each (var p:XML in XMLList(a)) var i:int = p.length();");
asBlockWalker.visitForLoop(node);
- assertOut("var foreachiter0_target = XMLList(a);\nfor (var foreachiter0 in foreachiter0_target.elementNames()) \n{\nvar p = foreachiter0_target[foreachiter0];\n\n var /** @type {number} */ i = p.length();}\n");
+ assertOut("var foreachiter0_target = XMLList.conversion(a);\nfor (var foreachiter0 in foreachiter0_target.elementNames()) \n{\nvar p = foreachiter0_target[foreachiter0];\n\n var /** @type {number} */ i = (p.length()) >> 0;}\n");
}
@Test
@@ -1056,7 +1465,7 @@
"import custom.TestProxy; public class B {public function b() { var a:TestProxy = new TestProxy();for each (var p:String in a) var i:int = p.length; }}",
IForLoopNode.class, WRAP_LEVEL_PACKAGE, true);
asBlockWalker.visitForLoop(node);
- assertOut("var foreachiter0_target = a;\nfor (var foreachiter0 in foreachiter0_target.propertyNames()) \n{\nvar p = foreachiter0_target.getProperty(foreachiter0);\n\n var /** @type {number} */ i = p.length;}\n");
+ assertOut("var foreachiter0_target = a;\nfor (var foreachiter0 in foreachiter0_target.propertyNames()) \n{\nvar p = foreachiter0_target.getProperty(foreachiter0);\n\n var /** @type {number} */ i = (p.length) >> 0;}\n");
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java
index 2c6eaf7..a06bfa0 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalFunctions.java
@@ -100,11 +100,20 @@
asBlockWalker.visitVariable(node);
assertOut("var /** @type {Array} */ a = Array(['Hello', 'World'])");
}
+
+ @Override
+ @Test
+ public void testObject()
+ {
+ IVariableNode node = getVariable("var a:Object = Object(\"1\");");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Object} */ a = org.apache.royale.utils.Language.resolveUncertain(Object(\"1\"))");
+ }
@Test
public void testParseInt()
{
- IVariableNode node = getVariable("var a:int = parseInt('1.8');");
+ IVariableNode node = getVariable("var a:Number = parseInt('1.8');");
asBlockWalker.visitVariable(node);
assertOut("var /** @type {number} */ a = parseInt('1.8', undefined)");
}
@@ -112,7 +121,7 @@
@Test
public void testParseIntTwoArgs()
{
- IVariableNode node = getVariable("var a:int = parseInt('1.8', 16);");
+ IVariableNode node = getVariable("var a:Number = parseInt('1.8', 16);");
asBlockWalker.visitVariable(node);
assertOut("var /** @type {number} */ a = parseInt('1.8', 16)");
}
@@ -159,6 +168,24 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {Array.<string>} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce'](['Hello', 'World'])");
+ }
+
+ @Test
+ public void testCustomVector()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(['Hello', 'World'], 'String')");
+ }
+
+ @Test
+ public void testCustomVectorAsArray()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
+ asBlockWalker.visitVariable(node);
assertOut("var /** @type {Array} */ a = ['Hello', 'World'].slice()");
}
@@ -184,8 +211,29 @@
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(30);");
asBlockWalker.visitVariable(node);
// MXMLC doesn't report an error either. Maybe we should.
+ assertOut("var /** @type {Array.<string>} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce'](30)");
+ }
+
+ @Test
+ public void testCustomVectorSizeArg()
+ {
+ project.config.setJsVectorEmulationClass(null, "CustomVector");
+ IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(30);");
+ asBlockWalker.visitVariable(node);
+ // MXMLC doesn't report an error either. Maybe we should.
+ assertOut("var /** @type {CustomVector} */ a = new CustomVector(30, 'String')");
+ }
+
+ @Test
+ public void testCustomVectorAsArraySizeArg()
+ {
+ project.config.setJsVectorEmulationClass(null, "Array");
+ IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(30);");
+ asBlockWalker.visitVariable(node);
+ // MXMLC doesn't report an error either. Maybe we should.
assertOut("var /** @type {Array} */ a = 30.slice()");
}
+
@Test
public void testVectorNumberArgs()
@@ -200,7 +248,7 @@
{
IVariableNode node = getVariable("var a:Vector.<String> = Vector.<String>(['Hello', 'World']);");
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {Array} */ a = ['Hello', 'World'].slice()");
+ assertOut("var /** @type {Array.<string>} */ a = org.apache.royale.utils.Language.synthVector('String')['coerce'](['Hello', 'World'])");
}
@Override
@@ -234,7 +282,7 @@
// (erikdebruin) E4X in Javascript is obsolete.
// Ref.: https://developer.mozilla.org/en-US/docs/E4X
- assertOut("var /** @type {XMLList} */ a = XMLList('<!-- comment -->')");
+ assertOut("var /** @type {XMLList} */ a = XMLList.conversion('<!-- comment -->')");
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleInterface.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleInterface.java
index 2ee8941..6dc1bca 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleInterface.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleInterface.java
@@ -90,7 +90,7 @@
+ "function baz1():Object;"
+ "function baz2(value:Object):void;}");
asBlockWalker.visitInterface(node);
- assertOut("/**\n * @interface\n */\nIA = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('IA', IA);\n/**\n * @return {Object}\n */\nIA.prototype.baz1 = function() {\n};\n/**\n * @param {Object} value\n */\nIA.prototype.baz2 = function(value) {\n};");
+ assertOut("/**\n * @interface\n */\nIA = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('IA', IA);\n/**\n * @export\n * @return {Object}\n */\nIA.prototype.baz1 = function() {\n};\n/**\n * @export\n * @param {Object} value\n */\nIA.prototype.baz2 = function(value) {\n};");
}
@Override
@@ -103,7 +103,7 @@
+ "function baz1():Object;"
+ "function baz2(value:Object):void;}");
asBlockWalker.visitInterface(node);
- assertOut("/**\n * @interface\n */\nIA = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('IA', IA);\n/** * @type {Object}\n */IA.prototype.foo1;\n/**\n * @return {Object}\n */\nIA.prototype.baz1 = function() {\n};\n/**\n * @param {Object} value\n */\nIA.prototype.baz2 = function(value) {\n};");
+ assertOut("/**\n * @interface\n */\nIA = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('IA', IA);\n/** * @type {Object}\n */IA.prototype.foo1;\n/**\n * @export\n * @return {Object}\n */\nIA.prototype.baz1 = function() {\n};\n/**\n * @export\n * @param {Object} value\n */\nIA.prototype.baz2 = function(value) {\n};");
}
protected IBackend createBackend()
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleMethodMembers.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleMethodMembers.java
index f05f4bc..b7664c2 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleMethodMembers.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleMethodMembers.java
@@ -38,7 +38,7 @@
{
IFunctionNode node = getMethod("function foo():int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function() {\n return -1;\n}");
+ assertOut("/**\n * @export\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function() {\n return -1;\n}");
}
@Override
@@ -47,7 +47,7 @@
{
IFunctionNode node = getMethod("function foo(bar):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {*} bar\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar) {\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {*} bar\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar) {\n return -1;\n}");
}
@Override
@@ -56,7 +56,7 @@
{
IFunctionNode node = getMethod("function foo(bar:String):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {string} bar\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar) {\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {string} bar\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar) {\n return -1;\n}");
}
@Override
@@ -65,7 +65,7 @@
{
IFunctionNode node = getMethod("function foo(bar:String = \"baz\"):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {string=} bar\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar) {\n bar = typeof bar !== 'undefined' ? bar : \"baz\";\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {string=} bar\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar) {\n bar = typeof bar !== 'undefined' ? bar : \"baz\";\n return -1;\n}");
}
@Override
@@ -74,7 +74,7 @@
{
IFunctionNode node = getMethod("function foo(bar:String, baz:int = null):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar, baz) {\n baz = typeof baz !== 'undefined' ? baz : null;\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar, baz) {\n baz = typeof baz !== 'undefined' ? baz : null;\n return -1;\n}");
}
@Test
@@ -82,7 +82,7 @@
{
IFunctionNode node = getMethodWithPackage("static const BAR:String = 'bar'; function foo(bar:String = RoyaleTest_A.BAR):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {string=} bar\n * @return {number}\n */\nfoo.bar.RoyaleTest_A.prototype.foo = function(bar) {\n bar = typeof bar !== 'undefined' ? bar : foo.bar.RoyaleTest_A.BAR;\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {string=} bar\n * @return {number}\n */\nfoo.bar.RoyaleTest_A.prototype.foo = function(bar) {\n bar = typeof bar !== 'undefined' ? bar : foo.bar.RoyaleTest_A.BAR;\n return -1;\n}");
}
@Override
@@ -91,7 +91,7 @@
{
IFunctionNode node = getMethod("function foo(bar:String, ...rest):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {string} bar\n * @param {...} rest\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar, rest) {\n rest = Array.prototype.slice.call(arguments, 1);\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {string} bar\n * @param {...} rest\n * @return {number}\n */\nRoyaleTest_A.prototype.foo = function(bar, rest) {\n rest = Array.prototype.slice.call(arguments, 1);\n return -1;\n}");
}
@Override
@@ -100,7 +100,7 @@
{
IFunctionNode node = getMethod("import custom.custom_namespace;custom_namespace function foo(bar:String, baz:int = null):int{ return -1;}");
asBlockWalker.visitFunction(node);
- assertOut("/**\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nRoyaleTest_A.prototype[\"http://ns.apache.org/2017/custom/namespace::foo\"] = function(bar, baz) {\n baz = typeof baz !== 'undefined' ? baz : null;\n return -1;\n}");
+ assertOut("/**\n * @export\n * @param {string} bar\n * @param {number=} baz\n * @return {number}\n */\nRoyaleTest_A.prototype.http_$$ns_apache_org$2017$custom$namespace__foo = function(bar, baz) {\n baz = typeof baz !== 'undefined' ? baz : null;\n return -1;\n}");
}
//--------------------------------------------------------------------------
@@ -147,7 +147,7 @@
{
IClassNode node = (IClassNode) getNode("public function RoyaleTest_A(){}; private function foo(value:int):String{return value;}; private function bar():String{if(true){while(i){return this.foo(42);}}};", IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- assertOut("/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @private\n * @param {number} value\n * @return {string}\n */\nRoyaleTest_A.prototype.foo = function(value) {\n return value;\n};\n\n\n/**\n * @private\n * @return {string}\n */\nRoyaleTest_A.prototype.bar = function() {\n if (true) {\n while (i) {\n return this.foo(42);\n }\n }\n};");
+ assertOut("/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @private\n * @param {number} value\n * @return {string}\n */\nRoyaleTest_A.prototype.foo = function(value) {\n return org.apache.royale.utils.Language.string(value);\n};\n\n\n/**\n * @private\n * @return {string}\n */\nRoyaleTest_A.prototype.bar = function() {\n if (true) {\n while (i) {\n return this.foo(42);\n }\n }\n};");
}
@Test
@@ -155,7 +155,7 @@
{
IClassNode node = (IClassNode) getNode("public function RoyaleTest_A(){}; private function foo(value:int):String{return value;}; private function bar():void{if(true){while(i){foo(42);}}};", IClassNode.class, WRAP_LEVEL_CLASS);
asBlockWalker.visitClass(node);
- assertOut("/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @private\n * @param {number} value\n * @return {string}\n */\nRoyaleTest_A.prototype.foo = function(value) {\n return value;\n};\n\n\n/**\n * @private\n */\nRoyaleTest_A.prototype.bar = function() {\n if (true) {\n while (i) {\n this.foo(42);\n }\n }\n};");
+ assertOut("/**\n * @constructor\n */\nRoyaleTest_A = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n/**\n * @private\n * @param {number} value\n * @return {string}\n */\nRoyaleTest_A.prototype.foo = function(value) {\n return org.apache.royale.utils.Language.string(value);\n};\n\n\n/**\n * @private\n */\nRoyaleTest_A.prototype.bar = function() {\n if (true) {\n while (i) {\n this.foo(42);\n }\n }\n};");
}
@Override
@@ -206,6 +206,14 @@
assertOut("/**\n * @export\n * @return {string}\n */\nRoyaleTest_A.prototype.foo = function() {\n \n/**\n * @const\n * @type {string}\n */\nvar A = 'Hello World';\n return A;\n}");
}
+ @Test
+ public void testAbstractMethod()
+ {
+ IClassNode node = (IClassNode) getNode("public abstract class A { public abstract function a(arg1:String):Object; }", IClassNode.class, WRAP_LEVEL_PACKAGE);
+ asBlockWalker.visitClass(node);
+ assertOut("/**\n * @constructor\n */\nA = function() {\n};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('A', A);\n\n\n/**\n * @export\n * @param {string} arg1\n * @return {Object}\n */\nA.prototype.a = function(arg1) {\n};");
+ }
+
@Override
protected IBackend createBackend()
{
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyalePackage.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyalePackage.java
index 15a4d07..53756f1 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyalePackage.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyalePackage.java
@@ -61,7 +61,7 @@
// with block disallows implicit blocks from getting { }
// (erikdebruin) the constuctor IS the class definition, in 'goog' JS,
- // therefor we need to write out implicit constructors
+ // therefor we need to write out implicit constructors
// (if I understand the term correctly)
IFileNode node = compileAS("package {public class A{}}");
@@ -105,7 +105,13 @@
" accessors: function () {return {};},\n" +
" methods: function () {return {};}\n" +
" };\n" +
- "};\n");
+ "};\n"+
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n");
}
@Override
@@ -153,7 +159,13 @@
" accessors: function () {return {};},\n" +
" methods: function () {return {};}\n" +
" };\n" +
- "};\n");
+ "};\n"+
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n");
}
@Override
@@ -163,49 +175,63 @@
IFileNode node = compileAS("package foo.bar.baz {public class A{public function A(){}}}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n");
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n"
+
+ );
}
@Override
@@ -215,54 +241,66 @@
IFileNode node = compileAS("package foo.bar.baz {public class A{public function A(){if (a){for (var i:Object in obj){doit();}}}}}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- " if (a) {\n" +
- " for (var /** @type {Object} */ i in obj) {\n" +
- " doit();\n" +
- " }\n" +
- " }\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ " if (a) {\n" +
+ " for (var /** @type {Object} */ i in obj) {\n" +
+ " doit();\n" +
+ " }\n" +
+ " }\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n");
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n");
}
@Test
@@ -271,50 +309,62 @@
IFileNode node = compileAS("package foo.bar.baz {[Event(name='add', type='mx.events.FlexEvent')]\npublic class A{public function A(){}}}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " },\n" +
- " metadata: function () { return [ { name: 'Event', args: [ { key: 'name', value: 'add' }, { key: 'type', value: 'mx.events.FlexEvent' } ] } ]; }\n" +
- " };\n" +
- "};\n");
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " },\n" +
+ " metadata: function () { return [ { name: 'Event', args: [ { key: 'name', value: 'add' }, { key: 'type', value: 'mx.events.FlexEvent' } ] } ]; }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n");
}
@Test
@@ -323,58 +373,71 @@
IFileNode node = compileAS("package foo.bar.baz {[Event(name='add', type='mx.events.FlexEvent')]\npublic class A{public function A(){}\n[Before]\npublic function foo() {}}}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.foo = function() {\n};\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.foo = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'},\n" +
- " 'foo': { type: '', declaredBy: 'foo.bar.baz.A', metadata: function () { return [ { name: 'Before' } ]; }}\n" +
- " };\n" +
- " },\n" +
- " metadata: function () { return [ { name: 'Event', args: [ { key: 'name', value: 'add' }, { key: 'type', value: 'mx.events.FlexEvent' } ] } ]; }\n" +
- " };\n" +
- "};\n" +
- "goog.exportProperty(foo.bar.baz.A.prototype, 'foo', foo.bar.baz.A.prototype.foo);\n");
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'},\n" +
+ " 'foo': { type: '', declaredBy: 'foo.bar.baz.A', metadata: function () { return [ { name: 'Before' } ]; }}\n" +
+ " };\n" +
+ " },\n" +
+ " metadata: function () { return [ { name: 'Event', args: [ { key: 'name', value: 'add' }, { key: 'type', value: 'mx.events.FlexEvent' } ] } ]; }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "goog.exportProperty(foo.bar.baz.A.prototype, 'foo', foo.bar.baz.A.prototype.foo);\n" );
}
@Test
@@ -390,86 +453,111 @@
"}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "goog.provide('foo.bar.baz.A.InternalClass');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- " var /** @type {foo.bar.baz.A.InternalClass} */ internalClass = new foo.bar.baz.A.InternalClass();\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n/" +
- "**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "goog.provide('foo.bar.baz.A.InternalClass');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ " var /** @type {foo.bar.baz.A.InternalClass} */ internalClass = new foo.bar.baz.A.InternalClass();\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n");
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n"
+ );
}
@Test
@@ -500,34 +588,46 @@
" */\n" +
"foo.bar.baz.A = function() {\n" +
" foo.bar.baz.A.internalFunction();\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "};\n" +
"\n" +
- "\n/" +
- "**\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
" * Metadata\n" +
" *\n" +
" * @type {Object.<string, Array.<Object>>}\n" +
" */\n" +
"foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
"\n" +
"\n" +
"\n" +
@@ -563,34 +663,46 @@
" */\n" +
"foo.bar.baz.A = function() {\n" +
" foo.bar.baz.A.internalVar = 3;\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "};\n" +
"\n" +
- "\n/" +
- "**\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
" * Metadata\n" +
" *\n" +
" * @type {Object.<string, Array.<Object>>}\n" +
" */\n" +
"foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
"\n" +
"\n" +
"\n" +
@@ -598,7 +710,8 @@
" * @export\n" +
" * @type {number}\n" +
" */\n" +
- "foo.bar.baz.A.internalVar = 2");
+ "foo.bar.baz.A.internalVar = 2"
+ );
}
@Test
@@ -621,120 +734,152 @@
"}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "goog.provide('foo.bar.baz.A.InternalClass');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- " var /** @type {foo.bar.baz.A.InternalClass} */ internalClass = new foo.bar.baz.A.InternalClass();\n" +
- " var /** @type {string} */ myString = foo.bar.baz.A.InternalClass.someString;\n" +
- " myString = foo.bar.baz.A.InternalClass.someStaticFunction();\n" +
- " myString = internalClass.someMethod();\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
- " variables: function () {return {};},\n" +
- " accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " * @type {string}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.someString = \"foo\";\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " * @return {string}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.someStaticFunction = function() {\n" +
- " return \"bar\";\n" +
- "};\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " * @return {string}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.someMethod = function() {\n" +
- " return \"baz\";\n" +
- "};\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "goog.provide('foo.bar.baz.A.InternalClass');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ " var /** @type {foo.bar.baz.A.InternalClass} */ internalClass = new foo.bar.baz.A.InternalClass();\n" +
+ " var /** @type {string} */ myString = foo.bar.baz.A.InternalClass.someString;\n" +
+ " myString = foo.bar.baz.A.InternalClass.someStaticFunction();\n" +
+ " myString = internalClass.someMethod();\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {return {};},\n" +
+ " accessors: function () {return {};},\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @type {string}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.someString = \"foo\";\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @return {string}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.someStaticFunction = function() {\n" +
+ " return \"bar\";\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @return {string}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.someMethod = function() {\n" +
+ " return \"baz\";\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {\n" +
" return {\n" +
- " '|someString': { type: 'String'}\n" +
+ " '|someString': { type: 'String', get_set: function (/** * */ v) {return v !== undefined ? foo.bar.baz.A.InternalClass.someString = v : foo.bar.baz.A.InternalClass.someString;}}\n" +
" };\n" +
" },\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'},\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'},\n" +
" '|someStaticFunction': { type: 'String', declaredBy: 'foo.bar.baz.A.InternalClass'},\n" +
- " 'someMethod': { type: 'String', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n");
+ " 'someMethod': { type: 'String', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "/**\n" +
+ " * Provide reflection support for distinguishing dynamic fields on class object (static)\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {Array<string>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO.statics = Object.keys(foo.bar.baz.A.InternalClass);\n"
+ );
}
@Test
@@ -762,130 +907,159 @@
"}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "goog.provide('foo.bar.baz.A.InternalClass');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- " var /** @type {foo.bar.baz.A.InternalClass} */ internalClass = new foo.bar.baz.A.InternalClass();\n" +
- " this.myString = internalClass.someString;\n" +
- " internalClass.someString = this.myString;\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "foo.bar.baz.A.prototype.get__myString = function() {\n" +
- " return null;\n" +
- "};\n" +
- "\n" +
- "\n" +
- "foo.bar.baz.A.prototype.set__myString = function(value) {\n" +
- "};\n" +
- "\n" +
- "\n" +
- "Object.defineProperties(foo.bar.baz.A.prototype, /** @lends {foo.bar.baz.A.prototype} */ {\n" +
- "/**\n * @export\n * @type {string} */\n" +
- "myString: {\n" +
- "get: foo.bar.baz.A.prototype.get__myString,\n" +
- "set: foo.bar.baz.A.prototype.set__myString}}\n" +
- ");\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
- " variables: function () {return {};},\n" +
- " accessors: function () {\n" +
- " return {\n" +
- " 'myString': { type: 'String', access: 'readwrite', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " },\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
- "\n" +
- "\n" +
- "foo.bar.baz.A.InternalClass.prototype.get__someString = function() {\n" +
- " return null;\n" +
- "};\n" +
- "\n" +
- "\n" +
- "foo.bar.baz.A.InternalClass.prototype.set__someString = function(value) {\n" +
- "};\n" +
- "\n" +
- "\n" +
- "Object.defineProperties(foo.bar.baz.A.InternalClass.prototype, /** @lends {foo.bar.baz.A.InternalClass.prototype} */ {\n" +
- "/**\n * @export\n * @type {string} */\n" +
- "someString: {\n" +
- "get: foo.bar.baz.A.InternalClass.prototype.get__someString,\n" +
- "set: foo.bar.baz.A.InternalClass.prototype.set__someString}}\n" +
- ");\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "goog.provide('foo.bar.baz.A.InternalClass');\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ " var /** @type {foo.bar.baz.A.InternalClass} */ internalClass = new foo.bar.baz.A.InternalClass();\n" +
+ " this.myString = internalClass.someString;\n" +
+ " internalClass.someString = this.myString;\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "foo.bar.baz.A.prototype.get__myString = function() {\n" +
+ " return null;\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "foo.bar.baz.A.prototype.set__myString = function(value) {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "Object.defineProperties(foo.bar.baz.A.prototype, /** @lends {foo.bar.baz.A.prototype} */ {\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @type {string} */\n" +
+ "myString: {\n" +
+ "get: foo.bar.baz.A.prototype.get__myString,\n" +
+ "set: foo.bar.baz.A.prototype.set__myString}}\n" +
+ ");\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
- " accessors: function () {\n" +
- " return {\n" +
- " 'someString': { type: 'String', access: 'readwrite', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
- " };\n" +
- " },\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n");
+ " accessors: function () {\n" +
+ " return {\n" +
+ " 'myString': { type: 'String', access: 'readwrite', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " },\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
+ "\n" +
+ "\n" +
+ "foo.bar.baz.A.InternalClass.prototype.get__someString = function() {\n" +
+ " return null;\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "foo.bar.baz.A.InternalClass.prototype.set__someString = function(value) {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "Object.defineProperties(foo.bar.baz.A.InternalClass.prototype, /** @lends {foo.bar.baz.A.InternalClass.prototype} */ {\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @type {string} */\n" +
+ "someString: {\n" +
+ "get: foo.bar.baz.A.InternalClass.prototype.get__someString,\n" +
+ "set: foo.bar.baz.A.InternalClass.prototype.set__someString}}\n" +
+ ");\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {return {};},\n" +
+ " accessors: function () {\n" +
+ " return {\n" +
+ " 'someString': { type: 'String', access: 'readwrite', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
+ " };\n" +
+ " },\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n"
+ );
}
@Test
@@ -908,140 +1082,178 @@
"}");
asBlockWalker.visitFile(node);
assertOutWithMetadata("/**\n" +
- " * foo.bar.baz.A\n" +
- " *\n" +
- " * @fileoverview\n" +
- " *\n" +
- " * @suppress {checkTypes|accessControls}\n" +
- " */\n" +
- "\n" +
- "goog.provide('foo.bar.baz.A');\n" +
- "goog.provide('foo.bar.baz.A.ITestInterface');\n" +
- "goog.provide('foo.bar.baz.A.InternalClass');\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " */\n" +
- "foo.bar.baz.A = function() {\n" +
- " var /** @type {foo.bar.baz.A.ITestInterface} */ internalClass = org.apache.royale.utils.Language.as(new foo.bar.baz.A.InternalClass(), foo.bar.baz.A.ITestInterface);\n" +
- " internalClass.test();\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
- " variables: function () {return {};},\n" +
- " accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @interface\n" +
- " */\n" +
- "foo.bar.baz.A.ITestInterface = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A.ITestInterface', foo.bar.baz.A.ITestInterface);\n" +
- "foo.bar.baz.A.ITestInterface.prototype.test = function() {\n" +
- "};\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.ITestInterface.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'ITestInterface', qName: 'foo.bar.baz.A.ITestInterface', kind: 'interface' }] };\n" +
+ " * foo.bar.baz.A\n" +
+ " *\n" +
+ " * @fileoverview\n" +
+ " *\n" +
+ " * @suppress {checkTypes|accessControls}\n" +
+ " */\n" +
+ "\n" +
+ "goog.provide('foo.bar.baz.A');\n" +
+ "goog.provide('foo.bar.baz.A.ITestInterface');\n" +
+ "goog.provide('foo.bar.baz.A.InternalClass');\n" +
"\n" +
"\n" +
"\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.ITestInterface.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " */\n" +
+ "foo.bar.baz.A = function() {\n" +
+ " var /** @type {foo.bar.baz.A.ITestInterface} */ internalClass = org.apache.royale.utils.Language.as(new foo.bar.baz.A.InternalClass(), foo.bar.baz.A.ITestInterface);\n" +
+ " internalClass.test();\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A', foo.bar.baz.A);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'A', qName: 'foo.bar.baz.A', kind: 'class' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'test': { type: 'void', declaredBy: 'foo.bar.baz.A.ITestInterface'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @constructor\n" +
- " * @implements {foo.bar.baz.A.ITestInterface}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * @export\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.test = function() {\n" +
- "};\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Metadata\n" +
- " *\n" +
- " * @type {Object.<string, Array.<Object>>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }], interfaces: [foo.bar.baz.A.ITestInterface] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
- " variables: function () {return {};},\n" +
- " accessors: function () {return {};},\n" +
- " methods: function () {\n" +
- " return {\n" +
- " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'},\n" +
- " 'test': { type: 'void', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
- " };\n" +
- " }\n" +
- " };\n" +
- "};\n"
- );
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'A': { type: '', declaredBy: 'foo.bar.baz.A'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @interface\n" +
+ " */\n" +
+ "foo.bar.baz.A.ITestInterface = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A.ITestInterface', foo.bar.baz.A.ITestInterface);\n" +
+ "foo.bar.baz.A.ITestInterface.prototype.test = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.ITestInterface.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'ITestInterface', qName: 'foo.bar.baz.A.ITestInterface', kind: 'interface' }] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.ITestInterface.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " accessors: function () {return {};},\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'test': { type: 'void', declaredBy: 'foo.bar.baz.A.ITestInterface'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.ITestInterface.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @constructor\n" +
+ " * @implements {foo.bar.baz.A.ITestInterface}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.baz.A.InternalClass', foo.bar.baz.A.InternalClass);\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * @export\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.test = function() {\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Metadata\n" +
+ " *\n" +
+ " * @type {Object.<string, Array.<Object>>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'InternalClass', qName: 'foo.bar.baz.A.InternalClass', kind: 'class' }], interfaces: [foo.bar.baz.A.ITestInterface] };\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
+ " variables: function () {return {};},\n" +
+ " accessors: function () {return {};},\n" +
+ " methods: function () {\n" +
+ " return {\n" +
+ " 'InternalClass': { type: '', declaredBy: 'foo.bar.baz.A.InternalClass'},\n" +
+ " 'test': { type: 'void', declaredBy: 'foo.bar.baz.A.InternalClass'}\n" +
+ " };\n" +
+ " }\n" +
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.baz.A.InternalClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n"
+ );
}
@Test
public void testPackageQualified_ClassAndInternalStaticConst()
{
IFileNode node = compileAS("package foo.bar {\n" +
+ //adding an unneeded import node here exposed a failing test at one point:
+ "import foo.bar.*\n" +
"public function A():Number {\n" +
" return Internal.x;\n" +
"}}\n" +
@@ -1075,7 +1287,13 @@
" * @constructor\n" +
" */\n" +
"foo.bar.A.Internal = function() {\n" +
- "};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('foo.bar.A.Internal', foo.bar.A.Internal);\n" +
+ "};\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Prevent renaming of class. Needed for reflection.\n" +
+ " */\n" +
+ "goog.exportSymbol('foo.bar.A.Internal', foo.bar.A.Internal);\n" +
"\n" +
"\n" +
"/**\n" +
@@ -1092,21 +1310,35 @@
" * @type {Object.<string, Array.<Object>>}\n" +
" */\n" +
"foo.bar.A.Internal.prototype.ROYALE_CLASS_INFO = { names: [{ name: 'Internal', qName: 'foo.bar.A.Internal', kind: 'class' }] };\n" +
- "\n" +
- "\n" +
- "\n" +
- "/**\n" +
- " * Reflection\n" +
- " *\n" +
- " * @return {Object.<string, Function>}\n" +
- " */\n" +
- "foo.bar.A.Internal.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
- " return {\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "/**\n" +
+ " * Reflection\n" +
+ " *\n" +
+ " * @return {Object.<string, Function>}\n" +
+ " */\n" +
+ "foo.bar.A.Internal.prototype.ROYALE_REFLECTION_INFO = function () {\n" +
+ " return {\n" +
" variables: function () {return {};},\n" +
" accessors: function () {return {};},\n" +
" methods: function () {return {};}\n" +
- " };\n" +
- "};\n");
+ " };\n" +
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "foo.bar.A.Internal.prototype.ROYALE_REFLECTION_INFO.compileFlags = 15;\n" +
+ "/**\n" +
+ " * Provide reflection support for distinguishing dynamic fields on class object (static)\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {Array<string>}\n" +
+ " */\n" +
+ "foo.bar.A.Internal.prototype.ROYALE_REFLECTION_INFO.statics = Object.keys(foo.bar.A.Internal);\n"
+ );
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java
index c1c0137..d71b6d6 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java
@@ -21,11 +21,13 @@
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.internal.codegen.js.goog.TestGoogStatements;
+import org.apache.royale.compiler.internal.driver.js.goog.JSGoogConfiguration;
import org.apache.royale.compiler.internal.driver.js.royale.RoyaleBackend;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode;
import org.apache.royale.compiler.tree.as.IFileNode;
import org.apache.royale.compiler.tree.as.IForLoopNode;
+import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IIfNode;
import org.apache.royale.compiler.tree.as.IImportNode;
import org.apache.royale.compiler.tree.as.ILiteralNode;
@@ -47,6 +49,7 @@
{
backend = createBackend();
project = new RoyaleJSProject(workspace, backend);
+ project.config = new JSGoogConfiguration();
super.setUp();
}
@@ -90,10 +93,181 @@
@Test
public void testVarDeclaration_withType()
{
- IVariableNode node = (IVariableNode) getNode("var a:int;",
+ IFunctionNode node = (IFunctionNode) getNode("var a:int;",
+ IFunctionNode.class);
+ asBlockWalker.visitFunction(node);
+ assertOut("RoyaleTest_A.prototype.royaleTest_a = function() {\n var /** @type {number} */ a = 0;\n //var /** @type {number} */ a = 0;\n}");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeBooleanAndAssignedPositiveNumber()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Boolean = 123.4;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
- assertOut("var /** @type {number} */ a = 0");
+ assertOut("var /** @type {boolean} */ a = true");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeBooleanAndAssignedNegativeNumber()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Boolean = -123;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = true");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeBooleanAndAssignedZeroNumber()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Boolean = 0;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = false");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeBooleanAndAssignedDecimalNumber()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Boolean = 0.123;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = true");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeBooleanAndAssignedNull()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Boolean = null;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = false");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeBooleanAndAssignedUndefined()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Boolean = undefined;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {boolean} */ a = false");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeIntAndAssignedHex()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:int = 0xabc;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 0xabc");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeUintAndAssignedHex()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:uint = 0xabc;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 0xabc");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeNumberAndAssignedHex()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:Number = 0xabc;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 0xabc");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeIntAndAssignedNumber()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:int = 123.4;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 123");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeUintAndAssignedNumber()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:uint = 123.4;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 123");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeUintAndAssignedNegative()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:uint = -123;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = 4294967173");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeStringAndAssignedStringLiteral()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:String = \"hi\";",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = \"hi\"");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeStringAndAssignedNull()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:String = null;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = null");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeStringAndAssignedUndefined()
+ {
+ IVariableNode node = (IVariableNode) getNode("var a:String = undefined;",
+ IVariableNode.class);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = null");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeStringAndAssignedStringVar()
+ {
+ IVariableNode node = (IVariableNode) getNode("function royaleTest_a():Object { var a:String = b }var b:String;",
+ IVariableNode.class, WRAP_LEVEL_CLASS);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = this.b");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeStringAndAssignedAnyTypeVar()
+ {
+ IVariableNode node = (IVariableNode) getNode("function royaleTest_a():Object { var a:String = b }var b:*;",
+ IVariableNode.class, WRAP_LEVEL_CLASS);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = org.apache.royale.utils.Language.string(this.b)");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeStringAndAssignedToStringFunctionCall()
+ {
+ IVariableNode node = (IVariableNode) getNode("function royaleTest_a():Object { var a:String = b.toString(); }var b:Object;",
+ IVariableNode.class, WRAP_LEVEL_CLASS);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {string} */ a = this.b.toString()");
+ }
+
+ @Test
+ public void testVarDeclaration_withTypeNumberAndAssignedDateProperty()
+ {
+ IVariableNode node = (IVariableNode) getNode("function royaleTest_a():Object { var a:Number = b.fullYear; }var b:Date;",
+ IVariableNode.class, WRAP_LEVEL_CLASS);
+ asBlockWalker.visitVariable(node);
+ assertOut("var /** @type {number} */ a = this.b.getFullYear()");
}
//----------------------------------
@@ -546,11 +720,8 @@
"RoyaleTest_A = function() {\n" +
"};\n\n\n/**\n * Prevent renaming of class. Needed for reflection.\n */\ngoog.exportSymbol('RoyaleTest_A', RoyaleTest_A);\n\n\n" +
"RoyaleTest_A.prototype.royaleTest_a = function() {\n" +
- " var self = this;\n" +
- " var /** @type {Function} */ __localFn0__ = function(foo, bar) {\n" +
- " bar = typeof bar !== 'undefined' ? bar : 'goo';\n" +
- " return -1;\n" +
- " }\n" +
+ " var self = this;\n" +
+ " var /** @type {number} */ len = 0;\n" +
" try {\n" +
" a;\n" +
" } catch (e) {\n" +
@@ -567,7 +738,7 @@
" } finally {\n" +
" }\n" +
" if (d) {\n" +
- " var /** @type {number} */ len = 0;\n" +
+ " //var /** @type {number} */ len = 0;\n" +
" for (var /** @type {number} */ i = 0; i < len; i++)\n" +
" break;\n" +
" }\n" +
@@ -595,7 +766,10 @@
" }\n" +
" } finally {\n" +
" d;\n" +
- " var /** @type {Object} */ a = __localFn0__;\n" +
+ " var /** @type {Object} */ a = function(foo, bar) {\n" +
+ " bar = typeof bar !== 'undefined' ? bar : 'goo';\n" +
+ " return -1;\n" +
+ " };\n" +
" eee.dd;\n" +
" eee.dd;\n" +
" eee.dd;\n" +
@@ -628,7 +802,13 @@
" accessors: function () {return {};},\n" +
" methods: function () {return {};}\n" +
"};\n" +
- "};\n");
+ "};\n" +
+ "/**\n" +
+ " * @export\n" +
+ " * @const\n" +
+ " * @type {number}\n" +
+ " */\n" +
+ "RoyaleTest_A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;\n");
}
@Override
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapExpressions.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapExpressions.java
index 72beed5..98978db 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapExpressions.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapExpressions.java
@@ -199,6 +199,36 @@
assertMapping(node, 0, 4, 0, 4, 0, 5); // b
}
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentLiteral()
+ {
+ IBinaryOperatorNode node = getBinaryNode("a = 123.2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertMapping(node, 0, 0, 0, 0, 0, 1); // a
+ assertMapping(node, 0, 1, 0, 1, 0, 4); // =
+ assertMapping(node, 0, 4, 0, 4, 0, 9); // 123.2
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentLiteralWithCompileTimeIntCoercion()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var a:int;a = 123.2");
+ asBlockWalker.visitBinaryOperator(node);
+ assertMapping(node, 0, 0, 0, 0, 0, 1); // a
+ assertMapping(node, 0, 1, 0, 1, 0, 4); // =
+ assertMapping(node, 0, 4, 0, 4, 0, 7); // 123
+ }
+
+ @Test
+ public void testVisitBinaryOperatorNode_AssignmentLiteralWithCompileTimeUintCoercion()
+ {
+ IBinaryOperatorNode node = getBinaryNode("var a:uint;a = -123");
+ asBlockWalker.visitBinaryOperator(node);
+ assertMapping(node, 0, 0, 0, 0, 0, 1); // a
+ assertMapping(node, 0, 1, 0, 1, 0, 4); // =
+ assertMapping(node, 0, 4, 0, 4, 0, 14); // 4294967173
+ }
+
//----------------------------------
// Bitwise
//----------------------------------
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java
index cca0683..d13a577 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/sourcemaps/TestSourceMapStatements.java
@@ -65,13 +65,13 @@
@Test
public void testVarDeclaration_withType()
{
- IVariableNode node = (IVariableNode) getNode("var a:int;",
+ IVariableNode node = (IVariableNode) getNode("var a:Number;",
IVariableNode.class);
asBlockWalker.visitVariable(node);
//var /** @type {number} */ a
assertMapping(node, 0, 0, 0, 0, 0, 4); // var
assertMapping(node, 0, 4, 0, 26, 0, 27); // a
- assertMapping(node, 0, 5, 0, 4, 0, 26); // :int
+ assertMapping(node, 0, 5, 0, 4, 0, 26); // :Number
}
@Test
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/TestMXMLApplication.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/TestMXMLApplication.java
index 0aa5601..0e39169 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/TestMXMLApplication.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/TestMXMLApplication.java
@@ -18,6 +18,8 @@
*/
package org.apache.royale.compiler.internal.codegen.mxml;
+import static org.junit.Assert.assertNotNull;
+
import org.apache.royale.compiler.internal.test.MXMLTestBase;
import org.apache.royale.compiler.tree.mxml.IMXMLFileNode;
import org.junit.Test;
@@ -33,6 +35,7 @@
+ "</custom:TestInstance>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
@@ -48,6 +51,7 @@
+ "</custom:TestInstance>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
@@ -64,6 +68,7 @@
+ "</custom:TestInstance>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
@@ -80,6 +85,7 @@
+ " ]]></fx:Script>" + "</custom:TestInstance>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
@@ -99,6 +105,7 @@
+ " </fx:Declarations>" + "</custom:TestInstance>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java
index c5c3750..deec96c 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/mxml/royale/TestRoyaleMXMLApplication.java
@@ -19,6 +19,7 @@
package org.apache.royale.compiler.internal.codegen.mxml.royale;
import static org.hamcrest.core.Is.is;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import org.apache.royale.compiler.clients.MXMLJSC;
@@ -57,11 +58,11 @@
IMXMLFileNode node = compileMXML(fileName, true,
new File(testAdapter.getUnitTestBaseDir(), "royale/files").getPath(), false);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
JSCSSCompilationSession jscss = (JSCSSCompilationSession)project.getCSSCompilationSession();
- jscss.setExcludeDefaultsCSSFiles(new ArrayList<String>());
String result = getCodeFromFile("CSSTestSource_result.css", "royale/files");
String output = jscss.emitCSS();
@@ -80,6 +81,7 @@
IMXMLFileNode node = compileMXML(fileName, true,
new File(testAdapter.getUnitTestBaseDir(), "royale/files").getPath(), false);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
@@ -95,6 +97,7 @@
IMXMLFileNode node = compileMXML(fileName, true,
new File(testAdapter.getUnitTestBaseDir(), "royale/files").getPath(), false);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
@@ -110,6 +113,7 @@
IMXMLFileNode node = compileMXML(fileName, true,
new File(testAdapter.getUnitTestBaseDir(), "royale/files").getPath(), false);
+ assertNotNull(node);
mxmlBlockWalker.visitFile(node);
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/ASTestBase.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/ASTestBase.java
index fd484ba..807c950 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/ASTestBase.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/ASTestBase.java
@@ -58,6 +58,19 @@
}
@Override
+ protected void addDependencies()
+ {
+ if (libraries.size() == 0)
+ {
+ String jsSwcPath = FilenameNormalization.normalize("../compiler-externc/target/js.swc");
+ libraries.add(new File(jsSwcPath));
+ String customSwcPath = FilenameNormalization.normalize("../compiler-jx/target/custom.swc");
+ libraries.add(new File(customSwcPath));
+ }
+ super.addDependencies();
+ }
+
+ @Override
protected void addSourcePaths(List<File> sourcePaths)
{
//sourcePaths.add(new File(FilenameNormalization.normalize(
@@ -194,4 +207,10 @@
return (IVariableNode) getNode(code, IVariableNode.class);
}
+ protected IASNode getLocalFunction(String code)
+ {
+ IFunctionNode method = (IFunctionNode) getNode(code, IFunctionNode.class);
+ return (IFunctionNode) findFirstDescendantOfType(method, IFunctionNode.class);
+ }
+
}
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/MXMLTestBase.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/MXMLTestBase.java
index 5235ffc..7f8ba79 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/MXMLTestBase.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/MXMLTestBase.java
@@ -18,6 +18,8 @@
*/
package org.apache.royale.compiler.internal.test;
+import static org.junit.Assert.assertNotNull;
+
import java.io.File;
import java.util.List;
@@ -54,6 +56,19 @@
}
@Override
+ protected void addDependencies()
+ {
+ if (libraries.size() == 0)
+ {
+ String jsSwcPath = FilenameNormalization.normalize("../compiler-externc/target/js.swc");
+ libraries.add(new File(jsSwcPath));
+ String customSwcPath = FilenameNormalization.normalize("../compiler-jx/target/custom.swc");
+ libraries.add(new File(customSwcPath));
+ }
+ super.addDependencies();
+ }
+
+ @Override
protected void addLibraries(List<File> libraries)
{
//libraries.addAll(testAdapter.getLibraries(true));
@@ -103,6 +118,7 @@
+ "</custom:TestInstance>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
if (wrapLevel >= WRAP_LEVEL_NODE) // for now: attributes
{
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/RoyaleTestBase.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/RoyaleTestBase.java
index 67ef4fb..5f7a8bd 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/RoyaleTestBase.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/RoyaleTestBase.java
@@ -18,14 +18,14 @@
*/
package org.apache.royale.compiler.internal.test;
+import static org.junit.Assert.assertNotNull;
+
import java.io.File;
import java.util.List;
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.internal.driver.mxml.royale.MXMLRoyaleBackend;
-import org.apache.royale.compiler.internal.mxml.MXMLNamespaceMapping;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
-import org.apache.royale.compiler.mxml.IMXMLNamespaceMapping;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.mxml.IMXMLFileNode;
import org.apache.royale.compiler.tree.mxml.IMXMLNode;
@@ -100,6 +100,7 @@
+ code + "]]></fx:Script></basic:Application>";
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
return findFirstASDescendantOfType(node, type);
}
@@ -115,6 +116,7 @@
}
IMXMLFileNode node = compileMXML(code);
+ assertNotNull(node);
return findFirstDescendantOfType(node, type);
}
diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/TestBase.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/TestBase.java
index 944b06e..c436fd9 100644
--- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/TestBase.java
+++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/test/TestBase.java
@@ -20,7 +20,6 @@
package org.apache.royale.compiler.internal.test;
import static org.hamcrest.core.Is.is;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import java.io.BufferedOutputStream;
@@ -47,6 +46,7 @@
import org.apache.royale.compiler.config.Configurator;
import org.apache.royale.compiler.driver.IBackend;
import org.apache.royale.compiler.internal.codegen.as.ASFilterWriter;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.projects.RoyaleProjectConfigurator;
import org.apache.royale.compiler.internal.projects.ISourceFileHandler;
@@ -102,13 +102,15 @@
protected File tempDir;
- private List<File> sourcePaths = new ArrayList<File>();
- private List<File> libraries = new ArrayList<File>();
- private List<IMXMLNamespaceMapping> namespaceMappings = new ArrayList<IMXMLNamespaceMapping>();
+ protected List<File> sourcePaths = new ArrayList<File>();
+ protected List<File> libraries = new ArrayList<File>();
+ protected List<IMXMLNamespaceMapping> namespaceMappings = new ArrayList<IMXMLNamespaceMapping>();
@Before
public void setUp()
{
+ DefinitionBase.setPerformanceCachingEnabled(true);
+
errors = new ArrayList<ICompilerProblem>();
if (project == null)
@@ -149,6 +151,7 @@
@After
public void tearDown()
{
+ DefinitionBase.setPerformanceCachingEnabled(false);
backend = null;
writer = null;
}
@@ -692,7 +695,7 @@
String jsSwcPath = FilenameNormalization.normalize("../compiler-externc/target/js.swc");
libraries.add(new File(jsSwcPath));
String customSwcPath = FilenameNormalization.normalize("../compiler/target/custom.swc");
- libraries.add(new File(customSwcPath));
+ libraries.add(new File(customSwcPath));
}
addNamespaceMappings(namespaceMappings);
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/Test_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/Test_result.js
index 23bd2a6..63b5209 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/Test_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/Test_result.js
@@ -86,3 +86,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Test.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/A_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/A_result.js
index ec11c7e..00a8df0 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/A_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/A_result.js
@@ -86,3 +86,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/B_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/B_result.js
index d4a3f12..a0174ff 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/B_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/B_result.js
@@ -61,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.B.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/C_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/C_result.js
index 0b1398e..4799d88 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/C_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/classes/C_result.js
@@ -61,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.C.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IA_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IA_result.js
index 395e896..878ead5 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IA_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IA_result.js
@@ -68,3 +68,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IA.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IB_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IB_result.js
index e28bf2e..c70befd 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IB_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IB_result.js
@@ -56,3 +56,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IB.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IC_result.js b/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IC_result.js
index cf0628d..db98f47 100644
--- a/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IC_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/bad_overrides/interfaces/IC_result.js
@@ -56,3 +56,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IC.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular/Base_result.js b/compiler-jx/src/test/resources/royale/projects/circular/Base_result.js
index 1d27a23..ea802df 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular/Base_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular/Base_result.js
@@ -66,3 +66,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Base.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular/Super_result.js b/compiler-jx/src/test/resources/royale/projects/circular/Super_result.js
index 146ca29..60b608f 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular/Super_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular/Super_result.js
@@ -42,7 +42,7 @@
* @private
* @type {Base}
*/
-Super.isItCircular;
+Super.isItCircular = null;
/**
@@ -70,3 +70,16 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Super.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
+/**
+ * Provide reflection support for distinguishing dynamic fields on class object (static)
+ * @export
+ * @const
+ * @type {Array<string>}
+ */
+Super.prototype.ROYALE_REFLECTION_INFO.statics = Object.keys(Super);
\ No newline at end of file
diff --git a/compiler-jx/src/test/resources/royale/projects/circular_proto/A_result.js b/compiler-jx/src/test/resources/royale/projects/circular_proto/A_result.js
index b2481e4..007efbf 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular_proto/A_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular_proto/A_result.js
@@ -72,3 +72,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular_proto/B_result.js b/compiler-jx/src/test/resources/royale/projects/circular_proto/B_result.js
index efacd72..8bafb82 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular_proto/B_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular_proto/B_result.js
@@ -71,8 +71,14 @@
methods: function () {
return {
'B': { type: '', declaredBy: 'B'},
- '|a': { type: 'int', declaredBy: 'B', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
+ '|a': { type: 'int', declaredBy: 'B', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
};
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+B.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular_proto/C_result.js b/compiler-jx/src/test/resources/royale/projects/circular_proto/C_result.js
index e230054..30562a9 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular_proto/C_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular_proto/C_result.js
@@ -73,8 +73,14 @@
methods: function () {
return {
'C': { type: '', declaredBy: 'C'},
- '|a': { type: 'int', declaredBy: 'C', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
+ '|a': { type: 'int', declaredBy: 'C', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
};
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+C.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular_proto/D_result.js b/compiler-jx/src/test/resources/royale/projects/circular_proto/D_result.js
index d3171dc..48d84c0 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular_proto/D_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular_proto/D_result.js
@@ -73,8 +73,14 @@
methods: function () {
return {
'D': { type: '', declaredBy: 'D'},
- '|a': { type: 'int', declaredBy: 'D', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
+ '|a': { type: 'int', declaredBy: 'D', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
};
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+D.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular_proto/E_result.js b/compiler-jx/src/test/resources/royale/projects/circular_proto/E_result.js
index 9eb682c..04e154d 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular_proto/E_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular_proto/E_result.js
@@ -69,8 +69,14 @@
methods: function () {
return {
'E': { type: '', declaredBy: 'E'},
- '|a': { type: 'int', declaredBy: 'E', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
+ '|a': { type: 'int', declaredBy: 'E', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
};
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+E.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/circular_proto/F_result.js b/compiler-jx/src/test/resources/royale/projects/circular_proto/F_result.js
index c641222..bb5bf9d 100644
--- a/compiler-jx/src/test/resources/royale/projects/circular_proto/F_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/circular_proto/F_result.js
@@ -73,8 +73,14 @@
methods: function () {
return {
'F': { type: '', declaredBy: 'F'},
- '|a': { type: 'int', declaredBy: 'F', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
+ '|a': { type: 'int', declaredBy: 'F', parameters: function () { return [ { index: 1, type: 'Boolean', optional: false } ]; }}
};
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+F.prototype.ROYALE_REFLECTION_INFO.compileFlags = 8;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/Test_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/Test_result.js
index ffdd7be..41f6619 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/Test_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/Test_result.js
@@ -82,8 +82,14 @@
methods: function () {
return {
'Test': { type: '', declaredBy: 'Test'},
- 'doSomething': { type: 'interfaces.IC', declaredBy: 'Test', parameters: function () { return [ { index: 1, type: 'interfaces.IC', optional: false } ]; }}
+ 'doSomething': { type: 'interfaces.IC', declaredBy: 'Test', parameters: function () { return [ { index: 1, type: 'interfaces.IC', optional: false } ]; }}
};
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Test.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/classes/A_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/classes/A_result.js
index 5020237..38adfe9 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/classes/A_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/classes/A_result.js
@@ -66,3 +66,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/classes/B_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/classes/B_result.js
index d4a3f12..362c2ac 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/classes/B_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/classes/B_result.js
@@ -61,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.B.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/classes/C_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/classes/C_result.js
index 0b1398e..3a586f8 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/classes/C_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/classes/C_result.js
@@ -61,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.C.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IA_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IA_result.js
index 6b1a475..92fc242 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IA_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IA_result.js
@@ -59,3 +59,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IA.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IC_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IC_result.js
index 465c89c..0aaf33e 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IC_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IC_result.js
@@ -59,3 +59,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IC.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/ID_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/ID_result.js
index b86a0af..31223a4 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/ID_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/ID_result.js
@@ -56,3 +56,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.ID.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IE_result.js b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IE_result.js
index 239c8bd..d4f2f8f 100644
--- a/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IE_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/interfaces/interfaces/IE_result.js
@@ -68,3 +68,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IE.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/internal/MainClass_result.js b/compiler-jx/src/test/resources/royale/projects/internal/MainClass_result.js
index 826e5f1..d403d5f 100644
--- a/compiler-jx/src/test/resources/royale/projects/internal/MainClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/internal/MainClass_result.js
@@ -64,6 +64,12 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+MainClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
@@ -85,7 +91,7 @@
* @export
* @type {OtherClass}
*/
-MainClass.InternalClass.prototype.foo;
+MainClass.InternalClass.prototype.foo = null;
/**
@@ -106,7 +112,7 @@
return {
variables: function () {
return {
- 'foo': { type: 'OtherClass'}
+ 'foo': { type: 'OtherClass', get_set: function (/** MainClass.InternalClass */ inst, /** * */ v) {return v !== undefined ? inst.foo = v : inst.foo;}}
};
},
accessors: function () {return {};},
@@ -117,3 +123,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+MainClass.InternalClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
\ No newline at end of file
diff --git a/compiler-jx/src/test/resources/royale/projects/internal/OtherClass_result.js b/compiler-jx/src/test/resources/royale/projects/internal/OtherClass_result.js
index 9506443..ad59e37 100644
--- a/compiler-jx/src/test/resources/royale/projects/internal/OtherClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/internal/OtherClass_result.js
@@ -61,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+OtherClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/Test_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/Test_result.js
index 5a0e4db..3d227df 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/Test_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/Test_result.js
@@ -88,3 +88,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Test.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/classes/A_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/classes/A_result.js
index 65ede50..577dab8 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/classes/A_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/classes/A_result.js
@@ -86,3 +86,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.A.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/classes/B_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/classes/B_result.js
index d4a3f12..362c2ac 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/classes/B_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/classes/B_result.js
@@ -61,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.B.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/classes/C_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/classes/C_result.js
index 0506eac..a8fa919 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/classes/C_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/classes/C_result.js
@@ -66,3 +66,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+classes.C.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IA_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IA_result.js
index 0a73f33..1a5b8ce 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IA_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IA_result.js
@@ -38,11 +38,13 @@
*/
goog.exportSymbol('interfaces.IA', interfaces.IA);
/**
+ * @export
* @return {classes.B}
*/
interfaces.IA.prototype.someFunction = function() {
};
/**
+ * @export
* @return {interfaces.IB}
*/
interfaces.IA.prototype.someOtherFunction = function() {
@@ -74,3 +76,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IA.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IB_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IB_result.js
index e28bf2e..cfd1886 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IB_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IB_result.js
@@ -56,3 +56,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IB.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IC_result.js b/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IC_result.js
index 9f0b203..cc176a9 100644
--- a/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IC_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/overrides/interfaces/IC_result.js
@@ -59,3 +59,9 @@
methods: function () {return {};}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+interfaces.IC.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_ambiguous_definition/AmbiguousDefinition_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_ambiguous_definition/AmbiguousDefinition_result.js
index b176467..59ea4a8 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_ambiguous_definition/AmbiguousDefinition_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_ambiguous_definition/AmbiguousDefinition_result.js
@@ -38,7 +38,7 @@
* @export
* @type {mypackage.TestClass}
*/
-AmbiguousDefinition.prototype.testClass;
+AmbiguousDefinition.prototype.testClass = null;
/**
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/DifferentPackageAsConflict_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/DifferentPackageAsConflict_result.js
index 920736a..e937e30 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/DifferentPackageAsConflict_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/DifferentPackageAsConflict_result.js
@@ -43,7 +43,7 @@
* @private
* @type {mypackage.TestClass}
*/
-DifferentPackageAsConflict.prototype.testClass;
+DifferentPackageAsConflict.prototype.testClass = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+DifferentPackageAsConflict.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/Event_result.js
index 7ab655d..e66b810 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/mypackage/TestClass_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/mypackage/TestClass_result.js
index 6b487b5..edc4b35 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/mypackage/TestClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/mypackage/TestClass_result.js
@@ -45,7 +45,7 @@
* @private
* @type {otherpackage.Event}
*/
-mypackage.TestClass.prototype.event;
+mypackage.TestClass.prototype.event = null;
/**
@@ -73,3 +73,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+mypackage.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/otherpackage/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/otherpackage/Event_result.js
index 9064c05..17edd42 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/otherpackage/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_different_package_as_conflict/otherpackage/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+otherpackage.Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/Event_result.js
index 7ab655d..2ff7e8d 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/Event_result.js
@@ -12,7 +12,6 @@
* limitations under the License.
*/
/**
- * Generated by Apache Royale Compiler from Event.as
* Event
*
* @fileoverview
@@ -62,3 +61,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/NoConflictNoWindow_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/NoConflictNoWindow_result.js
index efbdb42..fbac53a 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/NoConflictNoWindow_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/NoConflictNoWindow_result.js
@@ -43,7 +43,7 @@
* @private
* @type {mypackage.TestClass}
*/
-NoConflictNoWindow.prototype.testClass;
+NoConflictNoWindow.prototype.testClass = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+NoConflictNoWindow.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/mypackage/TestClass_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/mypackage/TestClass_result.js
index c644d1f..73ec794 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/mypackage/TestClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_no_window/mypackage/TestClass_result.js
@@ -43,7 +43,7 @@
* @private
* @type {Event}
*/
-mypackage.TestClass.prototype.event;
+mypackage.TestClass.prototype.event = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+mypackage.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/Event_result.js
index 7ab655d..e66b810 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/NoConflictUseWindow_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/NoConflictUseWindow_result.js
index 9410ca3..f4e8888 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/NoConflictUseWindow_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/NoConflictUseWindow_result.js
@@ -43,7 +43,7 @@
* @private
* @type {mypackage.TestClass}
*/
-NoConflictUseWindow.prototype.testClass;
+NoConflictUseWindow.prototype.testClass = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+NoConflictUseWindow.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/mypackage/TestClass_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/mypackage/TestClass_result.js
index c644d1f..73ec794 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/mypackage/TestClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_no_conflict_use_window/mypackage/TestClass_result.js
@@ -43,7 +43,7 @@
* @private
* @type {Event}
*/
-mypackage.TestClass.prototype.event;
+mypackage.TestClass.prototype.event = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+mypackage.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/Event_result.js
index 7ab655d..e66b810 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/SamePackageAsConflict_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/SamePackageAsConflict_result.js
index ebf818c..cab6477 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/SamePackageAsConflict_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/SamePackageAsConflict_result.js
@@ -43,7 +43,7 @@
* @private
* @type {mypackage.TestClass}
*/
-SamePackageAsConflict.prototype.testClass;
+SamePackageAsConflict.prototype.testClass = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+SamePackageAsConflict.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/Event_result.js
index 6bf3477..03790e1 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+mypackage.Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/TestClass_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/TestClass_result.js
index a0a5b4e..1dcdb08 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/TestClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_same_package_as_conflict/mypackage/TestClass_result.js
@@ -45,7 +45,7 @@
* @private
* @type {mypackage.Event}
*/
-mypackage.TestClass.prototype.event;
+mypackage.TestClass.prototype.event = null;
/**
@@ -73,3 +73,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+mypackage.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/Event_result.js
index 7ab655d..e66b810 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/UseWindow_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/UseWindow_result.js
index 2efb878..bf41e5d 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/UseWindow_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/UseWindow_result.js
@@ -43,7 +43,7 @@
* @private
* @type {mypackage.TestClass}
*/
-UseWindow.prototype.testClass;
+UseWindow.prototype.testClass = null;
/**
@@ -71,3 +71,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+UseWindow.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/mypackage/TestClass_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/mypackage/TestClass_result.js
index 812e1b0..b58f94c 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/mypackage/TestClass_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/mypackage/TestClass_result.js
@@ -46,14 +46,14 @@
* @private
* @type {Event}
*/
-mypackage.TestClass.prototype.event1;
+mypackage.TestClass.prototype.event1 = null;
/**
* @private
* @type {otherpackage.Event}
*/
-mypackage.TestClass.prototype.event2;
+mypackage.TestClass.prototype.event2 = null;
/**
@@ -81,3 +81,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+mypackage.TestClass.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/otherpackage/Event_result.js b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/otherpackage/Event_result.js
index 9064c05..17edd42 100644
--- a/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/otherpackage/Event_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/package_conflicts_use_window/otherpackage/Event_result.js
@@ -62,3 +62,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+otherpackage.Event.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/super/Base_result.js b/compiler-jx/src/test/resources/royale/projects/super/Base_result.js
index 6e626be..1c99d83 100644
--- a/compiler-jx/src/test/resources/royale/projects/super/Base_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/super/Base_result.js
@@ -92,3 +92,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Base.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/super/Super_result.js b/compiler-jx/src/test/resources/royale/projects/super/Super_result.js
index 4612c43..17ad26f 100644
--- a/compiler-jx/src/test/resources/royale/projects/super/Super_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/super/Super_result.js
@@ -94,3 +94,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+Super.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-jx/src/test/resources/royale/projects/xml_requires/XMLRequire_result.js b/compiler-jx/src/test/resources/royale/projects/xml_requires/XMLRequire_result.js
index 914a071..9b088fd 100644
--- a/compiler-jx/src/test/resources/royale/projects/xml_requires/XMLRequire_result.js
+++ b/compiler-jx/src/test/resources/royale/projects/xml_requires/XMLRequire_result.js
@@ -64,3 +64,9 @@
}
};
};
+/**
+ * @export
+ * @const
+ * @type {number}
+ */
+XMLRequire.prototype.ROYALE_REFLECTION_INFO.compileFlags = 9;
diff --git a/compiler-test-utils/pom.xml b/compiler-test-utils/pom.xml
index 0305699..8384eed 100644
--- a/compiler-test-utils/pom.xml
+++ b/compiler-test-utils/pom.xml
@@ -1,55 +1,65 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>compiler-test-utils</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: Test Utils</name>
- <description>
- Shared test code, which is needed by the compiler and the compiler-jx test-suites.
- </description>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-compress</artifactId>
- <version>1.10</version>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>compiler-test-utils</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: Test Utils</name>
+ <description>
+ Shared test code, which is needed by the compiler and the compiler-jx test-suites.
+ </description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-compress</artifactId>
+ <version>1.10</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/compiler/build.xml b/compiler/build.xml
index 5fb9577..bca3b89 100644
--- a/compiler/build.xml
+++ b/compiler/build.xml
@@ -184,6 +184,8 @@
<macrodef name="annotate.class">
<attribute name="file"/>
<attribute name="annotation"/>
+ <attribute name="datestart"/>
+ <attribute name="dateend"/>
<sequential>
<java classname="org.apache.royale.compiler.tools.annotate.AnnotateClass" fork="false">
<classpath>
@@ -193,6 +195,8 @@
</classpath>
<arg value="@{file}"/>
<arg value="@{annotation}"/>
+ <arg value="@{datestart}"/>
+ <arg value="@{dateend}"/>
</java>
</sequential>
</macrodef>
@@ -289,9 +293,9 @@
<antlr2 input="${compiler}/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g"
output="${compiler}/target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as"/>
<annotate.class file="${compiler}/target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.java"
- annotation='@SuppressWarnings("unused")'/>
+ annotation='@SuppressWarnings("unused")' datestart="" dateend=""/>
<annotate.class file="${compiler}/target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as/ASTokenTypes.java"
- annotation='@SuppressWarnings("unused")'/>
+ annotation='@SuppressWarnings("unused")' datestart="" dateend=""/>
</target>
<target name="set.metadata.parser.uptodate">
@@ -309,9 +313,9 @@
<antlr2 input="${compiler}/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/MetadataParser.g"
output="${compiler}/target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as"/>
<annotate.class file="${compiler}/target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as/MetadataParser.java"
- annotation='@SuppressWarnings("all")'/>
+ annotation='@SuppressWarnings("all")' datestart="" dateend=""/>
<annotate.class file="${compiler}/target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as/MetadataTokenTypes.java"
- annotation='@SuppressWarnings("unused")'/>
+ annotation='@SuppressWarnings("unused")' datestart="" dateend=""/>
</target>
<target name="set.css.lexer.and.parser.uptodate">
@@ -324,10 +328,10 @@
<echo message="Generating CSSLexer and CSSParser"/>
<antlr3 input="${compiler}/src/main/antlr3/org/apache/royale/compiler/internal/css/CSS.g"
output="${compiler}/target/generated-sources/antlr3/org/apache/royale/compiler/internal/css"/>
- <!--<annotate.class file="${compiler}/generated/src/org/apache/royale/compiler/internal/css/CSSLexer.java"
- annotation='@SuppressWarnings("unused")'/>-->
- <!--<annotate.class file="${compiler}/generated/src/org/apache/royale/compiler/internal/css/CSSParser.java"
- annotation='@SuppressWarnings("unused")'/>-->
+ <annotate.class file="${compiler}/target/generated-sources/antlr3/org/apache/royale/compiler/internal/css/CSSLexer.java"
+ annotation='@SuppressWarnings("all")' datestart="// $ANTLR 3.5.2 ***CSS.g" dateend=""/>
+ <annotate.class file="${compiler}/target/generated-sources/antlr3/org/apache/royale/compiler/internal/css/CSSParser.java"
+ annotation='@SuppressWarnings("all")' datestart="// $ANTLR 3.5.2 ***CSS.g" dateend=""/>
</target>
<target name="set.css.tree.uptodate">
@@ -340,8 +344,9 @@
<echo message="Generating CSSTree"/>
<antlr3 input="${compiler}/src/main/antlr3/org/apache/royale/compiler/internal/css/CSSTree.g"
output="${compiler}/target/generated-sources/antlr3/org/apache/royale/compiler/internal/css"/>
- <!--<annotate.class file="${compiler}/generated/src/org/apache/royale/compiler/internal/css/CSSTree.java"
- annotation='@SuppressWarnings({"rawtypes", "unchecked", "unused"})'/>-->
+ <annotate.class file="${compiler}/target/generated-sources/antlr3/org/apache/royale/compiler/internal/css/CSSTree.java"
+ annotation='@SuppressWarnings("all")'
+ datestart="// $ANTLR 3.5.2 ***CSSTree.g" dateend=""/>
</target>
<target name="antlr" depends="as.parser, metadata.parser, css.lexer.and.parser, css.tree"
@@ -385,7 +390,7 @@
<jburg input="${compiler}/src/main/jburg/org/apache/royale/compiler/internal/as/codegen/cmc.jbg"
output="${compiler}/target/generated-sources/jburg/org/apache/royale/compiler/internal/as/codegen/CmcEmitter.java"/>
<annotate.class file="${compiler}/target/generated-sources/jburg/org/apache/royale/compiler/internal/as/codegen/CmcEmitter.java"
- annotation='@SuppressWarnings({"rawtypes", "unchecked", "unused"})'/>
+ annotation='@SuppressWarnings({"rawtypes", "unchecked", "unused", "incomplete-switch"})' datestart="/* Generated" dateend=" by JBurg"/>
</target>
<target name="set.css.emitter.uptodate">
@@ -404,7 +409,7 @@
<jburg input="${compiler}/src/main/jburg/org/apache/royale/compiler/internal/css/codegen/css.jbg"
output="${compiler}/target/generated-sources/jburg/org/apache/royale/compiler/internal/css/codegen/CSSEmitter.java"/>
<annotate.class file="${compiler}/target/generated-sources/jburg/org/apache/royale/compiler/internal/css/codegen/CSSEmitter.java"
- annotation='@SuppressWarnings({"rawtypes", "unchecked", "unused"})'/>
+ annotation='@SuppressWarnings({"rawtypes", "unchecked", "unused", "incomplete-switch"})' datestart="/* Generated" dateend=" by JBurg"/>
</target>
<target name="jburg" depends="cmc.emitter, css.emitter"
diff --git a/compiler/pom.xml b/compiler/pom.xml
index 6182cd6..db0c924 100644
--- a/compiler/pom.xml
+++ b/compiler/pom.xml
@@ -1,581 +1,616 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>compiler</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: Compiler</name>
- <description>The Apache Royale Compiler</description>
-
- <build>
- <plugins>
- <plugin>
- <artifactId>maven-resources-plugin</artifactId>
- <version>3.1.0</version>
- <executions>
- <execution>
- <id>copy-externc-resources</id>
- <phase>process-test-resources</phase>
- <goals>
- <goal>copy-resources</goal>
- </goals>
- <configuration>
- <outputDirectory>${basedir}/../compiler-externc/target</outputDirectory>
- <resources>
- <resource>
- <directory>${basedir}/../compiler-externc/src/test/config</directory>
- </resource>
- </resources>
- </configuration>
- </execution>
- <execution>
- <id>copy-custom-resources</id>
- <phase>process-test-resources</phase>
- <goals>
- <goal>copy-resources</goal>
- </goals>
- <configuration>
- <outputDirectory>${basedir}/target</outputDirectory>
- <resources>
- <resource>
- <directory>${basedir}/src/test/config</directory>
- </resource>
- </resources>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <!--
- Do all the JFlex code generation
- -->
- <plugin>
- <groupId>de.jflex</groupId>
- <artifactId>maven-jflex-plugin</artifactId>
- <version>1.4.3</version>
- <executions>
- <execution>
- <id>generate-raw-as-tokenizer</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <outputDirectory>target/generated-sources/jflex</outputDirectory>
- <lexDefinitions>
- <lexDefinition>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/RawASTokenizer.lex</lexDefinition>
- </lexDefinitions>
- <skeleton>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/skeleton.royale</skeleton>
- </configuration>
- </execution>
- <execution>
- <id>generate-raw-as-doc-tokenizer</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <outputDirectory>target/generated-sources/jflex</outputDirectory>
- <lexDefinitions>
- <lexDefinition>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/RawASDocTokenizer.lex</lexDefinition>
- </lexDefinitions>
- <skeleton>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/skeleton.default</skeleton>
- </configuration>
- </execution>
- <execution>
- <id>generate-raw-mxml-tokenizer</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <outputDirectory>target/generated-sources/jflex</outputDirectory>
- <lexDefinitions>
- <lexDefinition>src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex</lexDefinition>
- </lexDefinitions>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <!--
- Do all the Antlr2 code generation
- -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antlr-plugin</artifactId>
- <version>2.0-beta-1</version>
- <executions>
- <execution>
- <id>generate-as-parser</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <grammars>org/apache/royale/compiler/internal/parsing/as/ASParser.g</grammars>
- </configuration>
- </execution>
- </executions>
- <dependencies>
- <dependency>
- <groupId>antlr</groupId>
- <artifactId>antlr</artifactId>
- <version>2.7.7</version>
- </dependency>
- </dependencies>
- </plugin>
-
- <!--
- The generation of the metadata-parser requires Antlr to
- load ImportMetadataTokenTypes.txt. Unfortunately Altlr
- looks in the current working directory. The only way to
- force it to work, is to start a new process with the
- working directory in the directory containing the file.
- -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>exec-maven-plugin</artifactId>
- <version>1.5.0</version>
- <executions>
- <execution>
- <id>generate-metadata-parser</id>
- <phase>generate-sources</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- <configuration>
- <executable>java</executable>
- <arguments>
- <argument>-classpath</argument>
- <classpath />
- <arguments>antlr.Tool</arguments>
- <argument>-o</argument>
- <argument>../../../../../../../../../../target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as</argument>
- <argument>MetadataParser.g</argument>
- </arguments>
- <workingDirectory>src/main/antlr/org/apache/royale/compiler/internal/parsing/as</workingDirectory>
- <sourceRoot>target/generated-sources/antlr</sourceRoot>
- </configuration>
- </execution>
- <execution>
- <id>generate-test-js-typedefs</id>
- <phase>test-compile</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- <configuration>
- <executable>java</executable>
- <arguments>
- <argument>-classpath</argument>
- <classpath />
- <arguments>org.apache.royale.compiler.clients.EXTERNC</arguments>
- <argument>-load-config+=../compiler-externc/src/test/config/externc-config.xml</argument>
- </arguments>
- </configuration>
- </execution>
- <execution>
- <id>generate-test-js-swc</id>
- <phase>test-compile</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- <configuration>
- <executable>java</executable>
- <arguments>
- <argument>-classpath</argument>
- <classpath />
- <arguments>org.apache.royale.compiler.clients.COMPC</arguments>
- <argument>-load-config+=../compiler-externc/target/compile-as-config.xml</argument>
- <argument>-output=../compiler-externc/target/js.swc</argument>
- </arguments>
- </configuration>
- </execution>
- <execution>
- <id>generate-test-custom-swc</id>
- <phase>test-compile</phase>
- <goals>
- <goal>exec</goal>
- </goals>
- <configuration>
- <executable>java</executable>
- <arguments>
- <argument>-classpath</argument>
- <classpath />
- <arguments>org.apache.royale.compiler.clients.COMPC</arguments>
- <argument>-load-config+=target/compile-as-config.xml</argument>
- <argument>-output=target/custom.swc</argument>
- </arguments>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <!--
- Do all the JBurg code generation.
- -->
- <plugin>
- <groupId>net.sourceforge.jburg</groupId>
- <artifactId>jburg-maven-plugin</artifactId>
- <version>1.10.4</version>
- <extensions>true</extensions>
- <executions>
- <execution>
- <id>generate-css-emitter</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <includes>
- <include>CSSEmitter.jbg</include>
- </includes>
- <sourceDirectory>src/main/jburg/org/apache/royale/compiler/internal/css/codegen</sourceDirectory>
- <outputDirectory>target/generated-sources/jburg/org/apache/royale/compiler/internal/css/codegen</outputDirectory>
- </configuration>
- </execution>
- <execution>
- <id>generate-cmc-emitter</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <includes>
- <include>CmcEmitter.jbg</include>
- </includes>
- <sourceDirectory>src/main/jburg/org/apache/royale/compiler/internal/as/codegen</sourceDirectory>
- <outputDirectory>target/generated-sources/jburg/org/apache/royale/compiler/internal/as/codegen</outputDirectory>
- </configuration>
- </execution>
- </executions>
- <configuration>
- <!-- debug=true generates the "dump" method for Emitters, which is used for debugging -->
- <debug>true</debug>
- </configuration>
- <dependencies>
- <dependency>
- <groupId>net.sourceforge.jburg</groupId>
- <artifactId>jburg</artifactId>
- <version>1.10.3</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-jburg-types</artifactId>
- <version>${compiler-jburg-types.version}</version>
- </dependency>
- </dependencies>
- </plugin>
-
- <!--
- Do all the Antlr3 code generation.
- -->
- <plugin>
- <groupId>org.antlr</groupId>
- <artifactId>antlr3-maven-plugin</artifactId>
- <version>3.5.2</version>
- <executions>
- <execution>
- <id>generate-csslexer-and-cssparser</id>
- <goals>
- <goal>antlr</goal>
- </goals>
- <configuration>
- <includes>
- <include>CSS.g</include>
- </includes>
- <sourceDirectory>src/main/antlr3/org/apache/royale/compiler/internal/css</sourceDirectory>
- <outputDirectory>target/generated-sources/antlr3/org/apache/royale/compiler/internal/css</outputDirectory>
- </configuration>
- </execution>
- <execution>
- <id>generate-csstree</id>
- <goals>
- <goal>antlr</goal>
- </goals>
- <configuration>
- <includes>
- <include>CSSTree.g</include>
- </includes>
- <sourceDirectory>src/main/antlr3/org/apache/royale/compiler/internal/css</sourceDirectory>
- <outputDirectory>target/generated-sources/antlr3/org/apache/royale/compiler/internal/css</outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <!--
- Do all the custom processing with the royale build tools.
- -->
- <plugin>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-build-tools</artifactId>
- <version>${compiler-build-tools.version}</version>
- <executions>
- <execution>
- <id>generate-unknown-tree-handler</id>
- <goals>
- <goal>generate-unknown-tree-handler</goal>
- </goals>
- <configuration>
- <inputFile>org/apache/royale/compiler/internal/as/codegen/UnknownTreeHandlerPatterns.xml</inputFile>
- <outputFile>org/apache/royale/compiler/internal/as/codegen/UnknownTreeHandlerPatterns.java</outputFile>
- </configuration>
- </execution>
- <execution>
- <id>add-suppress-unused-warnings-annotations</id>
- <goals>
- <goal>add-class-annotation</goal>
- </goals>
- <configuration>
- <includes>
- <include>antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.java</include>
- <include>antlr/org/apache/royale/compiler/internal/parsing/as/ASTokenTypes.java</include>
- <include>antlr/org/apache/royale/compiler/internal/parsing/as/MetadataTokenTypes.java</include>
- </includes>
- <annotation>@SuppressWarnings("unused")</annotation>
- </configuration>
- </execution>
- <execution>
- <id>add-suppress-all-warnings-annotations-jburg</id>
- <goals>
- <goal>add-class-annotation</goal>
- </goals>
- <configuration>
- <includes>
- <include>antlr/org/apache/royale/compiler/internal/parsing/as/MetadataParser.java</include>
- </includes>
- <annotation>@SuppressWarnings("all")</annotation>
- </configuration>
- </execution>
- <execution>
- <id>add-suppress-rawtypes-unchecked-unused-warnings-annotations</id>
- <goals>
- <goal>add-class-annotation</goal>
- </goals>
- <configuration>
- <includes>
- <include>jburg/org/apache/royale/compiler/internal/css/codegen/CSSEmitter.java</include>
- <include>jburg/org/apache/royale/compiler/internal/as/codegen/CmcEmitter.java</include>
- </includes>
- <annotation>@SuppressWarnings({"rawtypes", "unchecked", "unused"})</annotation>
- </configuration>
- </execution>
- <execution>
- <id>generate-problems-enum</id>
- <goals>
- <goal>generate-problems-enum</goal>
- </goals>
- </execution>
- <execution>
- <id>generate-problems-resource-bundle</id>
- <goals>
- <goal>generate-problems-resource-bundle</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <!-- Make the surefire execute all unit-tests -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>2.19</version>
- <configuration>
- <includes>
- <include>**/*Tests.java</include>
- </includes>
- <excludes>
- <exclude>as/**/*Tests.java</exclude>
- <exclude>f/**</exclude>
- <exclude>mxml/tags/**</exclude>
- <exclude>properties/**</exclude>
- <exclude>**/MXMLComponentTagTests.java</exclude>
- <exclude>**/MXMLComponentNodeTests.java</exclude>
- <exclude>**/MXMLHTTPServiceTagTests.java</exclude>
- <exclude>**/MXMLModelTagTests.java</exclude>
- <exclude>**/MXMLRemoteObjectNodeTests.java</exclude>
- <exclude>**/MXMLWebServiceNodeTests.java</exclude>
- <exclude>**/MXMLDesignLayerNodeTests.java</exclude>
- <exclude>**/MXMLHTTPServiceNodeTests.java</exclude>
- <exclude>**/MXMLModelNodeTests.java</exclude>
- <exclude>**/MXMLRemoteObjectTagTests.java</exclude>
- <exclude>**/MXMLStateNodeTests.java</exclude>
- <exclude>**/MXMLVectorNodeTests.java</exclude>
- <exclude>**/MXMLWebServiceTagTests.java</exclude>
- </excludes>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-failsafe-plugin</artifactId>
- <version>2.18.1</version>
- <configuration>
- <includes>
- <include>as/**/*Tests.java</include>
- </includes>
- <excludes>
- <exclude>f/**</exclude>
- <exclude>mxml/tags/**</exclude>
- <exclude>properties/**</exclude>
- <exclude>**/MXMLComponentTagTests.java</exclude>
- <exclude>**/MXMLComponentNodeTests.java</exclude>
- <exclude>**/MXMLHTTPServiceTagTests.java</exclude>
- <exclude>**/MXMLModelTagTests.java</exclude>
- <exclude>**/MXMLRemoteObjectNodeTests.java</exclude>
- <exclude>**/MXMLWebServiceNodeTests.java</exclude>
- <exclude>**/MXMLDesignLayerNodeTests.java</exclude>
- <exclude>**/MXMLHTTPServiceNodeTests.java</exclude>
- <exclude>**/MXMLModelNodeTests.java</exclude>
- <exclude>**/MXMLRemoteObjectTagTests.java</exclude>
- <exclude>**/MXMLStateNodeTests.java</exclude>
- <exclude>**/MXMLVectorNodeTests.java</exclude>
- <exclude>**/MXMLWebServiceTagTests.java</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <profiles>
- <!--
- This profile adds one test, that relies on the original FDK being
- available as it compiles each project in the framework/projects
- directory. It requires some environment variables being set.
- -->
- <profile>
- <id>include-sdk-compile-tests</id>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-failsafe-plugin</artifactId>
- <configuration>
- <includes combine.children="append">
- <include>f/**/*Tests.java</include>
- <include>mxml/**/*Tests.java</include>
- <include>properties/**/*Tests.java</include>
- <include>**/MXMLComponentTagTests.java</include>
- <include>**/MXMLComponentNodeTests.java</include>
- <include>**/MXMLHTTPServiceTagTests.java</include>
- <include>**/MXMLModelTagTests.java</include>
- <include>**/MXMLRemoteObjectNodeTests.java</include>
- <include>**/MXMLWebServiceNodeTests.java</include>
- <include>**/MXMLDesignLayerNodeTests.java</include>
- <include>**/MXMLHTTPServiceNodeTests.java</include>
- <include>**/MXMLModelNodeTests.java</include>
- <include>**/MXMLRemoteObjectTagTests.java</include>
- <include>**/MXMLStateNodeTests.java</include>
- <include>**/MXMLVectorNodeTests.java</include>
- <include>**/MXMLWebServiceTagTests.java</include>
- </includes>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </profile>
- </profiles>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-jburg-types</artifactId>
- <version>${compiler-jburg-types.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-common</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.flex</groupId>
- <artifactId>flex-tool-api</artifactId>
- <version>1.0.0</version>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
- <dependency>
- <groupId>commons-cli</groupId>
- <artifactId>commons-cli</artifactId>
- <version>1.2</version>
- </dependency>
- <dependency>
- <groupId>org.antlr</groupId>
- <artifactId>antlr</artifactId>
- <version>3.3</version>
- </dependency>
- <dependency>
- <groupId>com.google.guava</groupId>
- <artifactId>guava</artifactId>
- <version>20.0</version>
- </dependency>
- <dependency>
- <groupId>net.sourceforge.jburg</groupId>
- <artifactId>jburg</artifactId>
- <version>1.10.3</version>
- </dependency>
- <dependency>
- <groupId>de.jflex</groupId>
- <artifactId>jflex</artifactId>
- <version>1.6.0</version>
- <exclusions>
- <exclusion>
- <groupId>org.apache.ant</groupId>
- <artifactId>ant</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.b1.pack</groupId>
- <artifactId>lzma-sdk-4j</artifactId>
- <version>9.22.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-test-utils</artifactId>
- <version>0.9.4</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-externc</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- <!-- TODO: Currently only needed for the duplicate FlashplayerSecurityHandler -->
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.4</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>compiler</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: Compiler</name>
+ <description>The Apache Royale Compiler</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ <executions>
+ <execution>
+ <id>copy-externc-resources</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/../compiler-externc/target</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/../compiler-externc/src/test/config</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>copy-custom-resources</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${basedir}/target</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${basedir}/src/test/config</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!--
+ Do all the JFlex code generation
+ -->
+ <plugin>
+ <groupId>de.jflex</groupId>
+ <artifactId>maven-jflex-plugin</artifactId>
+ <version>1.4.3</version>
+ <executions>
+ <execution>
+ <id>generate-raw-as-tokenizer</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>target/generated-sources/jflex</outputDirectory>
+ <lexDefinitions>
+ <lexDefinition>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/RawASTokenizer.lex</lexDefinition>
+ </lexDefinitions>
+ <skeleton>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/skeleton.royale</skeleton>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-raw-as-doc-tokenizer</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>target/generated-sources/jflex</outputDirectory>
+ <lexDefinitions>
+ <lexDefinition>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/RawASDocTokenizer.lex</lexDefinition>
+ </lexDefinitions>
+ <skeleton>src/main/jflex/org/apache/royale/compiler/internal/parsing/as/skeleton.default</skeleton>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-raw-mxml-tokenizer</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>target/generated-sources/jflex</outputDirectory>
+ <lexDefinitions>
+ <lexDefinition>src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex</lexDefinition>
+ </lexDefinitions>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <!--
+ Do all the Antlr2 code generation
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-antlr-plugin</artifactId>
+ <version>2.0-beta-1</version>
+ <executions>
+ <execution>
+ <id>generate-as-parser</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <grammars>org/apache/royale/compiler/internal/parsing/as/ASParser.g</grammars>
+ </configuration>
+ </execution>
+ </executions>
+ <dependencies>
+ <dependency>
+ <groupId>antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>2.7.7</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <!--
+ The generation of the metadata-parser requires Antlr to
+ load ImportMetadataTokenTypes.txt. Unfortunately Altlr
+ looks in the current working directory. The only way to
+ force it to work, is to start a new process with the
+ working directory in the directory containing the file.
+ -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.5.0</version>
+ <executions>
+ <execution>
+ <id>generate-metadata-parser</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>antlr.Tool</arguments>
+ <argument>-o</argument>
+ <argument>../../../../../../../../../../target/generated-sources/antlr/org/apache/royale/compiler/internal/parsing/as</argument>
+ <argument>MetadataParser.g</argument>
+ </arguments>
+ <workingDirectory>src/main/antlr/org/apache/royale/compiler/internal/parsing/as</workingDirectory>
+ <sourceRoot>target/generated-sources/antlr</sourceRoot>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-test-js-typedefs</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>org.apache.royale.compiler.clients.EXTERNC</arguments>
+ <argument>-load-config+=../compiler-externc/src/test/config/externc-config.xml</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-test-js-swc</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>org.apache.royale.compiler.clients.COMPC</arguments>
+ <argument>-load-config+=../compiler-externc/target/compile-as-config.xml</argument>
+ <argument>-output=../compiler-externc/target/js.swc</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-test-custom-swc</id>
+ <phase>test-compile</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <executable>java</executable>
+ <arguments>
+ <argument>-classpath</argument>
+ <classpath />
+ <arguments>org.apache.royale.compiler.clients.COMPC</arguments>
+ <argument>-load-config+=target/compile-as-config.xml</argument>
+ <argument>-output=target/custom.swc</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!--
+ Do all the JBurg code generation.
+ -->
+ <plugin>
+ <groupId>net.sourceforge.jburg</groupId>
+ <artifactId>jburg-maven-plugin</artifactId>
+ <version>1.10.4</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>generate-css-emitter</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>CSSEmitter.jbg</include>
+ </includes>
+ <sourceDirectory>src/main/jburg/org/apache/royale/compiler/internal/css/codegen</sourceDirectory>
+ <outputDirectory>target/generated-sources/jburg/org/apache/royale/compiler/internal/css/codegen</outputDirectory>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-cmc-emitter</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>CmcEmitter.jbg</include>
+ </includes>
+ <sourceDirectory>src/main/jburg/org/apache/royale/compiler/internal/as/codegen</sourceDirectory>
+ <outputDirectory>target/generated-sources/jburg/org/apache/royale/compiler/internal/as/codegen</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- debug=true generates the "dump" method for Emitters, which is used for debugging -->
+ <debug>true</debug>
+ </configuration>
+ <dependencies>
+ <!-- this needs to be first in order to patch jburg -->
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-jburg-types</artifactId>
+ <version>${compiler-jburg-types.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.jburg</groupId>
+ <artifactId>jburg</artifactId>
+ <version>1.10.3</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <!--
+ Do all the Antlr3 code generation.
+ -->
+ <plugin>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr3-maven-plugin</artifactId>
+ <version>3.5.2</version>
+ <executions>
+ <execution>
+ <id>generate-csslexer-and-cssparser</id>
+ <goals>
+ <goal>antlr</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>CSS.g</include>
+ </includes>
+ <sourceDirectory>src/main/antlr3/org/apache/royale/compiler/internal/css</sourceDirectory>
+ <outputDirectory>target/generated-sources/antlr3/org/apache/royale/compiler/internal/css</outputDirectory>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-csstree</id>
+ <goals>
+ <goal>antlr</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>CSSTree.g</include>
+ </includes>
+ <sourceDirectory>src/main/antlr3/org/apache/royale/compiler/internal/css</sourceDirectory>
+ <outputDirectory>target/generated-sources/antlr3/org/apache/royale/compiler/internal/css</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!--
+ Do all the custom processing with the royale build tools.
+ -->
+ <plugin>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-build-tools</artifactId>
+ <version>${compiler-build-tools.version}</version>
+ <executions>
+ <execution>
+ <id>generate-unknown-tree-handler</id>
+ <goals>
+ <goal>generate-unknown-tree-handler</goal>
+ </goals>
+ <configuration>
+ <inputFile>org/apache/royale/compiler/internal/as/codegen/UnknownTreeHandlerPatterns.xml</inputFile>
+ <outputFile>org/apache/royale/compiler/internal/as/codegen/UnknownTreeHandlerPatterns.java</outputFile>
+ </configuration>
+ </execution>
+ <execution>
+ <id>add-suppress-unused-warnings-annotations</id>
+ <goals>
+ <goal>add-class-annotation</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.java</include>
+ <include>antlr/org/apache/royale/compiler/internal/parsing/as/ASTokenTypes.java</include>
+ <include>antlr/org/apache/royale/compiler/internal/parsing/as/MetadataTokenTypes.java</include>
+ </includes>
+ <annotation>@SuppressWarnings("unused")</annotation>
+ </configuration>
+ </execution>
+ <execution>
+ <id>add-suppress-all-warnings-annotations-css</id>
+ <goals>
+ <goal>add-class-annotation</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>antlr3/org/apache/royale/compiler/internal/css/CSSLexer.java</include>
+ <include>antlr3/org/apache/royale/compiler/internal/css/CSSParser.java</include>
+ </includes>
+ <annotation>@SuppressWarnings("all")</annotation>
+ <dateStart>// $ANTLR 3.5.2 ***CSS.g</dateStart>
+ </configuration>
+ </execution>
+ <execution>
+ <id>add-suppress-all-warnings-annotations-csstree</id>
+ <goals>
+ <goal>add-class-annotation</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>antlr3/org/apache/royale/compiler/internal/css/CSSTree.java</include>
+ </includes>
+ <annotation>@SuppressWarnings("all")</annotation>
+ <dateStart>// $ANTLR 3.5.2 ***CSSTree.g</dateStart>
+ </configuration>
+ </execution>
+ <execution>
+ <id>add-suppress-all-warnings-annotations-jburg</id>
+ <goals>
+ <goal>add-class-annotation</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>antlr/org/apache/royale/compiler/internal/parsing/as/MetadataParser.java</include>
+ </includes>
+ <annotation>@SuppressWarnings("all")</annotation>
+ </configuration>
+ </execution>
+ <execution>
+ <id>add-suppress-rawtypes-unchecked-unused-warnings-annotations</id>
+ <goals>
+ <goal>add-class-annotation</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>jburg/org/apache/royale/compiler/internal/css/codegen/CSSEmitter.java</include>
+ <include>jburg/org/apache/royale/compiler/internal/as/codegen/CmcEmitter.java</include>
+ </includes>
+ <annotation>@SuppressWarnings({"rawtypes", "unchecked", "unused"})</annotation>
+ <dateStart>/* Generated</dateStart>
+ <dateEnd> by JBurg</dateEnd>
+ </configuration>
+ </execution>
+ <execution>
+ <id>generate-problems-enum</id>
+ <goals>
+ <goal>generate-problems-enum</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>generate-problems-resource-bundle</id>
+ <goals>
+ <goal>generate-problems-resource-bundle</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Make the surefire execute all unit-tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19</version>
+ <configuration>
+ <includes>
+ <include>**/*Tests.java</include>
+ </includes>
+ <excludes>
+ <exclude>as/**/*Tests.java</exclude>
+ <exclude>f/**</exclude>
+ <exclude>mxml/tags/**</exclude>
+ <exclude>properties/**</exclude>
+ <exclude>**/MXMLComponentTagTests.java</exclude>
+ <exclude>**/MXMLComponentNodeTests.java</exclude>
+ <exclude>**/MXMLHTTPServiceTagTests.java</exclude>
+ <exclude>**/MXMLModelTagTests.java</exclude>
+ <exclude>**/MXMLRemoteObjectNodeTests.java</exclude>
+ <exclude>**/MXMLWebServiceNodeTests.java</exclude>
+ <exclude>**/MXMLDesignLayerNodeTests.java</exclude>
+ <exclude>**/MXMLHTTPServiceNodeTests.java</exclude>
+ <exclude>**/MXMLModelNodeTests.java</exclude>
+ <exclude>**/MXMLRemoteObjectTagTests.java</exclude>
+ <exclude>**/MXMLStateNodeTests.java</exclude>
+ <exclude>**/MXMLVectorNodeTests.java</exclude>
+ <exclude>**/MXMLWebServiceTagTests.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.18.1</version>
+ <configuration>
+ <includes>
+ <include>as/**/*Tests.java</include>
+ </includes>
+ <excludes>
+ <exclude>f/**</exclude>
+ <exclude>mxml/tags/**</exclude>
+ <exclude>properties/**</exclude>
+ <exclude>**/MXMLComponentTagTests.java</exclude>
+ <exclude>**/MXMLComponentNodeTests.java</exclude>
+ <exclude>**/MXMLHTTPServiceTagTests.java</exclude>
+ <exclude>**/MXMLModelTagTests.java</exclude>
+ <exclude>**/MXMLRemoteObjectNodeTests.java</exclude>
+ <exclude>**/MXMLWebServiceNodeTests.java</exclude>
+ <exclude>**/MXMLDesignLayerNodeTests.java</exclude>
+ <exclude>**/MXMLHTTPServiceNodeTests.java</exclude>
+ <exclude>**/MXMLModelNodeTests.java</exclude>
+ <exclude>**/MXMLRemoteObjectTagTests.java</exclude>
+ <exclude>**/MXMLStateNodeTests.java</exclude>
+ <exclude>**/MXMLVectorNodeTests.java</exclude>
+ <exclude>**/MXMLWebServiceTagTests.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <!--
+ This profile adds one test, that relies on the original FDK being
+ available as it compiles each project in the framework/projects
+ directory. It requires some environment variables being set.
+ -->
+ <profile>
+ <id>include-sdk-compile-tests</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <configuration>
+ <includes combine.children="append">
+ <include>f/**/*Tests.java</include>
+ <include>mxml/**/*Tests.java</include>
+ <include>properties/**/*Tests.java</include>
+ <include>**/MXMLComponentTagTests.java</include>
+ <include>**/MXMLComponentNodeTests.java</include>
+ <include>**/MXMLHTTPServiceTagTests.java</include>
+ <include>**/MXMLModelTagTests.java</include>
+ <include>**/MXMLRemoteObjectNodeTests.java</include>
+ <include>**/MXMLWebServiceNodeTests.java</include>
+ <include>**/MXMLDesignLayerNodeTests.java</include>
+ <include>**/MXMLHTTPServiceNodeTests.java</include>
+ <include>**/MXMLModelNodeTests.java</include>
+ <include>**/MXMLRemoteObjectTagTests.java</include>
+ <include>**/MXMLStateNodeTests.java</include>
+ <include>**/MXMLVectorNodeTests.java</include>
+ <include>**/MXMLWebServiceTagTests.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-jburg-types</artifactId>
+ <version>${compiler-jburg-types.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-common</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.flex</groupId>
+ <artifactId>flex-tool-api</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.2</version>
+ </dependency>
+ <dependency>
+ <groupId>org.antlr</groupId>
+ <artifactId>antlr</artifactId>
+ <version>3.3</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ <version>25.1-jre</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.jburg</groupId>
+ <artifactId>jburg</artifactId>
+ <version>1.10.3</version>
+ </dependency>
+ <dependency>
+ <groupId>de.jflex</groupId>
+ <artifactId>jflex</artifactId>
+ <version>1.6.0</version>
+ <exclusions>
+ <exclusion>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.b1.pack</groupId>
+ <artifactId>lzma-sdk-4j</artifactId>
+ <version>9.22.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-test-utils</artifactId>
+ <version>0.9.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-externc</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ <scope>test</scope>
+ </dependency>
+ <!-- TODO: Currently only needed for the duplicate FlashplayerSecurityHandler -->
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.4</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g b/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
index c9b1528..8a6a299 100644
--- a/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
+++ b/compiler/src/main/antlr/org/apache/royale/compiler/internal/parsing/as/ASParser.g
@@ -212,7 +212,7 @@
/**
* Matches an attribute such as:
- * - Modifiers: dynamic, final, native, override, static, virtual.
+ * - Modifiers: dynamic, final, native, override, static, virtual, abstract.
* - Namespace names.
* - Reserved namespace names: internal, private, public, protected.
*
@@ -580,6 +580,7 @@
| TOKEN_MODIFIER_STATIC
| TOKEN_MODIFIER_NATIVE
| TOKEN_MODIFIER_VIRTUAL
+ | TOKEN_MODIFIER_ABSTRACT
)
{ modifierNode = new ModifierNode((ASToken) modifierT); }
;
@@ -1884,6 +1885,7 @@
b = t.getContentsNode();
}
caseStatementList[b]
+ | asDocComment
;
exception catch [RecognitionException ex] {handleParsingError(ex); }
diff --git a/compiler/src/main/java/org/apache/royale/abc/semantics/Block.java b/compiler/src/main/java/org/apache/royale/abc/semantics/Block.java
index 930cf90..1d89d30 100644
--- a/compiler/src/main/java/org/apache/royale/abc/semantics/Block.java
+++ b/compiler/src/main/java/org/apache/royale/abc/semantics/Block.java
@@ -48,7 +48,7 @@
/**
* Successors to this block.
*/
- private Set<IBasicBlock> successors = Collections.emptySet();
+ private Collection<IBasicBlock> successors = Collections.emptySet();
/**
* @return successors of this block.
@@ -59,6 +59,12 @@
}
/**
+ * block number assigned by ControlFlowGraph. So far,
+ * only used to try to guarantee order in lists/collections
+ */
+ public int blocknum;
+
+ /**
* Add a successor to this block.
*
* @param succ - the successor block.
@@ -66,7 +72,7 @@
void addSuccessor(IBasicBlock succ)
{
if (this.successors.size() == 0)
- this.successors = new HashSet<IBasicBlock>();
+ this.successors = new ArrayList<IBasicBlock>();
this.successors.add(succ);
}
diff --git a/compiler/src/main/java/org/apache/royale/abc/semantics/ControlFlowGraph.java b/compiler/src/main/java/org/apache/royale/abc/semantics/ControlFlowGraph.java
index de0c42b..4f2800d 100644
--- a/compiler/src/main/java/org/apache/royale/abc/semantics/ControlFlowGraph.java
+++ b/compiler/src/main/java/org/apache/royale/abc/semantics/ControlFlowGraph.java
@@ -23,10 +23,13 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
import org.apache.royale.abc.ABCConstants;
import org.apache.royale.abc.graph.IBasicBlock;
@@ -34,6 +37,8 @@
import org.apache.royale.abc.graph.algorithms.DepthFirstPreorderIterator;
import org.apache.royale.abc.graph.algorithms.DominatorTree;
import org.apache.royale.abc.visitors.IFlowGraphVisitor;
+import org.apache.royale.compiler.css.ICSSDocument;
+import org.apache.royale.compiler.internal.projects.LibraryPathManager;
/**
* A ControlFlowGraph represents the flow of control through a sequence of
@@ -190,7 +195,24 @@
// We've seen all the instructions now, so we can compute the blocks that
// each label corresponds to, and fill in the rest of the graph
- for (Map.Entry<Block, Collection<Label>> entry : successor_labels.entrySet())
+ Set<Entry<Block, Collection<Label>>> entries = successor_labels.entrySet();
+ ArrayList<Entry<Block, Collection<Label>>> listOfEntries = new ArrayList<Entry<Block, Collection<Label>>>();
+ for (Map.Entry<Block, Collection<Label>> entry : entries)
+ listOfEntries.add(entry);
+ Collections.sort(listOfEntries, new Comparator<Entry<Block, Collection<Label>>>()
+ {
+ /**
+ * Sort by blocknum.
+ */
+ @Override
+ public int compare(Entry<Block, Collection<Label>> o1, Entry<Block, Collection<Label>> o2)
+ {
+ int block1 = o1.getKey().blocknum;
+ int block2 = o2.getKey().blocknum;
+ return block1 - block2;
+ }
+ });
+ for (Map.Entry<Block, Collection<Label>> entry : listOfEntries)
for (Label target_label : entry.getValue())
{
IBasicBlock target_block = getBlock(target_label);
@@ -259,6 +281,7 @@
private Block newBlock()
{
Block result = new Block();
+ result.blocknum = blocks.size();
blocks.add(result);
return result;
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/clients/ASC.java b/compiler/src/main/java/org/apache/royale/compiler/clients/ASC.java
index 615ce7c..83e154f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/clients/ASC.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/clients/ASC.java
@@ -490,6 +490,18 @@
{
return removeDeadCode;
}
+
+ @Override
+ public String getSWFMetadataDate() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getSWFMetadataDateFormat() {
+ // TODO Auto-generated method stub
+ return null;
+ }
}
private static final int EXIT_CODE_SUCCESS = 0;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/clients/ASDOC.java b/compiler/src/main/java/org/apache/royale/compiler/clients/ASDOC.java
index 07d66f5..24a3b71 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/clients/ASDOC.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/clients/ASDOC.java
@@ -188,6 +188,7 @@
{
final ISWCWriter swcWriter = new SWCWriter(outputOptionValue, useCompression,
targetSettings.isDebugEnabled(), targetSettings.isTelemetryEnabled(),
+ targetSettings.getSWFMetadataDate(), targetSettings.getSWFMetadataDateFormat(),
SizeReportWritingSWFWriter.getSWFWriterFactory(targetSettings.getSizeReport()));
swcWriter.write(swc);
final File outputFile = new File(outputOptionValue);
diff --git a/compiler/src/main/java/org/apache/royale/compiler/clients/COMPC.java b/compiler/src/main/java/org/apache/royale/compiler/clients/COMPC.java
index ef06ba7..c8c320b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/clients/COMPC.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/clients/COMPC.java
@@ -200,6 +200,7 @@
System.out.println("output swc as file");
final ISWCWriter swcWriter = new SWCWriter(outputOptionValue, useCompression,
targetSettings.isDebugEnabled(), targetSettings.isTelemetryEnabled(),
+ targetSettings.getSWFMetadataDate(), targetSettings.getSWFMetadataDateFormat(),
SizeReportWritingSWFWriter.getSWFWriterFactory(targetSettings.getSizeReport()));
if ((CompilerDiagnosticsConstants.diagnostics & CompilerDiagnosticsConstants.COMPC_PHASES) == CompilerDiagnosticsConstants.COMPC_PHASES)
System.out.println("attempting to write swc");
diff --git a/compiler/src/main/java/org/apache/royale/compiler/clients/MXMLC.java b/compiler/src/main/java/org/apache/royale/compiler/clients/MXMLC.java
index 497997e..8c1a971 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/clients/MXMLC.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/clients/MXMLC.java
@@ -121,7 +121,7 @@
// Therefore the following enum values must be non-negative.
SUCCESS(0),
PRINT_HELP(1),
- FAILED_WITH_PROBLEMS(2),
+ FAILED_WITH_PROBLEMS(0),
FAILED_WITH_ERRORS(3),
FAILED_WITH_EXCEPTIONS(4),
FAILED_WITH_CONFIG_ERRORS(5);
diff --git a/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java b/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
index dee1690..4aba20b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/constants/IMetaAttributeConstants.java
@@ -210,6 +210,12 @@
static final String NAME_MIN_VALUE_EXCLUSIVE = "minValueExclusive";
static final String NAME_MAX_VALUE = "maxValue";
static final String NAME_MAX_VALUE_EXCLUSIVE = "maxValueExclusive";
+
+ // [RoyaleAbstract]
+ static final String ATTRIBUTE_ABSTRACT = "RoyaleAbstract";
+
+ // [RoyalePrivateConstructor]
+ static final String ATTRIBUTE_PRIVATE_CONSTRUCTOR = "RoyalePrivateConstructor";
/**
* List of metadata tags that do not inherit
@@ -222,6 +228,8 @@
ATTRIBUTE_DEPRECATED,
ATTRIBUTE_DISCOURAGED_FOR_PROFILE,
ATTRIBUTE_EXCLUDECLASS,
+ ATTRIBUTE_ABSTRACT,
+ ATTRIBUTE_PRIVATE_CONSTRUCTOR,
})));
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/abc/ScopedDefinitionTraitsVisitor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/abc/ScopedDefinitionTraitsVisitor.java
index 82d7002..0298127 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/abc/ScopedDefinitionTraitsVisitor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/abc/ScopedDefinitionTraitsVisitor.java
@@ -256,7 +256,13 @@
public boolean apply(Namespace ns)
{
return ns.getApiVersion() != ABCConstants.NO_API_VERSION;
- } });
+ }
+ @Override
+ public boolean test(Namespace input)
+ {
+ return apply(input);
+ }
+ });
}
public static String getDefinitionName(Name name)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ABCGeneratingReducer.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ABCGeneratingReducer.java
index 5dfb649..b4eb1cf 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ABCGeneratingReducer.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ABCGeneratingReducer.java
@@ -72,7 +72,6 @@
import org.apache.royale.compiler.problems.UnknownContinueTargetProblem;
import org.apache.royale.compiler.problems.VoidTypeProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
-import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
@@ -6415,7 +6414,8 @@
*/
private enum XMLContentState { TagStart, TagLiteral, TagName, Attr, ValueNeedsEquals, Value, TagEnd, ContentLiteral, ContentExpression };
- public InstructionList reduce_XMLContent(IASNode iNode, Vector<InstructionList> exprs)
+ @SuppressWarnings("incomplete-switch")
+ public InstructionList reduce_XMLContent(IASNode iNode, Vector<InstructionList> exprs)
{
InstructionList result = createInstructionList(iNode);
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
index cc1fef1..16cfa1e 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/ClassDirectiveProcessor.java
@@ -50,18 +50,24 @@
import org.apache.royale.compiler.constants.IASKeywordConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.constants.IMetaAttributeConstants;
+import org.apache.royale.compiler.constants.INamespaceConstants;
import org.apache.royale.compiler.definitions.IAccessorDefinition;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IConstantDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IInterfaceDefinition;
+import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
+import org.apache.royale.compiler.definitions.references.INamespaceReference;
import org.apache.royale.compiler.exceptions.CodegenInterruptedException;
+import org.apache.royale.compiler.problems.AbstractOutsideClassProblem;
+import org.apache.royale.compiler.problems.BadAccessAbstractMethodProblem;
import org.apache.royale.compiler.problems.CircularTypeReferenceProblem;
import org.apache.royale.compiler.problems.ConstructorCannotHaveReturnTypeProblem;
import org.apache.royale.compiler.problems.ConstructorIsGetterSetterProblem;
import org.apache.royale.compiler.problems.ConstructorIsStaticProblem;
+import org.apache.royale.compiler.problems.ConstructorMustBePublicOrPrivateProblem;
import org.apache.royale.compiler.problems.ConstructorMustBePublicProblem;
import org.apache.royale.compiler.problems.DuplicateClassDefinitionProblem;
import org.apache.royale.compiler.problems.DynamicNotOnClassProblem;
@@ -77,6 +83,7 @@
import org.apache.royale.compiler.problems.OverrideNotFoundProblem;
import org.apache.royale.compiler.problems.StaticAndOverrideProblem;
import org.apache.royale.compiler.problems.StaticNamespaceDefinitionProblem;
+import org.apache.royale.compiler.problems.SyntaxProblem;
import org.apache.royale.compiler.problems.VirtualOutsideClassProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
@@ -85,6 +92,7 @@
import org.apache.royale.compiler.tree.as.IDefinitionNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
+import org.apache.royale.compiler.tree.as.INamespaceDecorationNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode.LanguageIdentifierKind;
import org.apache.royale.compiler.internal.abc.FunctionGeneratorHelper;
import org.apache.royale.compiler.internal.as.codegen.ICodeGenerator.IConstantValue;
@@ -467,6 +475,7 @@
initInstructions.addInstruction(OP_initproperty, className);
implementedInterfaceSemanticChecks(class_definition);
+ implementedAbstractClassSemanticChecks(class_definition);
processResourceBundles(class_definition, project, classScope.getProblems());
}
@@ -956,6 +965,8 @@
FunctionDefinition func = node.getDefinition();
+ verifyFunctionNamespace(node, func);
+
Collection<ICompilerProblem> problems = classScope.getProblems();
// code model has some peculiar ideas about what makes a function a constructor or not
@@ -972,9 +983,21 @@
// It is ok to omit the namespace
// We must check the AST, as CM treats all ctors as public no matter what the user typed in
// so the FunctionDefinition will always be in the public namespace
- if( node.getActualNamespaceNode() != null &&
- node.getActualNamespaceNode().getName() != IASKeywordConstants.PUBLIC)
- problems.add(new ConstructorMustBePublicProblem(node.getActualNamespaceNode()));
+ if( node.getActualNamespaceNode() != null )
+ {
+ if (classScope.getProject().getAllowPrivateConstructors())
+ {
+ if (node.getActualNamespaceNode().getName() != IASKeywordConstants.PUBLIC
+ && !func.isPrivate())
+ {
+ problems.add(new ConstructorMustBePublicOrPrivateProblem(node.getActualNamespaceNode()));
+ }
+ }
+ else if (node.getActualNamespaceNode().getName() != IASKeywordConstants.PUBLIC || func.isPrivate())
+ {
+ problems.add(new ConstructorMustBePublicProblem(node.getActualNamespaceNode()));
+ }
+ }
// A constructor cannot be static
if( func.isStatic() )
@@ -1064,37 +1087,131 @@
}
}
}
+
+ /**
+ * Check the class definition for various errors related to extended
+ * abstract classes, such as making sure that all abstract methods are
+ * implemented
+ *
+ * @param cls the class definition to check
+ */
+ void implementedAbstractClassSemanticChecks(ClassDefinition cls)
+ {
+ if(!classScope.getProject().getAllowAbstractClasses())
+ {
+ //don't do these checks if abstract classes aren't enabled
+ return;
+ }
+ if(cls.isAbstract())
+ {
+ // concrete classes don't need to implement abstract methods
+ return;
+ }
+ Iterator<IClassDefinition> it = cls.classIterator(classScope.getProject(), false);
+ while( it.hasNext() )
+ {
+ IClassDefinition otherClass = it.next();
+ if(!otherClass.isAbstract())
+ {
+ //if a subclass is already concrete, then we don't need to check
+ //this class for abstract methods too
+ break;
+ }
+
+ if( otherClass instanceof ClassDefinition && otherClass.isAbstract())
+ {
+ ((ClassDefinition)otherClass).validateClassImplementsAllMethods(classScope.getProject(), cls, classScope.getProblems());
+ }
+ }
+ }
+
+ /**
+ * Verify that abstract function has an appropriate namespace. If it doesn't,
+ * print the appropriate error
+ *
+ * @param func is the function node do be analyzed
+ * @param func_def is the definition for func
+ */
+ private void verifyFunctionNamespace(FunctionNode func, FunctionDefinition func_def)
+ {
+ if(!classScope.getProject().getAllowAbstractClasses())
+ {
+ //if abstract classes aren't allowed, other errors should take
+ //precedence
+ return;
+ }
+
+ if(!func_def.isAbstract())
+ {
+ return;
+ }
+
+ INamespaceDecorationNode nsNode = func.getActualNamespaceNode();
+
+ // if we have no "actual" node, then there is no namespace in front of our function
+ if (nsNode != null)
+ {
+ if (!INamespaceConstants.internal_.equals(nsNode.getName()))
+ {
+ INamespaceReference ns_ref = func_def.getNamespaceReference();
+ INamespaceDefinition ns_def = ns_ref.resolveNamespaceReference(classScope.getProject());
+ if (ns_def != null && ns_def instanceof INamespaceDefinition.IPrivateNamespaceDefinition)
+ {
+ classScope.addProblem(new BadAccessAbstractMethodProblem(func));
+ }
+ }
+ }
+ }
+
/**
*/
protected void verifyFunctionModifiers(FunctionNode f)
{
- ModifiersSet modifiersSet = f.getModifiers();
- if (modifiersSet == null)
- return;
-
IExpressionNode site = f.getNameExpressionNode();
- if( modifiersSet.hasModifier(ASModifier.STATIC) )
+ IDefinition functionDef = f.getDefinition();
+
+ boolean isStatic = false; //used below
+ ModifiersSet modifiersSet = f.getModifiers();
+ if (modifiersSet != null)
{
- if( modifiersSet.hasModifier(ASModifier.FINAL) )
+ isStatic = modifiersSet.hasModifier(ASModifier.STATIC);
+ if(isStatic)
{
- classScope.addProblem(new FinalOutsideClassProblem(site) );
+ if( modifiersSet.hasModifier(ASModifier.FINAL) )
+ {
+ classScope.addProblem(new FinalOutsideClassProblem(site) );
+ }
+ if( modifiersSet.hasModifier(ASModifier.OVERRIDE) )
+ {
+ classScope.addProblem(new StaticAndOverrideProblem(site) );
+ }
+ if( modifiersSet.hasModifier(ASModifier.DYNAMIC) )
+ {
+ classScope.addProblem(new DynamicNotOnClassProblem(site) );
+ }
+ if( modifiersSet.hasModifier(ASModifier.VIRTUAL) )
+ {
+ classScope.addProblem(new VirtualOutsideClassProblem(site) );
+ }
}
- if( modifiersSet.hasModifier(ASModifier.OVERRIDE) )
+ classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(f);
+ // Functions in a class allow all modifiers
+ }
+
+ if (functionDef.isAbstract())
+ {
+ if (classScope.getProject().getAllowAbstractClasses())
{
- classScope.addProblem(new StaticAndOverrideProblem(site) );
+ if (!SemanticUtils.canBeAbstract(f, classScope.getProject()))
+ {
+ classScope.addProblem(new AbstractOutsideClassProblem(site) );
+ }
}
- if( modifiersSet.hasModifier(ASModifier.DYNAMIC) )
+ else
{
- classScope.addProblem(new DynamicNotOnClassProblem(site) );
- }
- if( modifiersSet.hasModifier(ASModifier.VIRTUAL) )
- {
- classScope.addProblem(new VirtualOutsideClassProblem(site) );
+ classScope.addProblem(new SyntaxProblem(site, IASKeywordConstants.ABSTRACT));
}
}
- classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(f);
- // Functions in a class allow all modifiers
- return;
}
protected void verifyVariableModifiers(VariableNode v)
@@ -1127,6 +1244,17 @@
{
classScope.addProblem(new VirtualOutsideClassProblem(site));
}
+ else if( modifier == ASModifier.ABSTRACT )
+ {
+ if(classScope.getProject().getAllowAbstractClasses())
+ {
+ classScope.addProblem(new AbstractOutsideClassProblem(site));
+ }
+ else
+ {
+ classScope.addProblem(new SyntaxProblem(site, IASKeywordConstants.ABSTRACT));
+ }
+ }
}
classScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(v);
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/DirectiveProcessor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/DirectiveProcessor.java
index d199a88..c052318 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/DirectiveProcessor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/DirectiveProcessor.java
@@ -23,7 +23,6 @@
-import org.apache.royale.abc.instructionlist.InstructionList;
import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
import org.apache.royale.compiler.internal.tree.as.ClassNode;
import org.apache.royale.compiler.internal.tree.as.FunctionNode;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
index 0f4f3c8..7f28031 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/GlobalDirectiveProcessor.java
@@ -30,6 +30,7 @@
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.common.ModifiersSet;
+import org.apache.royale.compiler.constants.IASKeywordConstants;
import org.apache.royale.compiler.constants.IMetaAttributeConstants;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
@@ -45,6 +46,7 @@
import org.apache.royale.compiler.internal.tree.as.PackageNode;
import org.apache.royale.compiler.internal.tree.as.VariableNode;
import org.apache.royale.compiler.internal.tree.mxml.MXMLDocumentNode;
+import org.apache.royale.compiler.problems.AbstractOutsideClassProblem;
import org.apache.royale.compiler.problems.DynamicNotOnClassProblem;
import org.apache.royale.compiler.problems.EmbedOnlyOnClassesAndVarsProblem;
import org.apache.royale.compiler.problems.FinalOutsideClassProblem;
@@ -54,6 +56,7 @@
import org.apache.royale.compiler.problems.NativeVariableProblem;
import org.apache.royale.compiler.problems.OverrideOutsideClassProblem;
import org.apache.royale.compiler.problems.StaticOutsideClassProblem;
+import org.apache.royale.compiler.problems.SyntaxProblem;
import org.apache.royale.compiler.problems.VirtualOutsideClassProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.mxml.IMXMLDocumentNode;
@@ -320,30 +323,47 @@
*/
protected void verifyClassModifiers(ClassNode c)
{
- ModifiersSet modifiersSet = c.getModifiers();
- if (modifiersSet == null)
- return;
-
- ASModifier[] modifiers = modifiersSet.getAllModifiers();
IExpressionNode site = c.getNameExpressionNode();
- for (ASModifier modifier : modifiers)
+
+ ModifiersSet modifiersSet = c.getModifiers();
+ if (modifiersSet != null)
{
- // final allowed on a class
- if( modifier == ASModifier.FINAL || modifier == ASModifier.DYNAMIC)
+ ASModifier[] modifiers = modifiersSet.getAllModifiers();
+ for (ASModifier modifier : modifiers)
{
- continue;
+ // final, dynamic, and abstract allowed on a class
+ if( modifier == ASModifier.FINAL || modifier == ASModifier.DYNAMIC || modifier == ASModifier.ABSTRACT)
+ {
+ continue;
+ }
+ // native generates different error for class/interface
+ else if (modifier == ASModifier.NATIVE)
+ {
+ currentScope.addProblem(new NativeNotOnFunctionProblem(site) );
+ }
+ else
+ {
+ verifyModifier(site, modifier);
+ }
}
- // native generates different error for class/interface
- else if (modifier == ASModifier.NATIVE)
+ currentScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(c);
+ }
+
+ IDefinition classDef = c.getDefinition();
+ if (classDef.isAbstract())
+ {
+ if (currentScope.getProject().getAllowAbstractClasses())
{
- currentScope.addProblem(new NativeNotOnFunctionProblem(site) );
+ if(!SemanticUtils.canBeAbstract(c, currentScope.getProject()))
+ {
+ currentScope.addProblem(new AbstractOutsideClassProblem(site) );
+ }
}
else
{
- verifyModifier(site, modifier);
+ currentScope.addProblem(new SyntaxProblem(site, IASKeywordConstants.ABSTRACT));
}
}
- currentScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(c);
}
/**
@@ -408,6 +428,17 @@
currentScope.addProblem(new OverrideOutsideClassProblem(site));
else if( modifier == ASModifier.VIRTUAL )
currentScope.addProblem(new VirtualOutsideClassProblem(site));
+ else if( modifier == ASModifier.ABSTRACT )
+ {
+ if(currentScope.getProject().getAllowAbstractClasses())
+ {
+ currentScope.addProblem(new AbstractOutsideClassProblem(site));
+ }
+ else
+ {
+ currentScope.addProblem(new SyntaxProblem(site, IASKeywordConstants.ABSTRACT));
+ }
+ }
}
/**
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InlineFunctionLexicalScope.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InlineFunctionLexicalScope.java
index c53032a..395c02e 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InlineFunctionLexicalScope.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InlineFunctionLexicalScope.java
@@ -121,7 +121,7 @@
{
String paramName = params[i].getBaseName();
Binding paramBinding = getBinding(params[i]);
- if (paramBinding != null && !uniqueParamNames.contains(paramBinding))
+ if (paramBinding != null && !uniqueParamNames.contains(paramName))
{
result.addInstruction(paramBinding.setlocal());
uniqueParamNames.add(paramName);
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
index 2177b77..e8409c3 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/InterfaceDirectiveProcessor.java
@@ -38,6 +38,7 @@
import org.apache.royale.compiler.common.ASModifier;
import org.apache.royale.compiler.common.IMetaInfo;
import org.apache.royale.compiler.common.ModifiersSet;
+import org.apache.royale.compiler.constants.IASKeywordConstants;
import org.apache.royale.compiler.constants.INamespaceConstants;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IInterfaceDefinition;
@@ -55,6 +56,7 @@
import org.apache.royale.compiler.internal.tree.as.InterfaceNode;
import org.apache.royale.compiler.internal.tree.as.NamespaceIdentifierNode;
import org.apache.royale.compiler.internal.tree.as.VariableNode;
+import org.apache.royale.compiler.problems.AbstractOutsideClassProblem;
import org.apache.royale.compiler.problems.AmbiguousReferenceProblem;
import org.apache.royale.compiler.problems.CannotExtendClassProblem;
import org.apache.royale.compiler.problems.ConstructorInInterfaceProblem;
@@ -67,6 +69,7 @@
import org.apache.royale.compiler.problems.NamespaceInInterfaceProblem;
import org.apache.royale.compiler.problems.NativeUsedInInterfaceProblem;
import org.apache.royale.compiler.problems.StaticOutsideClassProblem;
+import org.apache.royale.compiler.problems.SyntaxProblem;
import org.apache.royale.compiler.problems.UnknownInterfaceProblem;
import org.apache.royale.compiler.problems.BadAccessInterfaceMemberProblem;
import org.apache.royale.compiler.problems.InterfaceNamespaceAttributeProblem;
@@ -347,6 +350,8 @@
// Warn if there is no return type
SemanticUtils.checkReturnValueHasNoTypeDeclaration(interfaceScope, func, func_def);
+ // Warn if there are any missing parameter types
+ SemanticUtils.checkParametersHaveNoTypeDeclaration(interfaceScope, func, func_def);
// Interface methods can't have a body
if( func.hasBody() )
@@ -426,40 +431,54 @@
*/
protected void verifyFunctionModifiers(FunctionNode f)
{
- ModifiersSet modifiersSet = f.getModifiers();
- if (modifiersSet == null)
- return;
-
- ASModifier[] modifiers = modifiersSet.getAllModifiers();
IExpressionNode site = f.getNameExpressionNode();
- for (ASModifier modifier : modifiers)
+
+ ModifiersSet modifiersSet = f.getModifiers();
+ if (modifiersSet != null)
{
- if( modifier == ASModifier.STATIC )
+ ASModifier[] modifiers = modifiersSet.getAllModifiers();
+ for (ASModifier modifier : modifiers)
{
- this.interfaceScope.addProblem(new StaticOutsideClassProblem(site));
+ if( modifier == ASModifier.STATIC )
+ {
+ this.interfaceScope.addProblem(new StaticOutsideClassProblem(site));
+ }
+ else if ( modifier == ASModifier.OVERRIDE )
+ {
+ interfaceScope.addProblem(new InvalidOverrideProblem(site));
+ }
+ else if( modifier == ASModifier.FINAL )
+ {
+ interfaceScope.addProblem(new FinalOutsideClassProblem(site));
+ }
+ else if( modifier == ASModifier.NATIVE )
+ {
+ interfaceScope.addProblem(new NativeUsedInInterfaceProblem(site));
+ }
+ else if( modifier == ASModifier.VIRTUAL )
+ {
+ interfaceScope.addProblem(new VirtualOutsideClassProblem(site));
+ }
+ else if ( modifier == ASModifier.DYNAMIC )
+ {
+ // Allow this and continue.
+ }
}
- else if ( modifier == ASModifier.OVERRIDE )
+ interfaceScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(f);
+ }
+
+ IDefinition functionDef = f.getDefinition();
+ if (functionDef.isAbstract())
+ {
+ if (interfaceScope.getProject().getAllowAbstractClasses())
{
- interfaceScope.addProblem(new InvalidOverrideProblem(site));
+ interfaceScope.addProblem(new AbstractOutsideClassProblem(site));
}
- else if( modifier == ASModifier.FINAL )
+ else
{
- interfaceScope.addProblem(new FinalOutsideClassProblem(site));
- }
- else if( modifier == ASModifier.NATIVE )
- {
- interfaceScope.addProblem(new NativeUsedInInterfaceProblem(site));
- }
- else if( modifier == ASModifier.VIRTUAL )
- {
- interfaceScope.addProblem(new VirtualOutsideClassProblem(site));
- }
- else if ( modifier == ASModifier.DYNAMIC )
- {
- // Allow this and continue.
+ interfaceScope.addProblem(new SyntaxProblem(site, IASKeywordConstants.ABSTRACT));
}
}
- interfaceScope.getMethodBodySemanticChecker().checkForDuplicateModifiers(f);
}
/**
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/LabelScopeControlFlowContext.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/LabelScopeControlFlowContext.java
index 29b6ce8..a01549f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/LabelScopeControlFlowContext.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/LabelScopeControlFlowContext.java
@@ -72,7 +72,8 @@
* @param labelMap Map to populate with found labels
* @param node Node to search from.
*/
- private static void populateLabelMap(Multimap<String, LabeledStatementNode> labelMap, IASNode node)
+ @SuppressWarnings("incomplete-switch")
+ private static void populateLabelMap(Multimap<String, LabeledStatementNode> labelMap, IASNode node)
{
ASTNodeID nodeID = node.getNodeID();
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/MXMLClassDirectiveProcessor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/MXMLClassDirectiveProcessor.java
index b92da21..01adf85 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/MXMLClassDirectiveProcessor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/MXMLClassDirectiveProcessor.java
@@ -2852,6 +2852,11 @@
{
return node instanceof IMXMLInstanceNode;
}
+ @Override
+ public boolean test(IASNode input)
+ {
+ return apply(input);
+ }
};
/**
@@ -2864,6 +2869,11 @@
{
return node instanceof IMXMLSpecifierNode;
}
+ @Override
+ public boolean test(IASNode input)
+ {
+ return apply(input);
+ }
};
/**
@@ -4355,7 +4365,8 @@
* based on the instances, properties, styles, and events
* that depend on the state.
*/
- void processMXMLState(IMXMLStateNode stateNode, Context context)
+ @SuppressWarnings("incomplete-switch")
+ void processMXMLState(IMXMLStateNode stateNode, Context context)
{
int numElements = 1;
if (getProject().getTargetSettings().getMxmlChildrenAsData())
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/clients/CLIFactory.java b/compiler/src/main/java/org/apache/royale/compiler/internal/clients/CLIFactory.java
index 48cad1b..d09c164 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/clients/CLIFactory.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/clients/CLIFactory.java
@@ -48,7 +48,7 @@
*
* @return Apache Common CLI options
*/
- @SuppressWarnings("static")
+ @SuppressWarnings({ "static-access" })
public static Options getOptionsForASC()
{
if (ascOptions != null)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDatabase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDatabase.java
index 186d602..43d392c 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDatabase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDatabase.java
@@ -317,7 +317,8 @@
return ret;
}
- private boolean objIsType(WatcherInfoBase obj, WatcherType type)
+ @SuppressWarnings("incomplete-switch")
+ private boolean objIsType(WatcherInfoBase obj, WatcherType type)
{
boolean ret = false;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDestinationMaker.java b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDestinationMaker.java
index add3260..6ffc3fa 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDestinationMaker.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingDestinationMaker.java
@@ -31,14 +31,21 @@
import org.apache.royale.compiler.internal.as.codegen.InstructionListNode;
import org.apache.royale.compiler.internal.as.codegen.MXMLClassDirectiveProcessor;
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.royale.compiler.internal.tree.as.DynamicAccessNode;
+import org.apache.royale.compiler.internal.tree.as.IdentifierNode;
+import org.apache.royale.compiler.internal.tree.as.NodeBase;
+import org.apache.royale.compiler.internal.tree.as.NumericLiteralNode;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
+import org.apache.royale.compiler.tree.mxml.IMXMLArrayNode;
+import org.apache.royale.compiler.tree.mxml.IMXMLConcatenatedDataBindingNode;
import org.apache.royale.compiler.tree.mxml.IMXMLDataBindingNode;
import org.apache.royale.compiler.tree.mxml.IMXMLModelNode;
import org.apache.royale.compiler.tree.mxml.IMXMLModelPropertyNode;
import org.apache.royale.compiler.tree.mxml.IMXMLModelRootNode;
import org.apache.royale.compiler.tree.mxml.IMXMLPropertySpecifierNode;
import org.apache.royale.compiler.tree.mxml.IMXMLSingleDataBindingNode;
+import org.apache.royale.compiler.tree.mxml.IMXMLStringNode;
/**
* Utility class for analyze binding destinations and making
@@ -144,6 +151,42 @@
}
}
}
+ else if (parent instanceof IMXMLStringNode && dbnode instanceof IMXMLConcatenatedDataBindingNode)
+ {
+ // this is a binding in a literal like a string, such as 'this is {SOME_VAR} times';
+ // we need to figure out how to set the evaluated value.
+ // if this binding is not in an array, then other code will use the effectiveID of the string
+ // and set the value.
+ // if it is in an array, then figure out the index in the array to set
+ if (parent.getParent() instanceof IMXMLArrayNode)
+ {
+ int index = -1;
+ int n = parent.getParent().getChildCount();
+ for (int i = 0; i < n; i++)
+ {
+ IASNode child = parent.getParent().getChild(i);
+ if (child == parent)
+ {
+ index = i;
+ break;
+ }
+ }
+ IdentifierNode arrayNode = new IdentifierNode(((IMXMLArrayNode)parent.getParent()).getEffectiveID());
+ arrayNode.setSourcePath(parent.getSourcePath());
+ arrayNode.setColumn(parent.getColumn());
+ arrayNode.setLine(parent.getLine());
+ NumericLiteralNode indexNode = new NumericLiteralNode(new Integer(index).toString());
+ indexNode.setSourcePath(parent.getSourcePath());
+ indexNode.setColumn(parent.getColumn());
+ indexNode.setLine(parent.getLine());
+ DynamicAccessNode mae = new DynamicAccessNode(arrayNode);
+ mae.setRightOperandNode(indexNode);
+ mae.setParent((NodeBase) dbnode.getParent());
+ arrayNode.setParent(mae);
+ indexNode.setParent(mae);
+ return mae;
+ }
+ }
return ret;
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/config/RoyaleTargetSettings.java b/compiler/src/main/java/org/apache/royale/compiler/internal/config/RoyaleTargetSettings.java
index e3d966c..414eed6 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/config/RoyaleTargetSettings.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/config/RoyaleTargetSettings.java
@@ -22,23 +22,15 @@
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
-import java.util.TreeMap;
-import org.apache.commons.io.FileUtils;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.config.Configurator;
-import org.apache.royale.compiler.config.RSLSettings;
import org.apache.royale.compiler.internal.projects.LibraryPathManager;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.projects.IRoyaleProject;
-import org.apache.royale.compiler.targets.ITargetSettings;
-import org.apache.royale.utils.FilenameNormalization;
-import com.google.common.collect.ImmutableList;
/**
* Value object of ITargetSettings.
@@ -72,4 +64,14 @@
return externalLibraryPath;
}
+
+ @Override
+ public File getLinkReport()
+ {
+ if (project != null)
+ return ((IRoyaleProject)project).getLinkReport(configuration);
+
+ return super.getLinkReport();
+ }
+
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSKeyFrames.java b/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSKeyFrames.java
index abc1da1..4708e57 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSKeyFrames.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSKeyFrames.java
@@ -48,7 +48,8 @@
private final String id;
- @Override
+ @SuppressWarnings("incomplete-switch")
+ @Override
public String toString()
{
final StringBuilder result = new StringBuilder();
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSProperty.java b/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSProperty.java
index 9b3ddf1..0f4c0a2 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSProperty.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/css/CSSProperty.java
@@ -57,7 +57,7 @@
@Override
public String toString()
{
- if (rawName.equalsIgnoreCase("border"))
+ if (rawName.equalsIgnoreCase("border") && value instanceof CSSArrayPropertyValue)
{
CSSArrayPropertyValue borderValues = (CSSArrayPropertyValue)value;
return String.format("%s: %s;", rawName, Joiner.on(" ").join(borderValues.getElements()));
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/css/codegen/CSSCompilationSession.java b/compiler/src/main/java/org/apache/royale/compiler/internal/css/codegen/CSSCompilationSession.java
index a9599e5..09ff971 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/css/codegen/CSSCompilationSession.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/css/codegen/CSSCompilationSession.java
@@ -166,11 +166,6 @@
private boolean keepAllTypeSelectors;
/**
- * Excluded CSS files.
- */
- private List<String> excludedCSSFiles;
-
- /**
* Determine if a rule should be in the output
*
* @return true if rule should be in the output
@@ -421,14 +416,4 @@
this.keepAllTypeSelectors = keepAllTypeSelectors;
}
- /**
- * Set whether to keep all type selectors for linking.
- *
- * @param keepAllTypeSelectors value
- */
- public void setExcludeDefaultsCSSFiles(List<String> excludes)
- {
- this.excludedCSSFiles = excludes;
- }
-
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/css/semantics/CSSSemanticAnalyzer.java b/compiler/src/main/java/org/apache/royale/compiler/internal/css/semantics/CSSSemanticAnalyzer.java
index b0f1f91..6573c57 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/css/semantics/CSSSemanticAnalyzer.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/css/semantics/CSSSemanticAnalyzer.java
@@ -406,6 +406,13 @@
}
return false;
}
+
+ @Override
+ public boolean test(ICSSRule input)
+ {
+ return apply(input);
+ }
+
}
/**
@@ -447,6 +454,12 @@
}
return true;
}
+
+ @Override
+ public boolean test(ICSSRule input)
+ {
+ return apply(input);
+ }
}
/**
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/AmbiguousDefinition.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/AmbiguousDefinition.java
index b51b8c5..91e0d5e 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/AmbiguousDefinition.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/AmbiguousDefinition.java
@@ -95,10 +95,11 @@
*
* @param project The Project to use to resolve things
* @param defs an Array of definitions to compare
+ * @param favorTypes
* @return the definition to use as the result of the lookup, if the
* ambiguity was successfully resolved, otherwise null
*/
- public static IDefinition resolveAmbiguities(ICompilerProject project, List<IDefinition> defs)
+ public static IDefinition resolveAmbiguities(ICompilerProject project, List<IDefinition> defs, boolean favorTypes)
{
IDefinition resolvedDef = null;
@@ -111,6 +112,26 @@
resolvedDef = defs.get(0);
}
+ // this is used to favor type definitions over function definitions
+ // when resolving the type of a variable (which can't be a function)
+ if (resolvedDef == null && defs.size() == 2)
+ {
+ IDefinition def0 = defs.get(0);
+ IDefinition def1 = defs.get(1);
+ if (def0 instanceof FunctionDefinition &&
+ (def1 instanceof ClassDefinition ||
+ (def1 instanceof InterfaceDefinition)))
+ {
+ resolvedDef = favorTypes ? def1 : def0;
+ }
+ else if (def1 instanceof FunctionDefinition &&
+ (def0 instanceof ClassDefinition ||
+ (def0 instanceof InterfaceDefinition)))
+ {
+ resolvedDef = favorTypes ? def0 : def1;
+ }
+ }
+
if (resolvedDef == null)
{
// check for redeclared variables and functions
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
index eb59a7b..85a6900 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinition.java
@@ -39,6 +39,7 @@
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.constants.IMetaAttributeConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
+import org.apache.royale.compiler.definitions.IAccessorDefinition;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IEffectDefinition;
@@ -74,6 +75,7 @@
import org.apache.royale.compiler.problems.MissingSkinStateProblem;
import org.apache.royale.compiler.problems.OnlyOneHostComponentAllowedProblem;
import org.apache.royale.compiler.problems.SkinPartsMustBePublicProblem;
+import org.apache.royale.compiler.problems.UnimplementedAbstractMethodProblem;
import org.apache.royale.compiler.problems.WrongSkinPartProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.scopes.IASScope;
@@ -311,6 +313,16 @@
protected void setConstructor(IFunctionDefinition constructor)
{
this.constructor = constructor;
+
+ if(this.constructor.isPrivate()
+ && this.constructor.getMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR) == null)
+ {
+ // ensures that the constructor remains private when compiled into
+ // a library because the metadata is how private constructors are
+ // stored in the bytecode
+ MetaTag privateMetaTag = new MetaTag(this, IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR, new IMetaTagAttribute[0]);
+ addMetaTag(privateMetaTag);
+ }
}
@Override
@@ -756,20 +768,27 @@
{
Set<String> states = new HashSet<String>();
- // Iterate over this class and its superclasses.
- for (IClassDefinition c : classIterable(project, true))
+ // Iterate over the superclasses first, but don't worry about duplicates
+ // yet. The superclasses will find their own duplicates!
+ for (IClassDefinition c : classIterable(project, false))
{
for (String state : c.getSkinStates(problems))
{
- if (states.contains(state))
- {
- ICompilerProblem problem = new DuplicateSkinStateProblem(c, state);
- problems.add(problem);
- }
-
states.add(state);
}
}
+ // Then, add the states from this class and check for duplicates that
+ // specifically come from this class
+ for (String state : getSkinStates(problems))
+ {
+ if (states.contains(state))
+ {
+ ICompilerProblem problem = new DuplicateSkinStateProblem(this, state);
+ problems.add(problem);
+ }
+
+ states.add(state);
+ }
return states.toArray(new String[states.size()]);
}
@@ -1455,4 +1474,61 @@
// Some implicit class definition we have never seen before.
return false;
}
+
+ /**
+ * Method to find all the abstract methods declared in this class, and
+ * validate that the concrete class definition passed in implements those
+ * methods, and that they are implemented with compatible signatures
+ *
+ * @param cls the class definition to check
+ * @param problems a list of problems to report errors to
+ */
+ public void validateClassImplementsAllMethods(ICompilerProject project, ClassDefinition cls, Collection<ICompilerProblem> problems)
+ {
+ ASScope classScope = cls.getContainedScope();
+
+ for (IDefinitionSet defSet : this.getContainedScope().getAllLocalDefinitionSets())
+ {
+ for (int i = 0, l = defSet.getSize(); i < l; ++i)
+ {
+ IDefinition def = defSet.getDefinition(i);
+ if (def instanceof FunctionDefinition && !(def instanceof IAccessorDefinition))
+ {
+ FunctionDefinition abstractMethod = (FunctionDefinition)def;
+
+ // Skip any implicit methods added for CM compat
+ if (abstractMethod.isImplicit())
+ continue;
+
+ // Skip the constructor method of the interface.
+ if (abstractMethod.getBaseName().equals(getBaseName()))
+ continue;
+
+ // Skip methods that are static
+ if (abstractMethod.isStatic())
+ continue;
+
+ // Skip methods that aren't abstract
+ if (!abstractMethod.isAbstract())
+ continue;
+
+ INamespaceDefinition ns = abstractMethod.resolveNamespace(project);
+ if(ns instanceof INamespaceDefinition.IProtectedNamespaceDefinition)
+ {
+ ns = cls.getProtectedNamespaceReference();
+ }
+
+ IDefinition c = classScope.getQualifiedPropertyFromDef(project, cls, abstractMethod.getBaseName(), ns, false);
+ if (c == null || c.isAbstract())
+ {
+ // Error, didn't implement the method
+ problems.add(new UnimplementedAbstractMethodProblem(cls,
+ abstractMethod.getBaseName(),
+ this.getBaseName(),
+ cls.getBaseName()));
+ }
+ }
+ }
+ }
+ }
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
index fd595e7..2dcf3ed 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/ClassDefinitionBase.java
@@ -32,8 +32,10 @@
import org.apache.royale.compiler.definitions.IInterfaceDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
+import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.definitions.references.IReference;
import org.apache.royale.compiler.internal.as.codegen.BindableHelper;
+import org.apache.royale.compiler.internal.definitions.metadata.MetaTag;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.scopes.ASProjectScope;
import org.apache.royale.compiler.internal.scopes.ASScope;
@@ -427,7 +429,23 @@
if (type instanceof IClassDefinition)
{
- if (baseDefinitions == null)
+ if (!getPerformanceCachingEnabled())
+ {
+ baseDefinitions = null;
+
+ // We're trying to determine whether this class
+ // is derived from a specified class ('type').
+ // Iterate the superclass chain looking for 'type'.
+ Iterator<IClassDefinition> iter = classIterator(project, false);
+ while (iter.hasNext())
+ {
+ IClassDefinition cls = iter.next();
+ if (cls == type)
+ return true;
+ }
+ return false;
+ }
+ else if (baseDefinitions == null)
{
if ((CompilerDiagnosticsConstants.diagnostics & CompilerDiagnosticsConstants.CLASS_DEFINITION_BASE) == CompilerDiagnosticsConstants.CLASS_DEFINITION_BASE)
System.out.println("ClassDefinitionBase waiting for lock for " + this.getQualifiedName());
@@ -456,7 +474,24 @@
}
else if (type instanceof IInterfaceDefinition)
{
- if (implDefinitions == null)
+ if (!getPerformanceCachingEnabled())
+ {
+ implDefinitions = null;
+
+ // We're trying to determine whether this class
+ // implements a specified interface ('type').
+ // Iterate all of the interfaces that this class implements,
+ // looking for 'type'.
+ Iterator<IInterfaceDefinition> iter = interfaceIterator(project);
+ while (iter.hasNext())
+ {
+ IInterfaceDefinition intf = iter.next();
+ if (intf == type)
+ return true;
+ }
+ return false;
+ }
+ else if (implDefinitions == null)
{
if ((CompilerDiagnosticsConstants.diagnostics & CompilerDiagnosticsConstants.CLASS_DEFINITION_BASE) == CompilerDiagnosticsConstants.CLASS_DEFINITION_BASE)
System.out.println("ClassDefinitionBase waiting for lock for " + this.getQualifiedName());
@@ -503,6 +538,30 @@
return interfaces;
}
+ @Override
+ public boolean isAbstract()
+ {
+ if(super.isAbstract())
+ {
+ return true;
+ }
+ IMetaTag[] metaTags = getMetaTagsByName(IMetaAttributeConstants.ATTRIBUTE_ABSTRACT);
+ return metaTags != null && metaTags.length > 0;
+ }
+
+ /**
+ * Utility to mark a definition as abstract. This method should only ever be
+ * called during construction or initialization of a definition.
+ */
+ @Override
+ public void setAbstract()
+ {
+ super.setAbstract();
+
+ MetaTag abstractMetaTag = new MetaTag(this, IMetaAttributeConstants.ATTRIBUTE_ABSTRACT, new IMetaTagAttribute[0]);
+ addMetaTag(abstractMetaTag);
+ }
+
/*
* This inner class implements an iterator that enumerates all of this
* ClassDefinition's superclasses. <p> It will stop iterating when it
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
index de6bdbc..50a4951 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/DefinitionBase.java
@@ -108,6 +108,18 @@
protected static final short FLAG_DEPRECATED = 1 << 13;
protected static final short FLAG_DECLARED_IN_CONTROL_FLOW = 1 << 14;
+ private static boolean performanceCachingEnabled = false;
+
+ public static boolean getPerformanceCachingEnabled()
+ {
+ return performanceCachingEnabled;
+ }
+
+ public static void setPerformanceCachingEnabled(boolean enable)
+ {
+ performanceCachingEnabled = enable;
+ }
+
/**
* Constructor.
*
@@ -243,7 +255,7 @@
@Override
public IDefinition getParent()
{
- if (parentDef != null)
+ if (getPerformanceCachingEnabled() && parentDef != null)
return parentDef;
IASScope scope = getContainingScope();
@@ -257,8 +269,10 @@
while ((scope != null) && (scope.getDefinition() == null))
scope = scope.getContainingScope();
- parentDef = scope != null ? scope.getDefinition() : null;
- return parentDef;
+ IDefinition result = scope != null ? scope.getDefinition() : null;
+ if (getPerformanceCachingEnabled())
+ parentDef = result;
+ return result;
}
@Override
@@ -535,6 +549,12 @@
private static DefinitionBase getContainingToplevelDefinition(DefinitionBase definition)
{
ASScope currentContainingScope = definition.getContainingASScope();
+ if (currentContainingScope == null)
+ {
+ // With some synthetic definitions you can't find a containint top level definition.
+ // This happens with Vector<T>, for example. In this case, return null
+ return null;
+ }
DefinitionBase currentDefinition = definition;
IScopedDefinition containingDefinition = currentContainingScope.getContainingDefinition();
@@ -543,10 +563,11 @@
currentDefinition = (DefinitionBase)containingDefinition;
currentContainingScope = currentDefinition.getContainingASScope();
- // With some synthetic definitions you can't find a containint top level definition.
- // This happens with Vector<T>, for example. In this case, return null
if (currentContainingScope == null)
- return null;
+ {
+ // See comment above
+ return null;
+ }
containingDefinition = currentContainingScope.getContainingDefinition();
}
@@ -687,6 +708,21 @@
flags |= FLAG_STATIC;
}
+ // instead of increasing the size of "flags" from a short to int, I added
+ // a boolean variable instead. feel free to change this, if desired. -JT
+ private boolean abstractFlag = false;
+
+ @Override
+ public boolean isAbstract()
+ {
+ return abstractFlag;
+ }
+
+ public void setAbstract()
+ {
+ abstractFlag = true;
+ }
+
@Override
public boolean hasModifier(ASModifier modifier)
{
@@ -717,6 +753,10 @@
// Ignore "virtual" modifier.
return false;
}
+ else if (modifier == ASModifier.ABSTRACT)
+ {
+ return abstractFlag;
+ }
else
{
assert false : "Unknown modifier: " + modifier;
@@ -738,6 +778,8 @@
result.addModifier(ASModifier.DYNAMIC);
if ((flags & FLAG_NATIVE) != 0)
result.addModifier(ASModifier.NATIVE);
+ if (abstractFlag)
+ result.addModifier(ASModifier.ABSTRACT);
return result;
}
@@ -760,6 +802,9 @@
else if (modifier == ASModifier.NATIVE)
flags |= FLAG_NATIVE;
+ else if (modifier == ASModifier.ABSTRACT)
+ setAbstract();
+
else
assert false;
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
index fdcbf80..9f0e546 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/FunctionDefinition.java
@@ -41,9 +41,10 @@
import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.references.INamespaceReference;
import org.apache.royale.compiler.definitions.metadata.IMetaTag;
+import org.apache.royale.compiler.definitions.metadata.IMetaTagAttribute;
import org.apache.royale.compiler.definitions.references.IReference;
+import org.apache.royale.compiler.internal.definitions.metadata.MetaTag;
import org.apache.royale.compiler.internal.projects.CompilerProject;
-import org.apache.royale.compiler.problems.AmbiguousReferenceProblem;
import org.apache.royale.compiler.problems.ConflictingDefinitionProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.scopes.IASScope;
@@ -271,6 +272,53 @@
}
@Override
+ public boolean isAbstract()
+ {
+ if(super.isAbstract())
+ {
+ return true;
+ }
+ IMetaTag[] metaTags = getMetaTagsByName(IMetaAttributeConstants.ATTRIBUTE_ABSTRACT);
+ return metaTags != null && metaTags.length > 0;
+ }
+
+ /**
+ * Utility to mark a definition as abstract. This method should only ever be
+ * called during construction or initialization of a definition.
+ */
+ @Override
+ public void setAbstract()
+ {
+ super.setAbstract();
+
+ MetaTag abstractMetaTag = new MetaTag(this, IMetaAttributeConstants.ATTRIBUTE_ABSTRACT, new IMetaTagAttribute[0]);
+ addMetaTag(abstractMetaTag);
+ }
+
+ @Override
+ public boolean isPrivate()
+ {
+ if (super.isPrivate())
+ {
+ return true;
+ }
+ if (isConstructor())
+ {
+ IDefinition parent = getParent();
+ if (parent == null)
+ {
+ return false;
+ }
+ // if the construcutor does not have a private namespace, the parent
+ // class may have [RoyalePrivateConstructor] metadata instead. this
+ // is how private constructors are stored in bytecode.
+ IMetaTag[] metaTags = parent.getMetaTagsByName(IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR);
+ return metaTags != null && metaTags.length > 0;
+ }
+ return false;
+ }
+
+ @Override
public boolean overridesAncestor(ICompilerProject project)
{
return (resolveOverriddenFunction(project) != null);
@@ -652,6 +700,12 @@
if (!definition.isPrivate()) return true;
return findPrivates;
}
+
+ @Override
+ public boolean test(IDefinition input)
+ {
+ return apply(input);
+ }
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/NamespaceDefinition.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/NamespaceDefinition.java
index fc1fd10..bbdef2e 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/NamespaceDefinition.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/NamespaceDefinition.java
@@ -46,7 +46,6 @@
import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.IPackageDefinition;
-import org.apache.royale.compiler.definitions.references.INamespaceReference;
import org.apache.royale.compiler.definitions.references.INamespaceResolvedReference;
import org.apache.royale.compiler.filespecs.IFileSpecification;
import org.apache.royale.compiler.internal.projects.CompilerProject;
@@ -1948,6 +1947,12 @@
}
return true;
}
+
+ @Override
+ public boolean test(IDefinition input)
+ {
+ return apply(input);
+ }
/**
* Determine if a reference from one definition to another should be considered a forward
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
index d0bd2cd..a465894 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VariableDefinition.java
@@ -221,7 +221,8 @@
return initializer;
}
- public void setInitializer(IExpressionNode initExpr)
+ @SuppressWarnings("incomplete-switch")
+ public void setInitializer(IExpressionNode initExpr)
{
if( initExpr != null )
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VectorInformation.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VectorInformation.java
index d83b27a..1310790 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VectorInformation.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/VectorInformation.java
@@ -198,14 +198,14 @@
//add the fixed getter/setter pair
GetterNode fixGetter = new GetterNode(null, null, new IdentifierNode("fixed"));
NamespaceIdentifierNode pub = new NamespaceIdentifierNode(INamespaceConstants.public_);
- pub.span(-1, -1, -1, -1);
+ pub.span(-1, -1, -1, -1, -1, -1);
fixGetter.setNamespace(pub);
fixGetter.setType(null, new IdentifierNode(IASLanguageConstants.Boolean));
retVal[2] = fixGetter;
SetterNode fixSetter = new SetterNode(null, null, new IdentifierNode("fixed"));
pub = new NamespaceIdentifierNode(INamespaceConstants.public_);
- pub.span(-1, -1, -1, -1);
+ pub.span(-1, -1, -1, -1, -1, -1);
fixSetter.setNamespace(pub);
fixSetter.setType(null, new IdentifierNode(IASLanguageConstants.void_));
ParameterNode value = new ParameterNode(new IdentifierNode("value"));
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/references/ResolvedQualifiersReference.java b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/references/ResolvedQualifiersReference.java
index 1561d13..bf2ac97 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/references/ResolvedQualifiersReference.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/definitions/references/ResolvedQualifiersReference.java
@@ -128,7 +128,7 @@
}
default:
{
- IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs);
+ IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs, false);
if (d == null)
return AmbiguousDefinition.get();
return d;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/EmbedData.java b/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/EmbedData.java
index 404c693..544133c 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/EmbedData.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/EmbedData.java
@@ -47,7 +47,6 @@
import org.apache.royale.compiler.internal.embedding.transcoders.SoundTranscoder;
import org.apache.royale.compiler.internal.embedding.transcoders.TranscoderBase;
import org.apache.royale.compiler.internal.embedding.transcoders.XMLTranscoder;
-import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.ASProject;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.projects.SourcePathManager;
@@ -63,6 +62,7 @@
import org.apache.royale.compiler.problems.EmbedUnrecogniedFileTypeProblem;
import org.apache.royale.compiler.problems.FontEmbeddingNotSupported;
import org.apache.royale.compiler.problems.ICompilerProblem;
+import org.apache.royale.compiler.projects.IASProject;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.swc.ISWCFileEntry;
@@ -143,6 +143,7 @@
private ISWCFileEntry swcSource;
@SuppressWarnings("unused")
private SkinClassInfo skinClassInfo;
+ private ICompilerProject project;
/**
* Add an attribute
@@ -156,6 +157,7 @@
*/
public boolean addAttribute(ICompilerProject project, ISourceLocation location, String key, String value, Collection<ICompilerProblem> problems)
{
+ this.project = project;
boolean hadError = false;
try
{
@@ -346,6 +348,7 @@
}
else if (EmbedAttribute.ADV_ANTI_ALIASING.equals(key) ||
EmbedAttribute.EMBED_AS_CFF.equals(key) ||
+ EmbedAttribute.UNICODE_RANGE.equals(key) ||
EmbedAttribute.FONT_FAMILY.equals(key) ||
EmbedAttribute.FONT_NAME.equals(key) ||
EmbedAttribute.FONT_STYLE.equals(key) ||
@@ -405,6 +408,18 @@
problems.add(new EmbedNoSourceAttributeProblem(location));
return false;
}
+ String uniqueName = source;
+ List<File> sourcePaths = ((IASProject)project).getSourcePath();
+ for (File sourcePath : sourcePaths)
+ {
+ String sourcePathString = sourcePath.getAbsolutePath();
+ if (source.startsWith(sourcePathString))
+ {
+ uniqueName = source.substring(sourcePathString.length());
+ uniqueName = uniqueName.replace("\\", "/");
+ break;
+ }
+ }
// also check that we have a mimetype set, as don't know what transcoder
// to create without it!
@@ -488,6 +503,8 @@
if (transcoder == null)
return false;
+ transcoder.hashCodeSourceName = uniqueName;
+
// there were problems with the transcoder because of attribute settings
// so don't return it, and let the user deal with the errors
if (!transcoder.analyze(location, problems))
@@ -518,10 +535,25 @@
source = swcSource.getContainingSWCPath().concat(source);
}
+ String uniqueName = source;
+ List<File> sourcePaths = ((IASProject)project).getSourcePath();
+ for (File sourcePath : sourcePaths)
+ {
+ String sourcePathString = sourcePath.getAbsolutePath();
+ if (source.startsWith(sourcePathString))
+ {
+ uniqueName = source.substring(sourcePathString.length());
+ uniqueName = uniqueName.replace("\\", "/");
+ break;
+ }
+ }
String filename = FilenameUtils.getName(source);
filename = filename.replace(".", "_");
- String qname = filename + "$" + StringEncoder.stringToMD5String(source);
-
+ String qname = filename + "$" + StringEncoder.stringToMD5String(uniqueName);
+ transcoder.hashCodeSourceName = uniqueName;
+// System.out.println("Embed UniqueName: " + uniqueName);
+// System.out.println("Embed QName: " + qname);
+
// add the transcoder hashCode to the end of the QName to ensure
// two embed data's with the same source, but different attributes
// don't clash
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/MovieTranscoder.java b/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/MovieTranscoder.java
index 928d192..dde0e8f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/MovieTranscoder.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/MovieTranscoder.java
@@ -27,7 +27,6 @@
import java.util.Map;
import java.util.Set;
-import org.apache.royale.compiler.caches.ISWFCache;
import org.apache.royale.compiler.common.ISourceLocation;
import org.apache.royale.compiler.constants.IASKeywordConstants;
import org.apache.royale.compiler.constants.INamespaceConstants;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/TranscoderBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/TranscoderBase.java
index caf7a81..60fa370 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/TranscoderBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/embedding/transcoders/TranscoderBase.java
@@ -79,6 +79,7 @@
protected String baseClassQName;
protected String source;
private EmbedMIMEType mimeType;
+ public String hashCodeSourceName;
/**
* Transcode the embedded asset
@@ -354,7 +355,7 @@
public int hashCode()
{
int hashCode = 0;
- hashCode = source.hashCode();
+ hashCode = hashCodeSourceName.hashCode();
hashCode ^= baseClassQName.hashCode();
hashCode ^= mimeType.toString().hashCode(); // the toString() gives us a reproducible hash code
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/SWCFileSpecification.java b/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/SWCFileSpecification.java
index 3e4939f..10b78c9 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/SWCFileSpecification.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/SWCFileSpecification.java
@@ -139,4 +139,10 @@
return new BufferedReader(new InputStreamReader(bufferedStrm, bom.charset));
}
+
+ @Override
+ public void setLastModified(long fileDate) {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/StringFileSpecification.java b/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/StringFileSpecification.java
index 243d2fe..01f2383 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/StringFileSpecification.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/StringFileSpecification.java
@@ -77,4 +77,10 @@
return false;
}
+ @Override
+ public void setLastModified(long fileDate) {
+ // TODO Auto-generated method stub
+
+ }
+
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/ZipFileSpecification.java b/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/ZipFileSpecification.java
index b9d4b5b..4bfd6ab 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/ZipFileSpecification.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/filespecs/ZipFileSpecification.java
@@ -123,4 +123,10 @@
{
return false;
}
+
+ @Override
+ public void setLastModified(long fileDate) {
+ // TODO Auto-generated method stub
+
+ }
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/mxml/MXMLTextData.java b/compiler/src/main/java/org/apache/royale/compiler/internal/mxml/MXMLTextData.java
index 0fa93d6..4e3c61f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/mxml/MXMLTextData.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/mxml/MXMLTextData.java
@@ -293,7 +293,8 @@
/**
* @return The start offset of actual content
*/
- public int getContentsStart()
+ @SuppressWarnings("incomplete-switch")
+ public int getContentsStart()
{
switch (type)
{
@@ -313,7 +314,8 @@
/**
* @return The end offset of content
*/
- public int getContentsEnd()
+ @SuppressWarnings("incomplete-switch")
+ public int getContentsEnd()
{
switch (type)
{
@@ -335,7 +337,8 @@
return getLine();
}
- public int getContentsColumn()
+ @SuppressWarnings("incomplete-switch")
+ public int getContentsColumn()
{
switch (type)
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
index 52f2040..fa8b149 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ASToken.java
@@ -463,6 +463,7 @@
case TOKEN_MODIFIER_NATIVE:
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
+ case TOKEN_MODIFIER_ABSTRACT:
return true;
}
return false;
@@ -514,6 +515,7 @@
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
case TOKEN_RESERVED_WORD_GET:
case TOKEN_RESERVED_WORD_SET:
case TOKEN_RESERVED_WORD_NAMESPACE:
@@ -655,6 +657,7 @@
case TOKEN_MODIFIER_NATIVE:
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
+ case TOKEN_MODIFIER_ABSTRACT:
return true;
}
return false;
@@ -918,6 +921,7 @@
case TOKEN_MODIFIER_NATIVE:
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
+ case TOKEN_MODIFIER_ABSTRACT:
return ASTokenKind.MODIFIER;
case HIDDEN_TOKEN_BUILTIN_NS:
case TOKEN_NAMESPACE_ANNOTATION:
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
index a8c3d7f..62bdaee 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/BaseASParser.java
@@ -1520,7 +1520,18 @@
(NamespaceIdentifierNode)left,
(ASToken)op,
(IdentifierNode)right);
- result = (ExpressionNodeBase) evaluateConstNodeExpression(cn);
+ IASNode possibleResult = evaluateConstNodeExpression(cn);
+ //it's possible for evaluateConstNodeExpression() to return null
+ //if that happens, fall back to the same behavior as the final
+ //else to avoid a null reference exception -JT
+ if (possibleResult != null)
+ {
+ result = (ExpressionNodeBase) possibleResult;
+ }
+ else
+ {
+ result = new NamespaceAccessExpressionNode(left, op, right);
+ }
}
else
{
@@ -1562,7 +1573,7 @@
}
else
{
- block.span(blockToken.getStart() + 1, blockToken.getStart() + 1, blockToken.getLine(), blockToken.getColumn());
+ block.span(blockToken.getStart() + 1, blockToken.getStart() + 1, blockToken.getLine(), blockToken.getColumn(), blockToken.getLine(), blockToken.getColumn());
}
}
@@ -2329,7 +2340,7 @@
}
private static final ImmutableSet<String> CONTEXTUAL_RESERVED_KEYWORD_MODIFIERS =
- ImmutableSet.of("dynamic", "final", "native", "static", "override");
+ ImmutableSet.of("dynamic", "final", "native", "static", "override", "abstract");
/**
* Recover from {@link CanNotInsertSemicolonProblem} after an expression
@@ -2854,6 +2865,7 @@
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
return true;
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
index 3d30c7d..89fcd51 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/ConfigProcessor.java
@@ -52,7 +52,6 @@
import org.apache.royale.compiler.internal.tree.as.NumericLiteralNode;
import org.apache.royale.compiler.internal.tree.as.ScopedBlockNode;
import org.apache.royale.compiler.internal.workspaces.Workspace;
-import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.problems.CannotResolveConfigExpressionProblem;
import org.apache.royale.compiler.problems.CannotResolveProjectLevelConfigExpressionProblem;
import org.apache.royale.compiler.problems.ConflictingNameInNamespaceProblem;
@@ -159,6 +158,24 @@
// TODO Auto-generated method stub
return false;
}
+
+ @Override
+ public boolean getAllowImportAliases() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getAllowAbstractClasses() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getAllowPrivateConstructors() {
+ // TODO Auto-generated method stub
+ return false;
+ }
}
/**
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
index 2cb8e99..32017a4 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/as/StreamingASTokenizer.java
@@ -101,6 +101,7 @@
.put(IASKeywordConstants.OVERRIDE, TOKEN_MODIFIER_OVERRIDE)
.put(IASKeywordConstants.STATIC, TOKEN_MODIFIER_STATIC)
.put(IASKeywordConstants.VIRTUAL, TOKEN_MODIFIER_VIRTUAL)
+ .put(IASKeywordConstants.ABSTRACT, TOKEN_MODIFIER_ABSTRACT)
.put(IASKeywordConstants.SET, TOKEN_RESERVED_WORD_SET)
// Keywords with special token types that affect subsequent blocks
.put(IASKeywordConstants.CATCH, TOKEN_KEYWORD_CATCH)
@@ -917,6 +918,7 @@
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
{
// previous token is either a modifier or a namespace, or if
// null, assume keyword
@@ -938,6 +940,7 @@
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
case TOKEN_NAMESPACE_ANNOTATION:
case TOKEN_NAMESPACE_NAME:
case HIDDEN_TOKEN_BUILTIN_NS:
@@ -1773,6 +1776,7 @@
case TOKEN_MODIFIER_OVERRIDE:
case TOKEN_MODIFIER_STATIC:
case TOKEN_MODIFIER_VIRTUAL:
+ case TOKEN_MODIFIER_ABSTRACT:
case TOKEN_KEYWORD_CLASS:
case TOKEN_KEYWORD_INTERFACE:
case TOKEN_NAMESPACE_ANNOTATION:
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
index f6b78fa..f542cf3 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/ASCProject.java
@@ -80,4 +80,22 @@
// TODO Auto-generated method stub
return false;
}
+
+ @Override
+ public boolean getAllowImportAliases() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getAllowAbstractClasses() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean getAllowPrivateConstructors() {
+ // TODO Auto-generated method stub
+ return false;
+ }
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/CompilerProject.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/CompilerProject.java
index 88b42e6..397bb6b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/CompilerProject.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/CompilerProject.java
@@ -847,7 +847,8 @@
return fatalProblems == null ? Collections.<ICompilerProblem>emptyList() : fatalProblems;
}
- @Override
+ @SuppressWarnings("incomplete-switch")
+ @Override
public ITypeDefinition getBuiltinType(IASLanguageConstants.BuiltinType type)
{
switch( type )
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/DependencyGraph.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/DependencyGraph.java
index a7fa031..86ae45b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/DependencyGraph.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/DependencyGraph.java
@@ -33,6 +33,7 @@
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.common.DependencyTypeSet;
+import org.apache.royale.compiler.config.CompilerDiagnosticsConstants;
import org.apache.royale.compiler.exceptions.CircularDependencyException;
import org.apache.royale.compiler.internal.graph.Graph;
import org.apache.royale.compiler.internal.graph.GraphEdge;
@@ -43,6 +44,7 @@
import org.apache.royale.compiler.units.ICompilationUnit;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
/**
* Class to track dependencies in a {@link CompilerProject}.
@@ -498,6 +500,8 @@
}
});
}
+
+ public CircularDependencyException lastCircularDependencyException;
/**
* Computes the list of all {@link ICompilationUnit}'s that the specified
@@ -520,6 +524,7 @@
lock.readLock().lock();
try
{
+ lastCircularDependencyException = null;
final ArrayList<ICompilationUnit> sortedList = new ArrayList<ICompilationUnit>(graph.getVertices().size());
TopologicalSort.IVisitor<ICompilationUnit, Edge> visitor =
new TopologicalSort.IVisitor<ICompilationUnit, Edge>()
@@ -549,6 +554,23 @@
}
catch (CircularDependencyException e1)
{
+ if ((CompilerDiagnosticsConstants.diagnostics & CompilerDiagnosticsConstants.GOOG_DEPS) == CompilerDiagnosticsConstants.GOOG_DEPS)
+ {
+ System.out.println("Circular Dependency Found");
+ @SuppressWarnings("unchecked")
+ ImmutableList<ICompilationUnit> nodes = (ImmutableList<ICompilationUnit>) e1.getCircularDependency();
+ for (ICompilationUnit node : nodes)
+ {
+ try {
+ System.out.println(node.getQualifiedNames().toString());
+ } catch (InterruptedException e2) {
+ // TODO Auto-generated catch block
+ e2.printStackTrace();
+ }
+ }
+ System.out.println("End of Circular Dependency");
+ }
+ lastCircularDependencyException = e1;
assert false : "CircularDependencyException";
}
return sortedList;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/LibraryPathManager.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/LibraryPathManager.java
index c9e7550..17ef23d 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/LibraryPathManager.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/LibraryPathManager.java
@@ -470,7 +470,8 @@
* @param swcFilesToRemove SWC file paths
* @return compilation units associated with the SWC files
*/
- private List<ICompilationUnit> computeUnitsToRemove(final Collection<String> swcFilesToRemove)
+ @SuppressWarnings("incomplete-switch")
+ private List<ICompilationUnit> computeUnitsToRemove(final Collection<String> swcFilesToRemove)
{
final List<ICompilationUnit> unitsToRemove;
unitsToRemove = new ArrayList<ICompilationUnit>();
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
index e787d6c..e2a63e5 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProject.java
@@ -380,6 +380,7 @@
private String objectProxyClass;
private String xmlWatcherClass;
private Name xmlWatcherClassName;
+ private String swfDebugfileAlias;
/**
* The fully-qualified name of the runtime class
@@ -2348,27 +2349,50 @@
{
if (meta.getTagName().equals(IMetaAttributeConstants.ATTRIBUTE_SWFOVERRIDE))
{
- IMetaTagAttribute attr = meta.getAttribute(IMetaAttributeConstants.NAME_SWFOVERRIDE_ALTPARAMS);
- if (attr != null)
+ IMetaTagAttribute altattr = meta.getAttribute(IMetaAttributeConstants.NAME_SWFOVERRIDE_ALTPARAMS);
+ if (altattr != null)
{
- // format is expectedQName:allowedQName,expectedQName:allowedQName.
- // we don't know which parameter it is so we're assuming for now that any mapping
- // applies to all occurences of that type in the parameter list
- String paramList = attr.getValue();
- String[] paramMap;
- if (paramList.contains(","))
- paramMap = paramList.split(",");
+ String altparamList = altattr.getValue();
+ String[] altparamMap;
+ if (altparamList.contains(","))
+ altparamMap = altparamList.split(",");
else
{
- paramMap = new String[1];
- paramMap[0] = paramList;
+ altparamMap = new String[1];
+ altparamMap[0] = altparamList;
}
- for (String item : paramMap)
+ IMetaTagAttribute attr = meta.getAttribute(IMetaAttributeConstants.NAME_SWFOVERRIDE_PARAMS);
+ if (attr != null)
{
- String[] parts = item.split(":");
- if (expectedDefinition.getQualifiedName().equals(parts[0]))
- if (((ITypeDefinition)actualDefinition).isInstanceOf(parts[1], this))
- return true;
+ String paramList = attr.getValue();
+ String[] paramMap;
+ if (paramList.contains(","))
+ paramMap = paramList.split(",");
+ else
+ {
+ paramMap = new String[1];
+ paramMap[0] = paramList;
+ }
+ int n = paramMap.length;
+ for (int i = 0; i < n; i++)
+ {
+ String item = paramMap[i];
+ if (((ITypeDefinition)expectedDefinition).isInstanceOf(item, this))
+ {
+ String alts = altparamMap[i];
+ String[] altList;
+ if (alts.contains(":"))
+ altList = alts.split(":");
+ else
+ {
+ altList = new String[1];
+ altList[0] = alts;
+ }
+ for (String alt : altList)
+ if (((ITypeDefinition)actualDefinition).isInstanceOf(alt, this))
+ return true;
+ }
+ }
}
}
}
@@ -2430,6 +2454,51 @@
allowPrivateNameConflicts = allow;
}
+ private boolean allowImportAliases = false;
+
+ /**
+ * Indicates if import aliases are allowed.
+ */
+ @Override
+ public boolean getAllowImportAliases()
+ {
+ return allowImportAliases;
+ }
+ public void setAllowImportAliases(boolean allow)
+ {
+ allowImportAliases = allow;
+ }
+
+ private boolean allowAbstractClasses = false;
+
+ /**
+ * Indicates if abstract classes are allowed.
+ */
+ @Override
+ public boolean getAllowAbstractClasses()
+ {
+ return allowAbstractClasses;
+ }
+ public void setAllowAbstractClasses(boolean allow)
+ {
+ allowAbstractClasses = allow;
+ }
+
+ private boolean allowPrivateConstructors = false;
+
+ /**
+ * Indicates if private constructors are allowed.
+ */
+ @Override
+ public boolean getAllowPrivateConstructors()
+ {
+ return allowPrivateConstructors;
+ }
+ public void setAllowPrivateConstructors(boolean allow)
+ {
+ allowPrivateConstructors = allow;
+ }
+
@Override
public boolean isPlatformRule(ICSSRule rule) {
return true;
@@ -2520,4 +2589,19 @@
return false;
}
+ @Override
+ public File getLinkReport(Configuration config) {
+ return config.getLinkReport();
+ }
+
+ public String getSwfDebugfileAlias()
+ {
+ return swfDebugfileAlias;
+ }
+
+ public void setSwfDebugfileAlias(String swfDebugfileAlias)
+ {
+ this.swfDebugfileAlias = swfDebugfileAlias;
+ }
+
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
index df8d4fa..ef8c367 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/RoyaleProjectConfigurator.java
@@ -30,6 +30,7 @@
import org.apache.royale.abc.semantics.Nsset;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.config.Configurator;
+import org.apache.royale.compiler.filespecs.FileSpecification;
import org.apache.royale.compiler.fxg.flex.FlexFXG2SWFTranscoder;
import org.apache.royale.compiler.internal.as.codegen.BindableHelper;
import org.apache.royale.compiler.internal.config.RoyaleTargetSettings;
@@ -262,7 +263,14 @@
project.setStrictXML(configuration.isStrictXML());
project.setAllowPrivateNameConflicts(configuration.getCompilerAllowPrivateNameConflicts());
+
+ project.setAllowImportAliases(configuration.getCompilerAllowImportAliases());
+ project.setAllowAbstractClasses(configuration.getCompilerAllowAbstractClasses());
+ project.setAllowPrivateConstructors(configuration.getCompilerAllowPrivateConstructors());
+ project.setSwfDebugfileAlias(configuration.getSwfDebugfileAlias());
+ if (configuration.getSwfDebugfileAlias() != null)
+ FileSpecification.useCRLFFilter = true;
DataTranscoder.embedClassName = configuration.getByteArrayEmbedClass();
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/SourcePathManager.java b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/SourcePathManager.java
index 366cab1..da6b74f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/projects/SourcePathManager.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/projects/SourcePathManager.java
@@ -256,7 +256,13 @@
{
DefinitionPriority defPriority = (DefinitionPriority)cu.getDefinitionPriority();
return defPriority.getBasePriority() == DefinitionPriority.BasePriority.SOURCE_PATH;
- }});
+ }
+ @Override
+ public boolean test(ICompilationUnit input)
+ {
+ return apply(input);
+ }
+ });
unitsToRemove.addAll(sourcePathCompilationUnitsToRemove);
}
}
@@ -335,6 +341,11 @@
DefinitionPriority priority = ((DefinitionPriority)compilationUnit.getDefinitionPriority());
return priority.getBasePriority() == DefinitionPriority.BasePriority.SOURCE_PATH;
}
+ @Override
+ public boolean test(ICompilationUnit input)
+ {
+ return apply(input);
+ }
});
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
index 434a2d9..b229304 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScope.java
@@ -1425,7 +1425,7 @@
assert baseName.indexOf('.') == -1 : "baseName must not be any sort of qname";
CompilerProject compilerProject = (CompilerProject)project;
ASScopeCache scopeCache = compilerProject.getCacheForScope(this);
- return filterWith(scopeCache.findProperty(baseName, dt), canEscapeWith);
+ return filterWith(scopeCache.findProperty(baseName, dt, canEscapeWith), canEscapeWith);
}
/**
@@ -1487,7 +1487,7 @@
assert def.isInProject(project);
break;
default:
- IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs);
+ IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs, false);
if (d != null)
def = d;
else
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScopeCache.java b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScopeCache.java
index fb43722..d3dff76 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScopeCache.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/ASScopeCache.java
@@ -25,6 +25,7 @@
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IInterfaceDefinition;
import org.apache.royale.compiler.definitions.INamespaceDefinition;
+import org.apache.royale.compiler.definitions.ITypeDefinition;
import org.apache.royale.compiler.definitions.references.IResolvedQualifiersReference;
import org.apache.royale.compiler.internal.definitions.AmbiguousDefinition;
import org.apache.royale.compiler.internal.definitions.ClassDefinitionBase;
@@ -32,6 +33,7 @@
import org.apache.royale.compiler.internal.definitions.TypeDefinitionBase;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.units.ICompilationUnit;
import com.google.common.collect.MapMaker;
@@ -131,15 +133,27 @@
* @param dt Which type of dependency to introduce when we do the lookup
* @return The IDefinition for the property, or null if it wasn't found
*/
- IDefinition findProperty(String name, DependencyType dt)
+ IDefinition findProperty(String name, DependencyType dt, boolean favorTypes)
{
ConcurrentMap<String, IDefinition> map = getScopeChainMap();
IDefinition result = map.get(name);
if (result != null)
{
- assert result.isInProject(project);
// We found a cached result - we're done
+ // after making sure it has a dependency
+ if (result instanceof ITypeDefinition)
+ {
+ ICompilationUnit from = scope.getFileScope().getCompilationUnit();
+ assert result.isInProject(project);
+
+ String qname = result.getQualifiedName();
+ ICompilationUnit to = ((ASProjectScope)project.getScope()).getCompilationUnitForDefinition(result);
+ if (to == null && !(qname.contentEquals("void") || qname.contentEquals("*")))
+ System.out.println("No compilation unit for " + qname);
+ if (to != null)
+ project.addDependency(from, to, dt, qname);
+ }
return result;
}
@@ -148,6 +162,7 @@
// the benefit is that we avoid any sort of locking, which was proving expensive (time wise,
// and memory wise).
+ boolean wasAmbiguous = false;
IDefinition def = null;
Set<INamespaceDefinition> namespaceSet = scope.getNamespaceSetForName(project, name);
// Look for the definition in the scope
@@ -164,7 +179,8 @@
assert def.isInProject(project);
break;
default:
- IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs);
+ wasAmbiguous = true;
+ IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs, favorTypes);
if (d != null)
def = d;
else {
@@ -186,7 +202,7 @@
// If the dependency type is null we can't cache the name
// resolution result, because the name resolution cache will not
// be properly invalidated when the file containing the definition changes.
- if (dt != null)
+ if (dt != null && !wasAmbiguous)
{
result = map.putIfAbsent(name, def);
if (result == null)
@@ -294,7 +310,7 @@
break;
default:
- IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs);
+ IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs, false);
if (d != null)
def = d;
else
@@ -361,7 +377,7 @@
assert def.isInProject(project);
break;
default:
- IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs);
+ IDefinition d = AmbiguousDefinition.resolveAmbiguities(project, defs, false);
if (d != null)
def = d;
else
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/NamespaceSetPredicate.java b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/NamespaceSetPredicate.java
index c2684eb..44e775a 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/NamespaceSetPredicate.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/NamespaceSetPredicate.java
@@ -88,6 +88,12 @@
return false;
}
+ @Override
+ public boolean test(IDefinition input)
+ {
+ return apply(input);
+ }
+
/**
* Does the underlying namespace set contain the namespace passed in
* @param d the namespace to check
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/TypeScope.java b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/TypeScope.java
index 07ff53d..2a2a40b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/TypeScope.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/scopes/TypeScope.java
@@ -662,5 +662,11 @@
{
return findStatics == definition.isStatic();
}
+
+ @Override
+ public boolean test(IDefinition input)
+ {
+ return apply(input);
+ }
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
index 6663afc..c455528 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/MethodBodySemanticChecker.java
@@ -70,6 +70,8 @@
import org.apache.royale.compiler.internal.definitions.VariableDefinition;
import org.apache.royale.compiler.problems.*;
import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.scopes.IASScope;
+import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IBinaryOperatorNode;
import org.apache.royale.compiler.tree.as.ICompoundAssignmentNode;
@@ -84,6 +86,8 @@
import org.apache.royale.compiler.tree.as.INumericLiteralNode;
import org.apache.royale.compiler.tree.as.IParameterNode;
import org.apache.royale.compiler.tree.as.IReturnNode;
+import org.apache.royale.compiler.tree.as.IScopedNode;
+import org.apache.royale.compiler.tree.as.ITypedExpressionNode;
import org.apache.royale.compiler.tree.as.IUnaryOperatorNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
import org.apache.royale.compiler.internal.as.codegen.ABCGeneratingReducer;
@@ -390,18 +394,18 @@
if (!SemanticUtils.isValidTypeConversion(expected_type, actual_type, project, currentScope.getInInvisibleCompilationUnit()))
{
- addProblem(new ImplicitTypeCheckCoercionToUnrelatedTypeProblem(iNode, actual_type.getBaseName(), expected_type.getBaseName()));
+ addProblem(new ImplicitTypeCheckCoercionToUnrelatedTypeProblem(iNode, actual_type.getQualifiedName(), expected_type.getQualifiedName()));
}
else
{
SpecialValue value = getSpecialValue((IExpressionNode)iNode);
if (value == SpecialValue.UNDEFINED) // test for undefined
{
- addProblem(new ImplicitTypeCheckCoercionToUnrelatedTypeProblem(iNode, IASLanguageConstants.UNDEFINED, expected_type.getBaseName()));
+ addProblem(new ImplicitTypeCheckCoercionToUnrelatedTypeProblem(iNode, IASLanguageConstants.UNDEFINED, expected_type.getQualifiedName()));
}
else if (iNode instanceof LiteralNode && IASKeywordConstants.NULL.equals(((LiteralNode)iNode).getValue())) // test for null
{
- addProblem(new ImplicitTypeCheckCoercionToUnrelatedTypeProblem(iNode, IASKeywordConstants.NULL, expected_type.getBaseName()));
+ addProblem(new ImplicitTypeCheckCoercionToUnrelatedTypeProblem(iNode, IASKeywordConstants.NULL, expected_type.getQualifiedName()));
}
}
}
@@ -570,11 +574,11 @@
{
if ( utils.isInstanceOf(expected_type, actual_type) )
{
- addProblem(new ImplicitCoercionToSubtypeProblem(iNode, actual_type.getBaseName(), expected_type.getBaseName()));
+ addProblem(new ImplicitCoercionToSubtypeProblem(iNode, actual_type.getQualifiedName(), expected_type.getQualifiedName()));
}
else
{
- addProblem(new ImplicitCoercionToUnrelatedTypeProblem(iNode, actual_type.getBaseName(), expected_type.getBaseName()));
+ addProblem(new ImplicitCoercionToUnrelatedTypeProblem(iNode, actual_type.getQualifiedName(), expected_type.getQualifiedName()));
}
}
}
@@ -785,9 +789,26 @@
{
FunctionNode func = (FunctionNode)iNode;
+ if (SemanticUtils.isFunctionClosure(func))
+ {
+ for (IASNode thisNode : findThisIdentifierNodes(func))
+ {
+ addProblem(new ThisUsedInClosureProblem(thisNode));
+ }
+ }
+
IDefinition def = func.getDefinition();
- if ( !( def.hasModifier(ASModifier.NATIVE ) || def.hasModifier(ASModifier.DYNAMIC) || func.isConstructor() ) )
+ if ( project.getAllowAbstractClasses()
+ && def.isAbstract()
+ && SemanticUtils.canBeAbstract(iNode, currentScope.getProject()))
+ {
+ if ( func.hasBody() )
+ {
+ addProblem(new AbstractMethodWithBodyProblem(SemanticUtils.getFunctionProblemNode(func)));
+ }
+ }
+ else if ( !( def.hasModifier(ASModifier.NATIVE ) || def.hasModifier(ASModifier.DYNAMIC) || func.isConstructor() ) )
{
if ( !func.hasBody() )
{
@@ -797,6 +818,24 @@
}
}
+ private static List<IASNode> findThisIdentifierNodes(IASNode iNode)
+ {
+ List<IASNode> result = new ArrayList<IASNode>();
+ for(int i = 0, count = iNode.getChildCount(); i < count; i++)
+ {
+ IASNode child = iNode.getChild(i);
+ if(SemanticUtils.isThisKeyword(child))
+ {
+ result.add(child);
+ }
+ else if(!child.isTerminal() && !(child instanceof IFunctionNode))
+ {
+ result.addAll(findThisIdentifierNodes(child));
+ }
+ }
+ return result;
+ }
+
public void checkNativeMethod(IASNode iNode)
{
if( iNode instanceof FunctionNode )
@@ -941,6 +980,7 @@
public void checkFunctionDefinition(IFunctionNode iNode, FunctionDefinition def )
{
SemanticUtils.checkReturnValueHasNoTypeDeclaration(this.currentScope, iNode, def);
+ SemanticUtils.checkParametersHaveNoTypeDeclaration(this.currentScope, iNode, def);
if (SemanticUtils.isInFunction(iNode))
{
@@ -1793,6 +1833,21 @@
IExpressionNode site = ((IMemberAccessExpressionNode)nameNode).getRightOperandNode();
def = ((IFunctionCallNode)iNode).resolveCalledExpression(project);
checkDeprecated(site, def);
+ if (def == null || def.isAbstract())
+ {
+ String methodName = null;
+ if (nameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID)
+ {
+ MemberAccessExpressionNode mae = (MemberAccessExpressionNode)nameNode;
+ IExpressionNode rightNode = mae.getRightOperandNode();
+ if (rightNode.getNodeID() == ASTNodeID.IdentifierID)
+ methodName = ((IdentifierNode)rightNode).getName();
+ }
+ assert methodName != null;
+ addProblem(new CallUndefinedMethodProblem(
+ iNode, methodName
+ ));
+ }
}
if ( this.superState == SuperState.Initial )
@@ -1985,7 +2040,8 @@
*
* @param call_node {@link FunctionCallNode} that has the "new" call.
*/
- public void checkNewExpr(IASNode call_node)
+ @SuppressWarnings("incomplete-switch")
+ public void checkNewExpr(IASNode call_node)
{
final ExpressionNodeBase name = ((FunctionCallNode)call_node).getNameNode();
if (name instanceof MemberAccessExpressionNode)
@@ -1998,7 +2054,8 @@
}
else if ( def instanceof ClassDefinition )
{
- // pass
+ IClassDefinition classDef = (IClassDefinition) def;
+ checkPrivateConstructorNewExpr(call_node, null, classDef, classDef.getConstructor());
}
else if ( def instanceof GetterDefinition )
{
@@ -2014,6 +2071,16 @@
addProblem(new MethodCannotBeConstructorProblem(call_node));
break;
}
+
+ if (func_def.isConstructor())
+ {
+ IDefinition class_def = func_def.getParent();
+ checkPrivateConstructorNewExpr(call_node, null, class_def, func_def);
+ }
+ }
+ else if (def == null)
+ {
+ addProblem(new UnresolvedClassReferenceProblem(call_node, func_name.getDisplayString()));
}
}
}
@@ -2025,11 +2092,7 @@
{
IDefinition def = class_binding.getDefinition();
- if ( class_binding.isLocal() )
- {
- // No checking required.
- }
- else if ( def == null && utils.definitionCanBeAnalyzed(class_binding) && !(class_binding.getName().isTypeName()) )
+ if ( def == null && utils.definitionCanBeAnalyzed(class_binding) && !(class_binding.getName().isTypeName()) )
{
// Note: don't have to check accessability because
// AS3 mandates constructors be public.
@@ -2049,12 +2112,21 @@
{
ClassDefinition class_def = (ClassDefinition)def;
+ if ( project.getAllowAbstractClasses() && class_def.isAbstract() )
+ {
+ addProblem(new AbstractClassCannotBeInstantiatedProblem(
+ roundUpUsualSuspects(class_binding, iNode)
+ ));
+ }
+
IFunctionDefinition ctor = class_def.getConstructor();
if ( ctor instanceof FunctionDefinition )
{
- FunctionDefinition func = (FunctionDefinition)ctor;
- checkFormalsVsActuals(iNode, func, args);
+ FunctionDefinition func_def = (FunctionDefinition)ctor;
+ checkFormalsVsActuals(iNode, func_def, args);
+
+ checkPrivateConstructorNewExpr(iNode, class_binding, class_def, func_def);
}
}
else if ( def instanceof GetterDefinition )
@@ -2066,17 +2138,85 @@
IFunctionDefinition.FunctionClassification func_type = func_def.getFunctionClassification();
- if ( func_type.equals(IFunctionDefinition.FunctionClassification.CLASS_MEMBER) || func_type.equals(IFunctionDefinition.FunctionClassification.INTERFACE_MEMBER) )
+ if (func_def.isConstructor())
+ {
+ IDefinition class_def = func_def.getParent();
+ checkPrivateConstructorNewExpr(iNode, class_binding, class_def, func_def);
+ }
+ else if ( func_type.equals(IFunctionDefinition.FunctionClassification.CLASS_MEMBER) || func_type.equals(IFunctionDefinition.FunctionClassification.INTERFACE_MEMBER) )
{
addProblem(new MethodCannotBeConstructorProblem(
roundUpUsualSuspects(class_binding, iNode)
));
}
}
+ else if ( def instanceof IVariableDefinition)
+ {
+ if (class_binding.isLocal())
+ {
+ // Note: previously, local variable bindings were not checked at
+ // all, but actually, variables of most types cannot be used with a
+ // "new" expression -JT
+
+ ITypeDefinition typeDef = def.resolveType(project);
+ if (typeDef != null
+ && !SemanticUtils.isBuiltin(typeDef, BuiltinType.CLASS, project)
+ && !SemanticUtils.isBuiltin(typeDef, BuiltinType.FUNCTION, project)
+ && !SemanticUtils.isBuiltin(typeDef, BuiltinType.OBJECT, project)
+ && !SemanticUtils.isBuiltin(typeDef, BuiltinType.ANY_TYPE, project))
+ {
+ addProblem(new CallUndefinedMethodProblem(
+ roundUpUsualSuspects(class_binding, iNode),
+ class_binding.getName().getBaseName()
+ ));
+ }
+ }
+ }
checkReference(class_binding);
}
+ private void checkPrivateConstructorNewExpr(IASNode iNode, Binding class_binding, IDefinition classDef, IFunctionDefinition funcDef)
+ {
+ if (!project.getAllowPrivateConstructors() || !funcDef.isPrivate())
+ {
+ return;
+ }
+
+ IScopedNode enclosingScope = iNode.getContainingScope();
+
+ if (enclosingScope != null)
+ {
+ boolean needsProblem = true;
+ IASScope currentScope = enclosingScope.getScope();
+ while (currentScope != null)
+ {
+ IDefinition currentDef = currentScope.getDefinition();
+ if (currentDef instanceof IClassDefinition)
+ {
+ needsProblem = !classDef.equals(currentScope.getDefinition());
+ break;
+ }
+ currentScope = currentScope.getContainingScope();
+ }
+ if(needsProblem)
+ {
+ if(class_binding != null)
+ {
+ addProblem(new InaccessibleConstructorReferenceProblem(
+ roundUpUsualSuspects(class_binding, iNode), classDef.getQualifiedName()
+ ));
+ }
+ else
+ {
+ addProblem(new InaccessibleConstructorReferenceProblem(
+ iNode, classDef.getQualifiedName()
+ ));
+ }
+ }
+ }
+ }
+
/**
* Check a return expression that returns a value.
* @param iNode - the return statement.
@@ -2143,7 +2283,7 @@
{
if ( SemanticUtils.isInFunction(iNode) )
{
- if ( SemanticUtils.functionMustReturnValue(iNode, this.project) )
+ if ( SemanticUtils.functionMustReturnValue(iNode, currentScope.getProject().getAllowAbstractClasses(), this.project) )
addProblem(new ReturnMustReturnValueProblem(iNode));
}
else if ( isInClassDefinition(iNode) )
@@ -2182,7 +2322,9 @@
if (
il.size() > 0 &&
il.lastElement() == ABCGeneratingReducer.synthesizedReturnVoid &&
- SemanticUtils.functionMustReturnValue(iNode, this.project)
+ SemanticUtils.functionMustReturnValue(iNode,
+ currentScope.getProject().getAllowAbstractClasses(),
+ this.project)
)
{
for ( IBasicBlock b: mbi.getCfg().blocksInControlFlowOrder() )
@@ -2219,6 +2361,13 @@
{
IASNode site = importNode.getImportNameNode();
+ String importAlias = importNode.getImportAlias();
+ if (importAlias != null && !project.getAllowImportAliases())
+ {
+ //import aliases need to be enabled
+ addProblem(new SyntaxProblem(importNode, "="));
+ }
+
if (!SemanticUtils.isValidImport(importNode, project, currentScope.getInInvisibleCompilationUnit()))
{
String importName = importNode.getImportName();
@@ -2409,6 +2558,13 @@
{
currentScope.addProblem(new StaticOutsideClassProblem(site));
}
+ else if( modifier == ASModifier.ABSTRACT )
+ {
+ if(currentScope.getProject().getAllowAbstractClasses())
+ {
+ currentScope.addProblem(new AbstractOutsideClassProblem(site));
+ }
+ }
}
}
@@ -2436,6 +2592,22 @@
}
}
+ ExpressionNodeBase typeNode = var.getTypeNode();
+ IExpressionNode currentTypeNode = typeNode;
+ IDefinition vectorType = project.getBuiltinType(IASLanguageConstants.BuiltinType.VECTOR);
+ while (currentTypeNode instanceof ITypedExpressionNode)
+ {
+ ITypedExpressionNode typedNode = (ITypedExpressionNode) currentTypeNode;
+ IExpressionNode collectionNode = typedNode.getCollectionNode();
+ IDefinition collectionType = collectionNode.resolve(project);
+ if (!vectorType.equals(collectionType))
+ {
+ currentScope.addProblem(new TypeParametersWithNonParameterizedTypeProblem(collectionNode));
+ }
+ //keep checking while there are nested types
+ currentTypeNode = typedNode.getTypeNode();
+ }
+
// check if thise is an assignment in this declaration.
// If so, do checks on that
final ExpressionNodeBase rightNode = var.getAssignedValueNode();
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
index 344f14f..d22d291 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/semantics/SemanticUtils.java
@@ -104,6 +104,7 @@
import org.apache.royale.compiler.problems.DeprecatedAPIWithSinceAndReplacementProblem;
import org.apache.royale.compiler.problems.DeprecatedAPIWithSinceProblem;
import org.apache.royale.compiler.problems.ICompilerProblem;
+import org.apache.royale.compiler.problems.ParameterHasNoTypeDeclarationProblem;
import org.apache.royale.compiler.problems.ReturnValueHasNoTypeDeclarationProblem;
import org.apache.royale.compiler.problems.ScopedToDefaultNamespaceProblem;
import org.apache.royale.compiler.problems.UnknownSuperclassProblem;
@@ -117,15 +118,18 @@
import org.apache.royale.compiler.tree.as.IDefinitionNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
import org.apache.royale.compiler.tree.as.IFileNode;
+import org.apache.royale.compiler.tree.as.IFunctionCallNode;
import org.apache.royale.compiler.tree.as.IFunctionNode;
import org.apache.royale.compiler.tree.as.IIdentifierNode;
import org.apache.royale.compiler.tree.as.IImportNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode;
import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode.LanguageIdentifierKind;
import org.apache.royale.compiler.tree.as.ILiteralNode;
+import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode;
import org.apache.royale.compiler.tree.as.INamespaceDecorationNode;
import org.apache.royale.compiler.tree.as.INumericLiteralNode;
import org.apache.royale.compiler.tree.as.IParameterNode;
+import org.apache.royale.compiler.tree.as.IScopedNode;
import org.apache.royale.compiler.tree.as.ITryNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
import org.apache.royale.compiler.tree.mxml.IMXMLEventSpecifierNode;
@@ -835,7 +839,7 @@
if (base != null && base.isDynamicExpression(project))
return true;
// the JS version of XML is not currently dynamic so special case it here.
- if (base != null && base.getNodeID() == ASTNodeID.IdentifierID && IdentifierNode.isXMLish(base.resolveType(project), project))
+ if (base != null && base.getNodeID() == ASTNodeID.IdentifierID && isXMLish(base.resolveType(project), project))
return true;
return false;
}
@@ -945,6 +949,127 @@
}
/**
+ * Resolving the type of an expression on an XMLish object always returns *,
+ * but this function returns the actual resolved type, if available.
+ *
+ * @param iNode The node you want to resolve
+ * @param project an ICompilerProject for the current project.
+ * @return The type of the underlying expression, or null.
+ */
+ public static IDefinition resolveTypeXML(IExpressionNode iNode, ICompilerProject project)
+ {
+ IDefinition def = resolveXML(iNode, project);
+ if(def == null)
+ {
+ return null;
+ }
+ if (def instanceof IFunctionDefinition)
+ {
+ IFunctionDefinition functionDef = (IFunctionDefinition) def;
+ return functionDef.resolveReturnType(project);
+ }
+ return def.resolveType(project);
+ }
+
+ /**
+ * Resolving an expression on an XMLish object always returns null, but this
+ * function returns the actual resolved definition, if available.
+ *
+ * @param iNode The node you want to resolve
+ * @param project an ICompilerProject for the current project.
+ * @return The definition of the underlying expression, or null.
+ */
+ public static IDefinition resolveXML(IExpressionNode iNode, ICompilerProject project)
+ {
+ if (iNode instanceof IFunctionCallNode)
+ {
+ IFunctionCallNode functionCall = (IFunctionCallNode) iNode;
+ IExpressionNode nameNode = functionCall.getNameNode();
+ if (nameNode instanceof IMemberAccessExpressionNode)
+ {
+ IMemberAccessExpressionNode memberAccess = (IMemberAccessExpressionNode) nameNode;
+ nameNode = memberAccess.getRightOperandNode();
+ }
+ if (nameNode instanceof IIdentifierNode)
+ {
+ IIdentifierNode identifierNode = (IIdentifierNode) nameNode;
+ IDefinition resolvedDef = identifierNode.resolve(project);
+ if (resolvedDef != null && isXMLish(resolvedDef.getParent(), project))
+ {
+ if (resolvedDef instanceof IFunctionDefinition
+ && !(resolvedDef instanceof IAccessorDefinition))
+ {
+ //method call on XML or XMLList instance
+ return resolvedDef;
+ }
+ }
+ }
+ return null;
+ }
+
+ if (iNode instanceof IIdentifierNode)
+ {
+ IIdentifierNode identifierNode = (IIdentifierNode) iNode;
+ IDefinition resolvedDef = identifierNode.resolve(project);
+ if (resolvedDef != null && isXMLish(resolvedDef.getParent(), project))
+ {
+ if (resolvedDef.isPrivate() || resolvedDef.isProtected())
+ {
+ //private/protected member inside the XML or XMLList class
+ return resolvedDef;
+ }
+ }
+ }
+ if (iNode instanceof IMemberAccessExpressionNode)
+ {
+ IMemberAccessExpressionNode memberAccess = (IMemberAccessExpressionNode) iNode;
+ IExpressionNode nameNode = memberAccess.getRightOperandNode();
+ return resolveXML(nameNode, project);
+ }
+ return null;
+ }
+
+ /**
+ * Determine if the definition passed in is one of the XML types (XML or
+ * XMLList) These classes are unrelated, but behave in similar manners.
+ *
+ * @param def the {@link IDefinition} to check
+ * @param project the {@link ICompilerProject} in which to look up types
+ * @return true if definition is the built-in XML or XMLList type.
+ */
+ public static boolean isXMLish(IDefinition def, ICompilerProject project)
+ {
+ IDefinition xmlDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.XML);
+ IDefinition xmlListDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.XMLLIST);
+ return (xmlDef != null && def == xmlDef) ||
+ (xmlListDef != null && def == xmlListDef);
+ }
+
+ /**
+ * Determines if an expression is a toString() function call.
+ */
+ public static boolean isToStringFunctionCall(IExpressionNode node, ICompilerProject project)
+ {
+ if(!(node instanceof IFunctionCallNode))
+ {
+ return false;
+ }
+ IFunctionCallNode functionCall = (IFunctionCallNode) node;
+ IExpressionNode nameExpression = functionCall.getNameNode();
+ if (nameExpression instanceof IMemberAccessExpressionNode)
+ {
+ IMemberAccessExpressionNode memberAccess = (IMemberAccessExpressionNode) nameExpression;
+ IExpressionNode rightNode = memberAccess.getRightOperandNode();
+ if (rightNode instanceof IIdentifierNode)
+ {
+ IIdentifierNode rightIdentifier = (IIdentifierNode) rightNode;
+ return rightIdentifier.getName().equals("toString");
+ }
+ }
+ return false;
+ }
+
+ /**
* Get the type of a node's base expression as a string.
* @param node the node whose base's type is desired.
* @return the type string, or null if none found.
@@ -1200,6 +1325,21 @@
}
/**
+ * Is this function node contained within another function node?
+ * @param iNode - the node of interest.
+ * @return true if the function node is a closure
+ */
+ public static boolean isFunctionClosure(IFunctionNode functionNode)
+ {
+ IScopedNode containingScope = functionNode.getContainingScope();
+ if (containingScope == null)
+ {
+ return false;
+ }
+ return containingScope.getParent() instanceof IFunctionNode;
+ }
+
+ /**
* Is the given node in a class with a base class definition?
* @param iNode - the node of interest.
* @return true if the node is in a class with a base class.
@@ -2492,6 +2632,36 @@
}
/**
+ * Checks that a given function's parameters have a type, and logs a problem if not
+ *
+ * @param scope is the scope where problems are to be logged
+ * @param node is the function node that is being checked (used for location reporting)
+ * @param func is the definition of the function to be checked.
+ */
+ public static void checkParametersHaveNoTypeDeclaration(LexicalScope scope, IFunctionNode node, IFunctionDefinition func)
+ {
+ for (IParameterNode paramNode : node.getParameterNodes())
+ {
+ IExpressionNode paramType = paramNode.getVariableTypeNode();
+
+ // check for parameter type declaration
+ if (paramType == null)
+ {
+ scope.addProblem(new ParameterHasNoTypeDeclarationProblem(paramNode, paramNode.getName(), node.getName()));
+ }
+ else if(paramType.getAbsoluteStart() == -1 && paramType.getAbsoluteEnd() == -1
+ && paramType instanceof ILanguageIdentifierNode)
+ {
+ ILanguageIdentifierNode identifier = (ILanguageIdentifierNode) paramType;
+ if (identifier.getKind().equals(LanguageIdentifierKind.ANY_TYPE))
+ {
+ scope.addProblem(new ParameterHasNoTypeDeclarationProblem(paramNode, paramNode.getName(), node.getName()));
+ }
+ }
+ }
+ }
+
+ /**
* Checks that a given function definition has a return type, and logs a problem if not
*
* @param scope is the scope where problems are to be logged
@@ -2889,13 +3059,44 @@
}
/**
+ * Can the subject be abstract?
+ * @param iNode - an AST node in (or at the border of) the function.
+ * @return true if the definition is allowed to be abstract
+ */
+ public static boolean canBeAbstract(IASNode iNode, ICompilerProject project)
+ {
+ if(iNode instanceof IClassNode)
+ {
+ IClassNode classNode = (IClassNode) iNode;
+ IClassDefinition classDef = classNode.getDefinition();
+ return !classDef.isFinal();
+ }
+ else if(iNode instanceof IFunctionNode)
+ {
+ IFunctionNode funcNode = (IFunctionNode) iNode;
+ IFunctionDefinition funcDef = funcNode.getDefinition();
+ IDefinition parentDef = funcDef.getParent();
+ if (parentDef instanceof IClassDefinition)
+ {
+ return parentDef.isAbstract()
+ && !funcDef.isStatic()
+ && !funcDef.isFinal()
+ && !funcDef.isConstructor()
+ && !(funcDef instanceof IAccessorDefinition);
+ }
+ return false;
+ }
+ return false;
+ }
+
+ /**
* Does the subject function require a non-void return value?
* @param iNode - an AST node in (or at the border of) the function.
* @return true if the function's definition is known, the definition's
* return type is known (and the function is not a constructor),
* and the return type is not void or *
*/
- public static boolean functionMustReturnValue(IASNode iNode, ICompilerProject project)
+ public static boolean functionMustReturnValue(IASNode iNode, boolean allowAbstract, ICompilerProject project)
{
FunctionDefinition func_def = SemanticUtils.getFunctionDefinition(iNode);
@@ -2908,7 +3109,8 @@
return_type == null ||
return_type.equals(ClassDefinition.getVoidClassDefinition()) ||
return_type.equals(ClassDefinition.getAnyTypeClassDefinition()) ||
- func_def.isConstructor()
+ func_def.isConstructor() ||
+ (allowAbstract && canBeAbstract(iNode, project) && func_def.isAbstract())
);
}
else
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleAppSWFTarget.java b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleAppSWFTarget.java
index 06fe9c2..597fbf4 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleAppSWFTarget.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleAppSWFTarget.java
@@ -47,6 +47,7 @@
import org.apache.royale.abc.visitors.IMethodBodyVisitor;
import org.apache.royale.abc.visitors.IMethodVisitor;
import org.apache.royale.abc.visitors.ITraitVisitor;
+import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.common.IEmbedResolver;
import org.apache.royale.compiler.config.Configuration;
import org.apache.royale.compiler.config.RSLSettings;
@@ -70,6 +71,7 @@
import org.apache.royale.compiler.internal.definitions.ClassDefinition;
import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.royale.compiler.internal.projects.DependencyGraph;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.scopes.ASProjectScope;
import org.apache.royale.compiler.internal.tree.mxml.MXMLFileNode;
@@ -544,6 +546,16 @@
// If there's more dependencies introduced by CSS, the loop continues.
done = !allCompilationUnitsInTarget.addAll(cssDependencies);
+ if (done)
+ {
+ ClassDefinition rootDef = getRootClassDefinition();
+ ICompilationUnit rootClassCompilationUnit = project.getScope().getCompilationUnitForDefinition(rootDef);
+ DependencyGraph graph = royaleProject.getDependencyGraph();
+ for (ICompilationUnit cu : cssDependencies)
+ {
+ graph.addDependency(rootClassCompilationUnit, cu, DependencyType.EXPRESSION);
+ }
+ }
}
delegate.cssCompilationSession.cssDocuments.addAll(activatedStyleSheets.sort());
@@ -841,7 +853,6 @@
this.cssCompilationSession = new CSSCompilationSession();
this.cssCompilationSession.setKeepAllTypeSelectors(targetSettings.keepAllTypeSelectors());
- this.cssCompilationSession.setExcludeDefaultsCSSFiles(targetSettings.getExcludeDefaultsCSSFiles());
}
private final IClassDefinition mainApplicationClassDefinition;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleTarget.java b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleTarget.java
index 933d9a6..6a36dec 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleTarget.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/RoyaleTarget.java
@@ -20,8 +20,11 @@
package org.apache.royale.compiler.internal.targets;
import java.io.File;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -755,13 +758,28 @@
*/
public void addProductInfoToSWF(ISWF swf)
{
+ long compileDate = new Date().getTime();
+ String rdfDate = targetSettings.getSWFMetadataDate();
+ String rdfDateFormat = targetSettings.getSWFMetadataDateFormat();
+ if (rdfDate != null && rdfDateFormat != null)
+ {
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(rdfDateFormat);
+ compileDate = sdf.parse(rdfDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
// Add product info to the swf.
ProductInfoTag productInfo = new ProductInfoTag(Product.ROYALE,
Edition.NONE,
(byte)Integer.parseInt(VersionInfo.FLEX_MAJOR_VERSION),
(byte)Integer.parseInt(VersionInfo.FLEX_MINOR_VERSION),
VersionInfo.getBuildLong(),
- 0);
+ compileDate);
swf.setProductInfo(productInfo);
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/SWCTarget.java b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/SWCTarget.java
index 8088ec9..dbeafc5 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/SWCTarget.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/SWCTarget.java
@@ -22,6 +22,8 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -318,6 +320,22 @@
if (contents != null)
{
+ long fileDate = 0;
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ fileSpec.setLastModified(fileDate);
+ }
swc.addFile(path, fileSpec.getLastModified(), contents);
}
else
@@ -532,7 +550,22 @@
for (final IDefinition def : fsResult.getExternallyVisibleDefinitions())
{
script.addDefinition(def.getQualifiedName());
- script.setLastModified(cu.getSyntaxTreeRequest().get().getLastModified());
+ long mod = cu.getSyntaxTreeRequest().get().getLastModified();
+ String metadataDate = targetSettings.getSWFMetadataDate();
+ if (metadataDate != null)
+ {
+ String metadataFormat = targetSettings.getSWFMetadataDateFormat();
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ mod = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
+ script.setLastModified(mod);
if (definitionsToBuild != null)
definitionsToBuild.add(def);
@@ -661,7 +694,11 @@
rootCompilationUnits.addAll(getIncludesCompilationUnits());
rootCompilationUnits.addAll(getIncludeLibrariesCompilationUnits());
- return new Target.RootedCompilationUnits(rootCompilationUnits, problems);
+ Target.RootedCompilationUnits units = new Target.RootedCompilationUnits(rootCompilationUnits, problems);
+ Set<ICompilationUnit> unitSet = units.getUnits();
+// for (ICompilationUnit cu : unitSet)
+// System.out.println(cu.getName());
+ return units;
}
@Override
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/Target.java b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/Target.java
index cc16eb7..8acd14e 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/targets/Target.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/targets/Target.java
@@ -26,9 +26,12 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.references.IResolvedQualifiersReference;
@@ -366,7 +369,20 @@
return Collections.emptySet();
}
}
- return visitedSet;
+ TreeSet<ICompilationUnit> sortedSet = new TreeSet<ICompilationUnit>(new Comparator<ICompilationUnit>()
+ {
+ @Override
+ public int compare(ICompilationUnit o1, ICompilationUnit o2)
+ {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+ sortedSet.addAll(visitedSet);
+// System.out.println("visited set");
+// for (ICompilationUnit visited : sortedSet)
+// System.out.println(visited.getName());
+// System.out.println("end visited set");
+ return sortedSet;
}
protected DirectDependencies getDirectDependencies(ICompilationUnit cu) throws InterruptedException
@@ -766,11 +782,19 @@
{
assert units != null;
assert problems != null;
- this.units = units;
+ this.units = new TreeSet<ICompilationUnit>(new Comparator<ICompilationUnit>()
+ {
+ @Override
+ public int compare(ICompilationUnit o1, ICompilationUnit o2)
+ {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
+ this.units.addAll(units);
this.problems = problems;
}
- private final Set<ICompilationUnit> units;
+ private final SortedSet<ICompilationUnit> units;
private final Iterable<ICompilerProblem> problems;
public Set<ICompilationUnit> getUnits()
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
index a1d9609..c45def6 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseDefinitionNode.java
@@ -401,6 +401,8 @@
db.setOverride();
if (hasModifier(ASModifier.STATIC))
db.setStatic();
+ if (hasModifier(ASModifier.ABSTRACT))
+ db.setAbstract();
}
protected void fillInMetadata(DefinitionBase definition)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseLiteralContainerNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseLiteralContainerNode.java
index 625d9e4..f1496df 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseLiteralContainerNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BaseLiteralContainerNode.java
@@ -37,7 +37,8 @@
/**
* Constructor.
*/
- public BaseLiteralContainerNode(LiteralNode baseTypeNode)
+ @SuppressWarnings("incomplete-switch")
+ public BaseLiteralContainerNode(LiteralNode baseTypeNode)
{
this.baseTypeNode = baseTypeNode;
baseTypeNode.setParent(this);
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorNodeBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorNodeBase.java
index d51c82d..03dae65 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorNodeBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorNodeBase.java
@@ -282,7 +282,7 @@
protected void fillInOffsets()
{
if (rightOperandNode == null && leftOperandNode == null && operatorStart != -1)
- span(operatorStart, operatorStart + 1, -1, -1);
+ span(operatorStart, operatorStart + 1, -1, -1, -1, -1);
else
super.fillInOffsets();
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorPlusNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorPlusNode.java
index 771b4aa..7f4bcea 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorPlusNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/BinaryOperatorPlusNode.java
@@ -21,6 +21,7 @@
import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
import org.apache.royale.compiler.definitions.ITypeDefinition;
+import org.apache.royale.compiler.internal.semantics.SemanticUtils;
import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
@@ -83,8 +84,8 @@
// If we're adding two XML-ish (i.e., XML or XMLList) objects,
// then the result is XMLList.
- if (IdentifierNode.isXMLish(leftType, project) &&
- IdentifierNode.isXMLish(rightType, project))
+ if (SemanticUtils.isXMLish(leftType, project) &&
+ SemanticUtils.isXMLish(rightType, project))
{
return project.getBuiltinType(BuiltinType.XMLLIST);
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ClassNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ClassNode.java
index 38e094b..484f0a8 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ClassNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ClassNode.java
@@ -361,6 +361,16 @@
{
if (contentsNode.getChild(i) instanceof IDefinitionNode)
names.add(((IDefinitionNode)contentsNode.getChild(i)));
+ else if (contentsNode.getChild(i).getNodeID() == ASTNodeID.ConfigBlockID)
+ {
+ ConfigConditionBlockNode configNode = (ConfigConditionBlockNode)contentsNode.getChild(i);
+ int configChildCount = configNode.getChildCount();
+ for (int j = 0; j < configChildCount; j++)
+ {
+ if (configNode.getChild(j) instanceof IDefinitionNode)
+ names.add(((IDefinitionNode)configNode.getChild(j)));
+ }
+ }
}
return names.toArray(new IDefinitionNode[0]);
}
@@ -503,10 +513,10 @@
// so we'll create one and add it to the ClassNode
IdentifierNode constructorNameNode = new IdentifierNode(getName());
constructorNameNode.setReferenceValue(getDefinition());
- constructorNameNode.span(getNameAbsoluteStart(), getNameAbsoluteEnd(), -1, -1);
+ constructorNameNode.span(getNameAbsoluteStart(), getNameAbsoluteEnd(), -1, -1, -1, -1);
defaultConstructorNode = new FunctionNode(null, constructorNameNode);
NamespaceIdentifierNode pub = new NamespaceIdentifierNode(INamespaceConstants.public_);
- pub.span(-1, -1, -1, -1);
+ pub.span(-1, -1, -1, -1, -1, -1);
defaultConstructorNode.setNamespace(pub);
defaultConstructorNode.normalize(true);
defaultConstructorNode.setParent(contentsNode);
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ConfigConditionBlockNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ConfigConditionBlockNode.java
index 62080ea..c0998f4 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ConfigConditionBlockNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ConfigConditionBlockNode.java
@@ -33,7 +33,7 @@
*/
public final class ConfigConditionBlockNode extends BlockNode
{
- private final boolean enabled;
+ private boolean enabled;
/**
* Create a enabled or disabled configuration config block.
@@ -58,6 +58,24 @@
else
return 0;
}
+
+ @Override
+ protected void fillInOffsets()
+ {
+ boolean oldEnabled = enabled;
+ enabled = true;
+ super.fillInOffsets();
+ enabled = oldEnabled;
+ }
+
+ @Override
+ public void normalize(boolean fillInOffsets)
+ {
+ boolean oldEnabled = enabled;
+ enabled = true;
+ super.normalize(fillInOffsets);
+ enabled = oldEnabled;
+ }
@Override
protected boolean buildInnerString(StringBuilder sb)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java
index 49cad6e..8df9fae 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/DynamicAccessNode.java
@@ -19,6 +19,9 @@
package org.apache.royale.compiler.internal.tree.as;
+import org.apache.royale.compiler.definitions.IAppliedVectorDefinition;
+import org.apache.royale.compiler.definitions.ITypeDefinition;
+import org.apache.royale.compiler.internal.semantics.SemanticUtils;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IDynamicAccessNode;
@@ -70,9 +73,28 @@
@Override
public boolean isDynamicExpression(ICompilerProject project)
{
+ ITypeDefinition leftType = getLeftOperandNode().resolveType(project);
+ if (leftType instanceof IAppliedVectorDefinition)
+ {
+ return super.isDynamicExpression(project);
+ }
return true;
}
+ @Override
+ public ITypeDefinition resolveType(ICompilerProject project)
+ {
+ ITypeDefinition leftType = getLeftOperandNode().resolveType(project);
+ if (leftType instanceof IAppliedVectorDefinition)
+ {
+ if (SemanticUtils.isNumericType(getRightOperandNode().resolveType(project), project)) {
+ IAppliedVectorDefinition vectorDef = (IAppliedVectorDefinition) leftType;
+ return vectorDef.resolveElementType(project);
+ }
+ }
+ return super.resolveType(project);
+ }
+
//
// OperatorNodeBase overrides
//
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FullNameNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FullNameNode.java
index c23fec7..92c9709 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FullNameNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FullNameNode.java
@@ -71,7 +71,11 @@
super(left, operator, right);
if (right != null)
+ {
setEnd(right.getAbsoluteEnd());
+ setEndLine(right.getEndLine());
+ setEndColumn(right.getEndColumn());
+ }
}
protected FullNameNode(MemberAccessExpressionNode node)
@@ -145,7 +149,11 @@
super.setRightOperandNode(right);
if (right != null)
+ {
setEnd(right.getAbsoluteEnd());
+ setEndLine(right.getEndLine());
+ setEndColumn(right.getEndColumn());
+ }
}
//
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionCallNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionCallNode.java
index 255eee5..b0628fb 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionCallNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionCallNode.java
@@ -23,10 +23,7 @@
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType;
-import org.apache.royale.compiler.definitions.IAccessorDefinition;
-import org.apache.royale.compiler.definitions.IDefinition;
-import org.apache.royale.compiler.definitions.IFunctionDefinition;
-import org.apache.royale.compiler.definitions.ITypeDefinition;
+import org.apache.royale.compiler.definitions.*;
import org.apache.royale.compiler.parsing.IASToken;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
@@ -211,8 +208,17 @@
// new foo() returns the * type
if (getNewKeywordNode() != null)
return project.getBuiltinType(BuiltinType.ANY_TYPE);
- else
- return ((IFunctionDefinition)calledFunction).resolveReturnType(project);
+ else {
+ //special case: removeAt on a Vector needs to resolve its return type to type 'T' (element type), not 'Object' (as it does with Array method)
+ if (calledFunction.getQualifiedName().equals("removeAt")
+ && calledFunction.getContainingScope() != null
+ && calledFunction.getContainingScope().getDefinition() instanceof IAppliedVectorDefinition)
+ {
+ return ((IAppliedVectorDefinition)(calledFunction.getContainingScope().getDefinition())).resolveElementType(project);
+ } else {
+ return ((IFunctionDefinition)calledFunction).resolveReturnType(project);
+ }
+ }
}
else if (calledFunction instanceof ITypeDefinition)
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
index c48154b..54c836c 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/FunctionNode.java
@@ -36,8 +36,10 @@
import org.apache.royale.compiler.common.IImportTarget;
import org.apache.royale.compiler.config.CompilerDiagnosticsConstants;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.IMetaAttributeConstants;
import org.apache.royale.compiler.constants.INamespaceConstants;
import org.apache.royale.compiler.definitions.IDefinition;
+import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition.FunctionClassification;
import org.apache.royale.compiler.definitions.IParameterDefinition;
import org.apache.royale.compiler.definitions.references.IReference;
@@ -74,6 +76,7 @@
import org.apache.royale.compiler.tree.as.IScopedNode;
import org.apache.royale.compiler.tree.as.ITypeNode;
import org.apache.royale.compiler.tree.as.IVariableNode;
+import org.apache.royale.compiler.tree.metadata.IMetaTagNode;
import org.apache.royale.compiler.workspaces.IWorkspace;
import com.google.common.base.Predicate;
@@ -165,6 +168,12 @@
* Save the problems until later if we were parsed from somewhere we don't have a problems collection
*/
private Collection<ICompilerProblem> parseProblems;
+
+ /**
+ * Indicates whether we've called rememberLocalFunction() on the parent
+ * function yet (if a parent function even exists in the first place) -JT
+ */
+ private boolean isRemembered = false;
//
// NodeBase overrides
@@ -203,12 +212,24 @@
@Override
protected void analyze(EnumSet<PostProcessStep> set, ASScope scope, Collection<ICompilerProblem> problems)
{
- if (set.contains(PostProcessStep.POPULATE_SCOPE))
+ if (!isRemembered)
{
+ //previously, we remembered local functions only during
+ //POPULATE_SCOPE. however, in MXML, functions get created multiple
+ //times, and the second time around, analyze() is NOT called with
+ //POPULATE_SCOPE. this causes our function to be forgotten.
+ //better to check if we've remembered or not no matter which steps
+ //were passed in. -JT
final IFunctionNode parentFunctionNode = (IFunctionNode)getAncestorOfType(IFunctionNode.class);
if (parentFunctionNode != null)
+ {
+ isRemembered = true;
parentFunctionNode.rememberLocalFunction(this);
-
+ }
+ }
+
+ if (set.contains(PostProcessStep.POPULATE_SCOPE))
+ {
FunctionDefinition definition = buildDefinition();
setDefinition(definition);
@@ -346,10 +367,32 @@
if (isConstructor())
{
- if (namespaceNode != null && namespaceNode.getName().equals(INamespaceConstants.public_))
+ if (namespaceNode != null
+ && (namespaceNode.getName().equals(INamespaceConstants.public_) || namespaceNode.getName().equals(INamespaceConstants.private_)))
+ {
+ // if the existing node is already public or private, return it
return namespaceNode;
+ }
+ IASNode parentNode = getParent();
+ if (parentNode instanceof IDefinitionNode)
+ {
+ IDefinitionNode defNode = (IDefinitionNode) parentNode;
+ IMetaTagNode[] metaTagNodes = defNode.getMetaTags().getTagsByName(IMetaAttributeConstants.ATTRIBUTE_PRIVATE_CONSTRUCTOR);
+ if (metaTagNodes != null && metaTagNodes.length > 0)
+ {
+ // if the parent class has [RoyalePrivateConstructor]
+ // metadata, the constructor should be considered private
+ // and we should generate a fake namespace node
+ NamespaceIdentifierNode priv = new NamespaceIdentifierNode(INamespaceConstants.private_);
+ priv.span(-1, -1, -1, -1, -1, -1);
+ priv.setDecorationTarget(this);
+ return priv;
+ }
+ }
+ // if there is no namespace node, the namespace defaults to public
+ // and we'll generate a fake node
NamespaceIdentifierNode pub = new NamespaceIdentifierNode(INamespaceConstants.public_);
- pub.span(-1, -1, -1, -1);
+ pub.span(-1, -1, -1, -1, -1, -1);
pub.setDecorationTarget(this);
return pub;
}
@@ -364,11 +407,12 @@
if (ns != null)
{
String nameString = ns.getName();
- // If public, just return it.
- if (nameString.equals(INamespaceConstants.public_))
+ // If public or private, just return it.
+ if (nameString.equals(INamespaceConstants.public_) || nameString.equals(INamespaceConstants.private_))
return nameString;
- // Otherwise, check to see if we are a constructor.
+ // Otherwise, check to see if we are a constructor and always return
+ // public
if (isConstructor())
return INamespaceConstants.public_;
@@ -631,8 +675,16 @@
classNode.constructorNode = this;
}
}
+ // if the namespace reference is private, don't change it
+ if(!(funcDef.getNamespaceReference() instanceof INamespaceDefinition.IPrivateNamespaceDefinition))
+ {
+ funcDef.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
+ }
}
- funcDef.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
+ else
+ {
+ funcDef.setNamespaceReference(NamespaceDefinition.getCodeModelImplicitDefinitionNamespace());
+ }
}
}
@@ -902,6 +954,11 @@
{
return problem.getLine() == line;
}
+ @Override
+ public boolean test(ICompilerProblem input)
+ {
+ return apply(input);
+ }
};
}
@@ -917,6 +974,11 @@
{
return problemClass.isInstance(problem);
}
+ @Override
+ public boolean test(ICompilerProblem input)
+ {
+ return apply(input);
+ }
};
}
@@ -1040,19 +1102,5 @@
localFunctions = new ArrayList<IFunctionNode>();
localFunctions.add(value);
- }
-
- private boolean emitLocalFunctions;
-
- @Override
- public boolean getEmittingLocalFunctions()
- {
- return emitLocalFunctions;
- }
-
- @Override
- public void setEmittingLocalFunctions(boolean emit)
- {
- emitLocalFunctions = emit;
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/IdentifierNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/IdentifierNode.java
index ccad9d6..3ba32a1 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/IdentifierNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/IdentifierNode.java
@@ -104,22 +104,6 @@
}
/**
- * Determine if the definition passed in is one of the XML types (XML or
- * XMLList) These classes are unrelated, but behave in similar manners.
- *
- * @param def the {@link IDefinition} to check
- * @param project the {@link ICompilerProject} in which to look up types
- * @return true if definition is the built-in XML or XMLList type.
- */
- public static boolean isXMLish(IDefinition def, ICompilerProject project)
- {
- IDefinition xmlDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.XML);
- IDefinition xmlListDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.XMLLIST);
- return (xmlDef != null && def == xmlDef) ||
- (xmlListDef != null && def == xmlListDef);
- }
-
- /**
* Constructor.
*/
public IdentifierNode(String name)
@@ -323,6 +307,7 @@
return true;
}
+ private IDefinition idDef = null;
//
// ExpressionNodeBase overrides
//
@@ -330,6 +315,9 @@
@Override
public IDefinition resolve(ICompilerProject project)
{
+ if (DefinitionBase.getPerformanceCachingEnabled() && idDef != null)
+ return idDef;
+
ASScope asScope = getASScope();
if (asScope == null)
@@ -391,7 +379,10 @@
{
if (qualifier == null)
{
- result = asScope.findProperty(project, name, getDependencyType(), isTypeRef());
+ DependencyType dt = getDependencyType();
+ result = asScope.findProperty(project, name, dt, isTypeRef());
+ if (result != null && name.equals("graphics") && (result.getParent() instanceof ITypeDefinition) && ((ITypeDefinition)(result.getParent())).isInstanceOf("mx.core.UIComponent", project))
+ result = asScope.findProperty(project, "royalegraphics", getDependencyType(), isTypeRef());
// ASVariableTests_localVarSameNameAsPrivateMethod
if (isLegacyCodegen(project) && result != null && getParent().getNodeID() == ASTNodeID.FunctionCallID && result instanceof VariableDefinition)
{
@@ -457,6 +448,7 @@
((RoyaleProject)project).addToAPIReport(result);
}
+ idDef = result;
return result;
}
@@ -467,7 +459,7 @@
if (def != null)
{
- if (isXMLish(def.getParent(), project))
+ if (SemanticUtils.isXMLish(def.getParent(), project))
{
// XML and XMLList members should be treated as '*' because any access could
// resolve to some content inside the XML (i.e. it has a child tag named 'name').
@@ -878,7 +870,7 @@
IDefinition result = null;
// Determine baseType, the type of 'a' (the left-hand-side of the member access operator).
- IDefinition baseType = null;
+ ITypeDefinition baseType = null;
ExpressionNodeBase baseExpr = getBaseExpression();
if (baseExpr != null)
{
@@ -901,7 +893,7 @@
// and x is type XML you would get a can't-convert-Object-to-String
// problem, but there is lots of existing source code that expects
// this to compile with no cast.
- if (!((RoyaleProject)project).useStrictXML() && isXMLish(baseType, project))
+ if (!((RoyaleProject)project).useStrictXML() && SemanticUtils.isXMLish(baseType, project))
return null;
if (baseExpr instanceof IdentifierNode)
@@ -920,6 +912,12 @@
}
if (qualifier != null)
result = asScope.getQualifiedPropertyFromDef(project, baseType, name, qualifier, isSuper);
+ else if (name.equals("graphics") && baseType.isInstanceOf("mx.core.UIComponent", project))
+ {
+ result = asScope.getPropertyFromDef(project, baseType, "royalegraphics", isSuper);
+ if (result == null)
+ result = asScope.getPropertyFromDef(project, baseType, name, isSuper);
+ }
else
result = asScope.getPropertyFromDef(project, baseType, name, isSuper);
}
@@ -1031,7 +1029,7 @@
// Can't early bind to XML/XMLList properties as they may be hidden by the unknown contents
// of the XML itself, i.e. a child tag named 'parent'
// Matches ASC behavior.
- if (!isXMLish(def.getParent(), project))
+ if (!SemanticUtils.isXMLish(def.getParent(), project))
return true;
}
return false;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LanguageIdentifierNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LanguageIdentifierNode.java
index 89175d5..090717b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LanguageIdentifierNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LanguageIdentifierNode.java
@@ -464,7 +464,8 @@
*
* @return The Context that this expression occurs in
*/
- public Context getContext()
+ @SuppressWarnings("incomplete-switch")
+ public Context getContext()
{
IASNode p = getParent();
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LiteralNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LiteralNode.java
index 1f60b9f..f9eb2f8 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LiteralNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/LiteralNode.java
@@ -119,7 +119,8 @@
// NodeBase overrides
//
- @Override
+ @SuppressWarnings("incomplete-switch")
+ @Override
public ASTNodeID getNodeID()
{
switch (type)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceAccessExpressionNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceAccessExpressionNode.java
index 175f500..ae8e987 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceAccessExpressionNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceAccessExpressionNode.java
@@ -41,7 +41,7 @@
{
super(operator, left instanceof IdentifierNode ? new NamespaceIdentifierNode((IdentifierNode)left) : left, right);
- leftOperandNode.span(left.getAbsoluteStart(), left.getAbsoluteEnd(), left.getLine(), left.getColumn());
+ leftOperandNode.span(left.getAbsoluteStart(), left.getAbsoluteEnd(), left.getLine(), left.getColumn(), left.getEndLine(), left.getEndColumn());
}
/**
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceIdentifierNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceIdentifierNode.java
index bd74fd2..05238a9 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceIdentifierNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NamespaceIdentifierNode.java
@@ -79,7 +79,7 @@
{
super(node.getName());
- span(node.getAbsoluteStart(), node.getAbsoluteEnd(), node.getLine(), node.getColumn());
+ span(node.getAbsoluteStart(), node.getAbsoluteEnd(), node.getLine(), node.getColumn(), node.getEndLine(), node.getEndColumn());
setSourcePath(node.getSourcePath());
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NodeBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NodeBase.java
index d4d9941..eef182f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NodeBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/NodeBase.java
@@ -483,13 +483,28 @@
* @param start start offset for the node
* @param end end offset for the node
* @param line line number for the node
+ * @deprecated Use span(int,int,int,int,int,int) instead so that endLine and endColumn are included
*/
public final void span(int start, int end, int line, int column)
{
+ span(start, end, line, column, -1, -1);
+ }
+
+ /**
+ * Set the start and end offsets of the node. Used during parsing.
+ *
+ * @param start start offset for the node
+ * @param end end offset for the node
+ * @param line line number for the node
+ */
+ public final void span(int start, int end, int line, int column, int endLine, int endColumn)
+ {
setStart(start);
setEnd(end);
setLine(line);
setColumn(column);
+ setEndLine(endLine);
+ setEndColumn(endColumn);
}
public Collection<ICompilerProblem> runPostProcess(EnumSet<PostProcessStep> set, ASScope containingScope)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ParameterNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ParameterNode.java
index 51b209c..93efc2f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ParameterNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/ParameterNode.java
@@ -172,7 +172,7 @@
if (typeNode == null && isRest())
{
typeNode = new IdentifierNode(IASLanguageConstants.Array);
- typeNode.span(-1, -1, -1, -1);
+ typeNode.span(-1, -1, -1, -1, -1, -1);
return;
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UnaryOperatorNodeBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UnaryOperatorNodeBase.java
index 5145924..be92a12 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UnaryOperatorNodeBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UnaryOperatorNodeBase.java
@@ -148,7 +148,7 @@
{
if (operandNode == null && operatorStart != -1)
{
- span(operatorStart, operatorStart + 1, -1, -1);
+ span(operatorStart, operatorStart + 1, -1, -1, -1, -1);
}
else
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UseNamespaceNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UseNamespaceNode.java
index 8ce1130..51a3d29 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UseNamespaceNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/UseNamespaceNode.java
@@ -123,7 +123,7 @@
{
namespaceNode = new NamespaceIdentifierNode(((IIdentifierNode)namespace).getName());
((NodeBase)namespaceNode).setSourcePath(namespace.getSourcePath());
- ((NodeBase)namespaceNode).span(namespace.getAbsoluteStart(), namespace.getAbsoluteEnd(), namespace.getLine(), namespace.getColumn());
+ ((NodeBase)namespaceNode).span(namespace.getAbsoluteStart(), namespace.getAbsoluteEnd(), namespace.getLine(), namespace.getColumn(), namespace.getEndLine(), namespace.getEndColumn());
}
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingAttributeNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingAttributeNode.java
index 1fee677..56b8247 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingAttributeNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingAttributeNode.java
@@ -83,6 +83,11 @@
return attributeName;
}
+ public void setName(String s)
+ {
+ attributeName = s;
+ }
+
@Override
public int getChildCount()
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingNode.java
index 19b8085..5ed122b 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLBindingNode.java
@@ -39,7 +39,7 @@
/**
* Implementation of the {@code IMXMLBindingNode} interface.
*/
-class MXMLBindingNode extends MXMLNodeBase implements IMXMLBindingNode
+public class MXMLBindingNode extends MXMLNodeBase implements IMXMLBindingNode
{
/**
* Constructor
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassReferenceNodeBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassReferenceNodeBase.java
index 1327d7a..4c66aa4 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassReferenceNodeBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassReferenceNodeBase.java
@@ -51,6 +51,7 @@
import org.apache.royale.compiler.parsing.MXMLTokenTypes;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.MXMLDuplicateChildTagProblem;
+import org.apache.royale.compiler.problems.MXMLUnresolvedTagProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
@@ -592,6 +593,11 @@
}
}
}
+ if (processingDefaultProperty && definition == null)
+ {
+ builder.getProblems().add(new MXMLUnresolvedTagProblem(childTag));
+ return;
+ }
// Handle child tags that are something other than property/style/event tags
// or instance tags.
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLExpressionNodeBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLExpressionNodeBase.java
index 1bb26bc..34a9586 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLExpressionNodeBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLExpressionNodeBase.java
@@ -198,7 +198,7 @@
if (!SemanticUtils.isValidTypeConversion(expectedType, exprType, project, builder.getCompilationUnit().isInvisible()))
{
ICompilerProblem problem = new ImplicitCoercionToUnrelatedTypeProblem(
- expressionNode, exprType.getBaseName(), expectedType.getBaseName());
+ expressionNode, exprType.getQualifiedName(), expectedType.getQualifiedName());
builder.addProblem(problem);
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLNodeBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLNodeBase.java
index 4909e2e..b511f63 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLNodeBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLNodeBase.java
@@ -689,6 +689,7 @@
* @param end The ending offset of this node.
* @param line The number of the line on which this node starts.
* @param column This number of the column at which this node starts.
+ * @deprecated Use setLocation(String,int,int,int,int,int,int) instead
*/
public void setLocation(String sourcePath, int start, int end, int line, int column)
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLObjectNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLObjectNode.java
index 04f98a1..ef12b6f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLObjectNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLObjectNode.java
@@ -19,7 +19,6 @@
package org.apache.royale.compiler.internal.tree.mxml;
-import java.util.ArrayList;
import java.util.List;
import org.apache.royale.compiler.constants.IASLanguageConstants;
@@ -28,7 +27,6 @@
import org.apache.royale.compiler.mxml.IMXMLTagData;
import org.apache.royale.compiler.mxml.IMXMLUnitData;
import org.apache.royale.compiler.tree.ASTNodeID;
-import org.apache.royale.compiler.tree.mxml.IMXMLNode;
import org.apache.royale.compiler.tree.mxml.IMXMLObjectNode;
/**
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java
index 557dbf2..07291f8 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLTreeBuilder.java
@@ -137,6 +137,7 @@
this.compilationUnit = compilationUnit;
this.fileSpecGetter = fileSpecGetter;
project = compilationUnit.getProject();
+ factoryDef = (ITypeDefinition) project.resolveQNameToDefinition(project.getFactoryInterface());
projectScope = (ASProjectScope)project.getScope();
workspace = (Workspace)project.getWorkspace();
this.qname = qname;
@@ -154,6 +155,8 @@
private final IFileSpecificationGetter fileSpecGetter;
private final RoyaleProject project;
+
+ private final ITypeDefinition factoryDef;
private final ASProjectScope projectScope;
@@ -664,7 +667,7 @@
String typeName = (type != null) ? type.getQualifiedName() : "";
// For a property of type IFactory, create an MXMLFactoryNode.
- if (typeName.equals(project.getFactoryInterface()))
+ if (type != null && type.isInstanceOf(factoryDef, project))
{
if (flags.contains(TextParsingFlags.ALLOW_BINDING))
{
@@ -791,7 +794,7 @@
return instanceNode;
}
-
+
/**
* Reads an external file specified by a <code>source</code> attribute.
*
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/XMLBuilder.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/XMLBuilder.java
index bb5b63e..b428289 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/XMLBuilder.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/XMLBuilder.java
@@ -198,7 +198,8 @@
* those are (these are the expressions to set the value in the XML object
* when the TODO: PropertyChange event fires).
*/
- void processNode(IMXMLTextData tag,
+ @SuppressWarnings("incomplete-switch")
+ void processNode(IMXMLTextData tag,
StringWriter sw)
{
switch (tag.getTextType())
@@ -284,6 +285,8 @@
MXMLBindingNode bindingNode = new MXMLBindingNode(parent);
MXMLBindingAttributeNode target = new MXMLBindingAttributeNode(bindingNode, destExpr);
+ target.setLocation(attr);
+ target.setName(attr.getName());
destExpr.setParent(target);
MXMLBindingAttributeNode source = new MXMLBindingAttributeNode(bindingNode, dbnode.getExpressionNode());
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/units/CompilationUnitBase.java b/compiler/src/main/java/org/apache/royale/compiler/internal/units/CompilationUnitBase.java
index 9e680f6..a0cef1f 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/units/CompilationUnitBase.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/units/CompilationUnitBase.java
@@ -58,6 +58,7 @@
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.DefinitionPriority;
import org.apache.royale.compiler.internal.projects.DependencyGraph;
+import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.scopes.ASFileScope;
import org.apache.royale.compiler.internal.scopes.ASProjectScope;
import org.apache.royale.compiler.internal.scopes.ASProjectScope.DefinitionPromise;
@@ -1005,13 +1006,21 @@
*/
private String computeName()
{
- final String filename = FilenameUtils.getName(getAbsoluteFilename()).replace('.', '_');
- final String encodedAbsolutePath = StringEncoder.stringToHashCodeString(getAbsoluteFilename());
- String encodedName = encodedAbsolutePath + ":" + filename;
+ String absoluteFileName = getAbsoluteFilename();
+ final String filename = FilenameUtils.getName(absoluteFileName).replace('.', '_');
if (definitionPromises.isEmpty())
{
+ // conditional compilation units may not have definitionpromises
+ String encodedName = StringEncoder.stringToHashCodeString(absoluteFileName);
+ encodedName += ":" + filename;
return encodedName;
}
+ // we used to use the absolute path, but it would be different
+ // on different machines and we want builds to be binary reproducible.
+ // So we will use the first definition's QName as that should be unique
+ IDefinition def0 = getDefinitionPromises().get(0);
+ final String encodedQName = StringEncoder.stringToHashCodeString(def0.getQualifiedName());
+ String encodedName = encodedQName + ":" + filename;
try
{
@@ -1163,6 +1172,15 @@
rootPath = getAbsoluteFilename().replace(File.separatorChar + filenameNoPath, "");
else
rootPath = getAbsoluteFilename().replace(File.separatorChar + packagePath + File.separatorChar + filenameNoPath, "");
+ if (asProject instanceof RoyaleProject)
+ {
+ String swfDebugfileAlias = ((RoyaleProject)asProject).getSwfDebugfileAlias();
+ if (swfDebugfileAlias != null)
+ {
+ rootPath = swfDebugfileAlias;
+ packagePath = packagePath.replace('\\', '/');
+ }
+ }
String encodedPath = rootPath + ';' + packagePath + ';' + getFilenameNoPath();
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/units/FXGCompilationUnit.java b/compiler/src/main/java/org/apache/royale/compiler/internal/units/FXGCompilationUnit.java
index 1d62143..406f6fa 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/units/FXGCompilationUnit.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/units/FXGCompilationUnit.java
@@ -52,6 +52,7 @@
import org.apache.royale.compiler.internal.parsing.as.ASParser;
import org.apache.royale.compiler.internal.projects.CompilerProject;
import org.apache.royale.compiler.internal.projects.DefinitionPriority.BasePriority;
+import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.scopes.ASProjectScope;
import org.apache.royale.compiler.internal.scopes.FXGFileScope;
import org.apache.royale.compiler.internal.scopes.PackageScope;
@@ -64,6 +65,7 @@
import org.apache.royale.compiler.internal.units.requests.SyntaxTreeRequestResult;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.InternalCompilerProblem2;
+import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.units.requests.IABCBytesRequestResult;
import org.apache.royale.compiler.units.requests.IFileScopeRequestResult;
import org.apache.royale.compiler.units.requests.IOutgoingDependenciesRequestResult;
@@ -95,7 +97,16 @@
public GeneratedSourceFileSpecfication(String name, String content)
{
this.reader = new StringReader(content);
- this.name = FilenameNormalization.normalize(name);
+ String alias = null;
+ ICompilerProject project = FXGCompilationUnit.this.getProject();
+ if (project instanceof RoyaleProject)
+ {
+ alias = ((RoyaleProject)project).getSwfDebugfileAlias();
+ }
+ if (alias != null)
+ this.name = alias + "/" + name;
+ else
+ this.name = FilenameNormalization.normalize(name);
}
private final StringReader reader;
@@ -124,6 +135,12 @@
{
return false;
}
+
+ @Override
+ public void setLastModified(long fileDate) {
+ // TODO Auto-generated method stub
+
+ }
}
public FXGCompilationUnit(CompilerProject project, String path, BasePriority basePriority, String qname)
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/units/SWCCompilationUnit.java b/compiler/src/main/java/org/apache/royale/compiler/internal/units/SWCCompilationUnit.java
index 7a3d1ce..cb09a07 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/units/SWCCompilationUnit.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/units/SWCCompilationUnit.java
@@ -410,6 +410,11 @@
{
return swc.isANE();
}
+
+ public ISWC getSWC()
+ {
+ return swc;
+ }
@Override
public String getName()
@@ -456,7 +461,21 @@
*/
protected static String getLinkReportName(ICompilationUnit cu)
{
- StringBuilder reportBuilder = new StringBuilder(cu.getAbsoluteFilename());
+ String absoluteFileName = cu.getAbsoluteFilename();
+ ICompilerProject project = cu.getProject();
+ if (project instanceof RoyaleProject)
+ {
+ String alias = ((RoyaleProject)project).getSwfDebugfileAlias();
+ if (alias != null)
+ {
+ // clip off path to SWC
+ int slash = absoluteFileName.lastIndexOf("/");
+ int backslash = absoluteFileName.lastIndexOf("\\");
+ int lastSep = slash > backslash ? slash : backslash;
+ absoluteFileName = absoluteFileName.substring(lastSep + 1);
+ }
+ }
+ StringBuilder reportBuilder = new StringBuilder(absoluteFileName);
reportBuilder.append('(');
ArrayList<String> definitionQnames = new ArrayList<String>(cu.getDefinitionPromises().size());
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/units/requests/SWFTagsRequestResult.java b/compiler/src/main/java/org/apache/royale/compiler/internal/units/requests/SWFTagsRequestResult.java
index 8c83081..376e3ef 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/units/requests/SWFTagsRequestResult.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/units/requests/SWFTagsRequestResult.java
@@ -28,7 +28,6 @@
import java.util.Map.Entry;
import org.apache.royale.compiler.embedding.IEmbedData;
-import org.apache.royale.compiler.internal.embedding.EmbedData;
import org.apache.royale.compiler.internal.embedding.transcoders.TranscoderBase;
import org.apache.royale.compiler.problems.ICompilerProblem;
import org.apache.royale.compiler.units.requests.ISWFTagsRequestResult;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractClassCannotBeInstantiatedProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractClassCannotBeInstantiatedProblem.java
new file mode 100644
index 0000000..e9d34d1
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractClassCannotBeInstantiatedProblem.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Semantics diagnostic emitted when the method body
+ * semantic checker detects an attempt to instantiate an abstract class.
+ */
+public final class AbstractClassCannotBeInstantiatedProblem extends SemanticProblem
+{
+ public static final String DESCRIPTION =
+ "Abstract classes cannot be instantiated with the ${NEW} operator.";
+
+ public static final int errorCode = 1156;
+
+ public AbstractClassCannotBeInstantiatedProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String NEW = "new";
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractMethodWithBodyProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractMethodWithBodyProblem.java
new file mode 100644
index 0000000..e847e6b
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractMethodWithBodyProblem.java
@@ -0,0 +1,41 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Diagnostic emitted when an abstract method has a body
+ */
+public final class AbstractMethodWithBodyProblem extends SemanticProblem
+{
+ public static final String DESCRIPTION =
+ "Method marked ${ABSTRACT} must not have a body.";
+
+ public static final int errorCode = 1125;
+
+ public AbstractMethodWithBodyProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String ABSTRACT = "abstract";
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractOutsideClassProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractOutsideClassProblem.java
new file mode 100644
index 0000000..4ab44e2
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/AbstractOutsideClassProblem.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Problem generated when 'abstract' is used outside of a class
+ */
+public final class AbstractOutsideClassProblem extends CodegenProblem
+{
+ // TODO ErrorMSG: not specific to methods
+ public static final String DESCRIPTION =
+ "The ${ABSTRACT} attribute can only be used on a ${CLASS} definition or a non-static, non-final method defined on an ${ABSTRACT} ${CLASS}.";
+
+ public static final int errorCode = 1011;
+
+ public AbstractOutsideClassProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String ABSTRACT = "abstract";
+ public final String CLASS = "class";
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/BadAccessAbstractMethodProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/BadAccessAbstractMethodProblem.java
new file mode 100644
index 0000000..edd19cb
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/BadAccessAbstractMethodProblem.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Diagnostic emitted when the code generator detects an abstract method
+ * declared with an invalid access modifier
+ */
+public final class BadAccessAbstractMethodProblem extends SemanticProblem
+{
+ public static final String DESCRIPTION =
+ "Methods that are ${ABSTRACT} cannot be declared ${PRIVATE}.";
+
+ public static final int errorCode = 1157;
+
+ public BadAccessAbstractMethodProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String ABSTRACT = "abstract";
+ public final String PRIVATE = "private";
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/ConstructorMustBePublicOrPrivateProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/ConstructorMustBePublicOrPrivateProblem.java
new file mode 100644
index 0000000..93e8755
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/ConstructorMustBePublicOrPrivateProblem.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Diagnostic emitted when a constructor is not public or private
+ */
+public final class ConstructorMustBePublicOrPrivateProblem extends CodegenProblem
+{
+ public static final String DESCRIPTION =
+ "A constructor can only be declared ${PUBLIC} or ${PRIVATE}";
+
+ public static final int errorCode = 1153;
+
+ public ConstructorMustBePublicOrPrivateProblem(IASNode site)
+ {
+ super(site);
+ }
+
+ // Prevent these from being localized.
+ public final String PUBLIC = "public";
+ public final String PRIVATE = "private";
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/InaccessibleConstructorReferenceProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/InaccessibleConstructorReferenceProblem.java
new file mode 100644
index 0000000..761717a
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/InaccessibleConstructorReferenceProblem.java
@@ -0,0 +1,43 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Diagnostic emitted when the semantic analyzer detects
+ * an attempt to call an inaccessible constructor (e.g., a
+ * private constructor call outside the class).
+ */
+public final class InaccessibleConstructorReferenceProblem extends StrictSemanticsProblem
+{
+ public static final String DESCRIPTION =
+ "Attempted access of inaccessible constructor through a reference with static type ${className}.";
+
+ public static final int errorCode = 1195;
+
+ public InaccessibleConstructorReferenceProblem(IASNode site, final String className)
+ {
+ super(site);
+ this.className = className;
+ }
+
+ public final String className;
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/TypeParametersWithNonParameterizedTypeProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/TypeParametersWithNonParameterizedTypeProblem.java
new file mode 100644
index 0000000..8287171
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/TypeParametersWithNonParameterizedTypeProblem.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.tree.as.IASNode;
+
+/**
+ * Semantics diagnostic emitted when the method body
+ * semantic checker detects an attempt to add type parameters to a
+ * non-parameterized type.
+ */
+public final class TypeParametersWithNonParameterizedTypeProblem extends SemanticProblem
+{
+ public static final String DESCRIPTION =
+ "Type parameters with a non-parameterized type.";
+
+ public TypeParametersWithNonParameterizedTypeProblem(IASNode site)
+ {
+ super(site);
+ }
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/problems/UnimplementedAbstractMethodProblem.java b/compiler/src/main/java/org/apache/royale/compiler/problems/UnimplementedAbstractMethodProblem.java
new file mode 100644
index 0000000..332cd42
--- /dev/null
+++ b/compiler/src/main/java/org/apache/royale/compiler/problems/UnimplementedAbstractMethodProblem.java
@@ -0,0 +1,50 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.royale.compiler.problems;
+
+import org.apache.royale.compiler.definitions.IDefinition;
+
+/**
+ * Problem generated when a class does not implement an abstract method from one
+ * of its superclasses.
+ */
+public final class UnimplementedAbstractMethodProblem extends CodegenProblem
+{
+ public static final String DESCRIPTION =
+ "Method ${methodName} in ${ABSTRACT} ${CLASS} ${abstractClassName} not implemented by ${CLASS} ${className}";
+
+ public static final int errorCode = 1044;
+
+ public UnimplementedAbstractMethodProblem(IDefinition site, String methodName, String abstractClassName, String className)
+ {
+ super(site);
+ this.methodName = methodName;
+ this.abstractClassName = abstractClassName;
+ this.className = className;
+ }
+
+ public final String methodName;
+ public final String abstractClassName;
+ public final String className;
+
+ // Prevent these from being localized.
+ public final String ABSTRACT = "abstract";
+ public final String CLASS = "class";
+}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/projects/IRoyaleProject.java b/compiler/src/main/java/org/apache/royale/compiler/projects/IRoyaleProject.java
index c1c206a..f1a63db 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/projects/IRoyaleProject.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/projects/IRoyaleProject.java
@@ -233,4 +233,10 @@
* List of defined variables so it can be overridden
*/
Map<String, String> getCompilerDefine(Configuration config);
+
+ /**
+ * The File for the link report
+ */
+ File getLinkReport(Configuration config);
+
}
diff --git a/compiler/src/main/java/org/apache/royale/swc/SWCLibrary.java b/compiler/src/main/java/org/apache/royale/swc/SWCLibrary.java
index 2a708d2..c8a49af 100644
--- a/compiler/src/main/java/org/apache/royale/swc/SWCLibrary.java
+++ b/compiler/src/main/java/org/apache/royale/swc/SWCLibrary.java
@@ -33,7 +33,6 @@
import org.apache.royale.swc.io.SWCReader;
import org.apache.royale.swf.ISWF;
import org.apache.royale.swf.io.ISWFReader;
-import org.apache.royale.swf.io.SWFReader;
/**
* Implementation of library model in a SWC.
diff --git a/compiler/src/main/java/org/apache/royale/swc/io/SWCWriter.java b/compiler/src/main/java/org/apache/royale/swc/io/SWCWriter.java
index 55ceff8..c64e6ad 100644
--- a/compiler/src/main/java/org/apache/royale/swc/io/SWCWriter.java
+++ b/compiler/src/main/java/org/apache/royale/swc/io/SWCWriter.java
@@ -20,6 +20,7 @@
package org.apache.royale.swc.io;
import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
@@ -28,12 +29,15 @@
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.security.DigestOutputStream;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.io.IOUtils;
-
+import org.apache.royale.compiler.filespecs.FileSpecification;
import org.apache.royale.swc.ISWC;
import org.apache.royale.swc.ISWCFileEntry;
import org.apache.royale.swc.ISWCLibrary;
@@ -54,9 +58,9 @@
*
* @param filename path to write the file to.
*/
- public SWCWriter(final String filename) throws FileNotFoundException
+ public SWCWriter(final String filename, String swcDate, String swcDateFormat) throws FileNotFoundException
{
- this(filename, true, true, false, SizeReportWritingSWFWriter.getSWFWriterFactory(null));
+ this(filename, true, true, false, swcDate, swcDateFormat, SizeReportWritingSWFWriter.getSWFWriterFactory(null));
}
/**
@@ -71,6 +75,7 @@
boolean compressLibrarySWF,
boolean enableDebug,
boolean enableTelemetry,
+ String metadataDate, String metadataFormat,
ISWFWriterFactory swfWriterFactory) throws FileNotFoundException
{
super(compressLibrarySWF, enableDebug, enableTelemetry, swfWriterFactory);
@@ -80,6 +85,26 @@
File outputDirectory = new File(outputFile.getAbsoluteFile().getParent());
outputDirectory.mkdirs();
+ if (metadataDate != null)
+ {
+ // strip off timezone. Zip format doesn't store timezone
+ // and the goal is to have the same date and time regardless
+ // of which timezone the build machine is using.
+ int c = metadataDate.lastIndexOf(" ");
+ metadataDate = metadataDate.substring(0, c);
+ c = metadataFormat.lastIndexOf(" ");
+ metadataFormat = metadataFormat.substring(0, c);
+ try {
+ SimpleDateFormat sdf = new SimpleDateFormat(metadataFormat);
+ fileDate = sdf.parse(metadataDate).getTime();
+ } catch (ParseException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ } catch (IllegalArgumentException e1) {
+ e1.printStackTrace();
+ }
+ }
+
zipOutputStream = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
zipOutputStream.setLevel(Deflater.NO_COMPRESSION);
}
@@ -88,14 +113,30 @@
* Target SWC output stream.
*/
private final ZipOutputStream zipOutputStream;
+
+ private long fileDate = System.currentTimeMillis();
@Override
void writeCatalog(final ISWC swc) throws IOException
{
- zipOutputStream.putNextEntry(new ZipEntry(CATALOG_XML));
- final Writer catalogXMLWriter = new OutputStreamWriter(zipOutputStream);
+ ZipEntry ze = new ZipEntry(CATALOG_XML);
+ ze.setTime(fileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ final Writer catalogXMLWriter = new OutputStreamWriter(baos);
writeCatalogXML(swc, catalogXMLWriter);
catalogXMLWriter.flush();
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+ zipOutputStream.putNextEntry(ze);
+
+ baos.writeTo(zipOutputStream);
+
zipOutputStream.closeEntry();
}
@@ -107,14 +148,26 @@
assert swf != null : "Expect SWF model";
assert path != null : "Expect SWF path";
- zipOutputStream.putNextEntry(new ZipEntry(path));
-
- final DigestOutputStream digestStream = getDigestOutputStream(library, zipOutputStream);
-
+ ZipEntry ze = new ZipEntry(path);
+ ze.setTime(fileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
ISWFWriter swfWriter = swfWriterFactory.createSWFWriter(swf,
getLibrarySWFCompression(), enableDebug, enableTelemetry);
- swfWriter.writeTo(digestStream != null ? digestStream : zipOutputStream);
+ swfWriter.writeTo(baos);
swfWriter.close();
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+ zipOutputStream.putNextEntry(ze);
+
+ final DigestOutputStream digestStream = getDigestOutputStream(library, zipOutputStream);
+ baos.writeTo(digestStream != null ? digestStream : zipOutputStream);
+
zipOutputStream.closeEntry();
if (digestStream != null) {
@@ -125,10 +178,35 @@
@Override
void writeFile(final ISWCFileEntry fileEntry) throws IOException
{
- zipOutputStream.putNextEntry(new ZipEntry(fileEntry.getPath()));
+ ZipEntry ze = new ZipEntry(fileEntry.getPath());
+ ze.setTime(fileDate);
+ ze.setMethod(ZipEntry.STORED);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
final InputStream fileInputStream = fileEntry.createInputStream();
- IOUtils.copy(fileInputStream, zipOutputStream);
- fileInputStream.close();
+ String name = fileEntry.getPath();
+ if (name.endsWith(".css")) // add other text files here
+ {
+ FileSpecification.NoCRLFInputStream filteredInputStream =
+ new FileSpecification.NoCRLFInputStream(fileInputStream);
+ IOUtils.copy(filteredInputStream, baos);
+ filteredInputStream.close();
+ }
+ else
+ {
+ IOUtils.copy(fileInputStream, baos);
+ fileInputStream.close();
+ }
+
+ ze.setSize(baos.size());
+ ze.setCompressedSize(baos.size());
+ CRC32 crc = new CRC32();
+ crc.reset();
+ crc.update(baos.toByteArray());
+ ze.setCrc(crc.getValue());
+ zipOutputStream.putNextEntry(ze);
+
+ baos.writeTo(zipOutputStream);
zipOutputStream.closeEntry();
}
diff --git a/compiler/src/main/java/org/apache/royale/swf/io/SWFDump.java b/compiler/src/main/java/org/apache/royale/swf/io/SWFDump.java
index 4c35786..5f5fdc7 100644
--- a/compiler/src/main/java/org/apache/royale/swf/io/SWFDump.java
+++ b/compiler/src/main/java/org/apache/royale/swf/io/SWFDump.java
@@ -1394,7 +1394,7 @@
if (styleChange.isStateLineStyle())
{
out.print("lineStyle=\"" +
- (styles.getFillStyles().indexOf(styleChange.getLinestyle()) + 1) + "\" ");
+ (styles.getLineStyles().indexOf(styleChange.getLinestyle()) + 1) + "\" ");
}
if (styleChange.isStateNewStyles())
{
diff --git a/compiler/src/main/java/org/apache/royale/swf/io/SWFWriter.java b/compiler/src/main/java/org/apache/royale/swf/io/SWFWriter.java
index 1747e7d..a5cbc3f 100644
--- a/compiler/src/main/java/org/apache/royale/swf/io/SWFWriter.java
+++ b/compiler/src/main/java/org/apache/royale/swf/io/SWFWriter.java
@@ -1465,7 +1465,8 @@
writeTag(extraTag);
}
- private boolean writeRawTag(RawTag tag)
+ @SuppressWarnings("incomplete-switch")
+ private boolean writeRawTag(RawTag tag)
{
boolean skipTag = false;
// if writing out an AS3 swf, there are a number of
diff --git a/compiler/src/main/java/org/apache/royale/swf/io/SizeReportWritingSWFWriter.java b/compiler/src/main/java/org/apache/royale/swf/io/SizeReportWritingSWFWriter.java
index 610f0af..545070b 100644
--- a/compiler/src/main/java/org/apache/royale/swf/io/SizeReportWritingSWFWriter.java
+++ b/compiler/src/main/java/org/apache/royale/swf/io/SizeReportWritingSWFWriter.java
@@ -138,7 +138,8 @@
writeSizeReport();
}
- @Override
+ @SuppressWarnings("incomplete-switch")
+ @Override
protected void finishTag(ITag tag, IOutputBitStream tagData, IOutputBitStream out)
{
int startPos = out.size();
diff --git a/compiler/src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex b/compiler/src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex
index 7dfd516..be7802b 100644
--- a/compiler/src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex
+++ b/compiler/src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex
@@ -377,8 +377,7 @@
// or a TOKEN_EMPTY_TAG_END token (for />) before returning to the
// initial state.
-
-<MARKUP> "xmlns"?(":"{ID_FOLLOW}*)?
+<MARKUP> "xmlns"(":"{ID_FOLLOW}*)?
{
return buildToken(TOKEN_XMLNS);
}
diff --git a/compiler/src/main/resources/downloads.xml b/compiler/src/main/resources/downloads.xml
index ce7528c..b3195a2 100644
--- a/compiler/src/main/resources/downloads.xml
+++ b/compiler/src/main/resources/downloads.xml
@@ -29,7 +29,7 @@
antlr (3) - BSD
commons-cli (1.2) - Apache 2.0
commons-io (2.0.1) - Apache 2.0
- guava (15.0) - Apache 2.0
+ guava (25.1) - Apache 2.0
JBurg (1.10.2) - CPL 1.0
lzma-sdk (9.2) - Public Domain
-->
@@ -131,13 +131,13 @@
<!-- guava -->
<property name="guava.name" value="guava"/>
- <property name="guava.version" value="20.0"/>
+ <property name="guava.version" value="25.1-jre"/>
<antcall target="download-dependency">
<param name="name" value="${guava.name}"/>
<param name="src.server" value="${maven.search.url}"/>
<param name="src.folder" value="com/google/guava/guava/${guava.version}"/>
<param name="src.filename" value="guava-${guava.version}.jar"/>
- <param name="src.checksum" value="f32a8a2524620dbecc9f6bf6a20c293f"/>
+ <param name="src.checksum" value="da3838847d109ac435f0d3ed4ae1c794"/>
<param name="dest.folder" value=""/>
<param name="dest.filename" value="${guava.name}.jar"/>
<param name="license.use.apache" value="true"/>
@@ -166,7 +166,7 @@
<property name="jflex.name" value="jflex"/>
<property name="jflex.version" value="1.6.0"/>
<!-- property name="jflex.version" value="1.5.1"/ -->
- <property name="jflex.server" value="http://jflex.de"/>
+ <property name="jflex.server" value="https://jflex.de"/>
<property name="jflex.folder" value="."/>
<property name="jflex.filename" value="${jflex.name}-${jflex.version}.tar.gz"/>
<property name="jflex.md5" value="df8cc9ca50b549bf705bd23479c100dc"/>
@@ -193,10 +193,10 @@
<!-- lzma -->
<property name="lzma.name" value="lzma"/>
<property name="lzma.version" value="9.20"/>
- <property name="lzma.server" value="http://www.java2s.com"/>
- <property name="lzma.folder" value="Code/JarDownload/lzma"/>
- <property name="lzma.filename" value="${lzma.name}-${lzma.version}.jar.zip"/>
- <property name="lzma.md5" value="d5f7343bbd03bf1c4a4806b372cc5354"/>
+ <property name="lzma.server" value="${maven.search.url}"/>
+ <property name="lzma.folder" value="org/b1/pack/lzma-sdk-4j/9.22.0"/>
+ <property name="lzma.filename" value="lzma-sdk-4j-9.22.0.jar"/>
+ <property name="lzma.md5" value="15fe7f01f4a37ea0f93e6ff5736406fd"/>
<antcall target="download-dependency">
<param name="name" value="${lzma.name}-sdk"/>
<param name="version" value="${lzma.version}"/>
diff --git a/compiler/src/test/downloads.xml b/compiler/src/test/downloads.xml
index ba638a1..a9e0943 100644
--- a/compiler/src/test/downloads.xml
+++ b/compiler/src/test/downloads.xml
@@ -130,7 +130,7 @@
<target name="junit-download-jar" depends="junit-jar-check" unless="junit.jar.exists"
description="Downloads the JUnit jar.">
<antcall target="download-jar">
- <param name="srcUrl" value="http://search.maven.org/remotecontent?filepath=junit/junit/4.10"/>
+ <param name="srcUrl" value="https://search.maven.org/remotecontent?filepath=junit/junit/4.10"/>
<param name="srcJarFile" value="junit-4.10.jar"/>
<param name="destDir" value="${external.lib.dir}"/>
<param name="destJarFile" value="junit-4.10.jar"/>
diff --git a/compiler/src/test/java/as/ASAbstractClassTests.java b/compiler/src/test/java/as/ASAbstractClassTests.java
new file mode 100644
index 0000000..d98c122
--- /dev/null
+++ b/compiler/src/test/java/as/ASAbstractClassTests.java
@@ -0,0 +1,1193 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package as;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ASAbstractClassTests extends ASFeatureTestsBase
+{
+ @Test
+ public void testAbstractNotAllowedOnClassError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ //error because abstract classes have not been enabled
+ "abstract class A {",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnInterfaceError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ //error because abstract classes have not been enabled
+ "abstract interface A {",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnClassMethodError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because abstract classes have not been enabled
+ "public abstract function a():void",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnInterfaceMethodError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "interface A {",
+ //error because abstract classes have not been enabled
+ "abstract function a():void",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnStaticMethodError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because abstract classes have not been enabled
+ "public static abstract function a():void",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnGetterError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because abstract classes have not been enabled
+ "public abstract function get a():Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\nFunction does not have a body.\nFunction does not return a value.\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnSetterError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because abstract classes have not been enabled
+ "public abstract function set a(value:Object):void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnVariableError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because abstract classes have not been enabled
+ "public abstract var a:Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnStaticVariableError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because abstract classes have not been enabled
+ "public static abstract var a:Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnInterfaceGetterError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "interface A {",
+ //error because abstract classes have not been enabled
+ "abstract function get a():Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractNotAllowedOnInterfaceSetterError_withAllowAbstractClassesDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "interface A {",
+ //error because abstract classes have not been enabled
+ "abstract function set a(value:Object):void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=false"
+ };
+ compileAndExpectErrors(source, false,false,false, options,"'abstract' is not allowed here\n");
+ }
+
+ @Test
+ public void testAbstractClassNoErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testAbstractMethodOnClassNoErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testAbstractMethodWithParametersAndReturnOnClassNoErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a(arg0:String, arg1:Number):Boolean;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testAbstractMethodOnInterfaceError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "interface A {",
+ "abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\n");
+ }
+
+ @Test
+ public void testAbstractGetterOnInterfaceError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "interface A {",
+ "abstract function get a():Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\n");
+ }
+
+ @Test
+ public void testAbstractSetterOnInterfaceError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "interface A {",
+ "abstract function set a(value:Object):void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\n");
+ }
+
+ @Test
+ public void testAbstractProtectedMethodNoErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "protected abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testAbstractInternalMethodNoErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "internal abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testAbstractPrivateMethodError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "private abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Methods that are abstract cannot be declared private.\n");
+ }
+
+ @Test
+ public void testAbstractFinalClassError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract final class A {",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\n");
+ }
+
+ @Test
+ public void testAbstractFinalMethodError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public final abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractMethodNotInAbstractClassError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because an abstract method may only be defined on an
+ //abstract class
+ "public abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractStaticMethodError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ //error because a static function cannot be abstract
+ "public static abstract function a():void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractGetterError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ //error because a getter cannot be abstract
+ "public abstract function get a():Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\nFunction does not have a body.\nFunction does not return a value.\n");
+ }
+
+ @Test
+ public void testAbstractSetterError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ //error because a setter cannot be abstract
+ "public abstract function set a(value:Object):void;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\nFunction does not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractVariableError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ //error because a variable cannot be abstract
+ "public abstract var a:Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\n");
+ }
+
+ @Test
+ public void testAbstractStaticVariableError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ //error because a static variable cannot be abstract
+ "public static abstract var a:Object;",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "The abstract attribute can only be used on a class definition or a non-static, non-final method defined on an abstract class.\n");
+ }
+
+ @Test
+ public void testAbstractMethodBodyError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ //error because an abstract method has a body
+ "public abstract function a():void {}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Method marked abstract must not have a body.\n");
+ }
+
+ @Test
+ public void testAbstractClassNewOperatorError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ //error because the class is abstract and cannot be
+ //instantiated with new
+ "var obj:A = new A();",
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Abstract classes cannot be instantiated with the new operator.\n");
+ }
+
+ @Test
+ public void testConcreteClassExtendsAbstractNewOperatorNoErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ "var obj:A = new B();",
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "}",
+ "class B extends A {",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testAbstractClassSuperError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "class B extends A {",
+ "override public function a():void {",
+ //error because the the super method is abstract
+ "super.a();",
+ "};",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Call to a possibly undefined method a.\n");
+ }
+
+ @Test
+ public void testAbstractClassNotImplementedError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "class B extends A {",
+ //error because we did not implement the abstract method in
+ //a concrete subclass
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Method a in abstract class A not implemented by class B\n");
+ }
+
+ @Test
+ public void testAbstractClassNotImplementedErrorOneTimeForTwoConcreteSubclasses_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "class B extends A {",
+ //error because we did not implement the abstract method in
+ //a concrete subclass
+ "}",
+ "class C extends B {",
+ //no duplicate error here!
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Method a in abstract class A not implemented by class B\n");
+ }
+
+ @Test
+ public void testAbstractClassMissingOverrideError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "class B extends A {",
+ //error because we did not use the override keyword
+ "public function a():void {}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Overriding a function that is not marked for override\n");
+ }
+
+ @Test
+ public void testAbstractClassExtendsAbstractWithoutImplementingNoError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "abstract class B extends A {",
+ //we don't want an error for unimplemented methods because
+ //this class is also abstract
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testConcreteClassExtendsAbstractExtendsAbstractNotImplementedError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "abstract class B extends A {",
+ //we don't want an error for unimplemented methods because
+ //this class is also abstract
+ "}",
+ "class C extends B {",
+ //but we do want an error here for unimplemented methods
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Method a in abstract class A not implemented by class C\n");
+ }
+
+ @Test
+ public void testConcreteClassExtendsAbstractExtendsAbstractMultipleNotImplementedErrors_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "abstract class B extends A {",
+ "public abstract function b():void;",
+ "}",
+ "class C extends B {",
+ //mulitple errors because more than one method is not implemented
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ compileAndExpectErrors(source, false,false,false, options, "Method b in abstract class B not implemented by class C\nMethod a in abstract class A not implemented by class C\n");
+ }
+
+ @Test
+ public void testAbstractClassExtendsAbstractAndImplementsNoError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "abstract class B extends A {",
+ //it's okay for an abstract subclass to implement any
+ //abstract methods from the superclass
+ "override public function a():void {}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testConcreteClassExtendsAbstractNoError_withAllowAbstractClassesEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "abstract class A {",
+ "public abstract function a():void;",
+ "}",
+ "class B extends A {",
+ //no errors because we've implemented all of the methods
+ //that are abstract
+ "override public function a():void {}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+
+ String[] options = new String[]
+ {
+ "-allow-abstract-classes=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false,false,false, options, true);
+ Assert.assertEquals("", result);
+ }
+}
\ No newline at end of file
diff --git a/compiler/src/test/java/as/ASFeatureTestsBase.java b/compiler/src/test/java/as/ASFeatureTestsBase.java
index 9a5cf71..0b2c597 100644
--- a/compiler/src/test/java/as/ASFeatureTestsBase.java
+++ b/compiler/src/test/java/as/ASFeatureTestsBase.java
@@ -154,7 +154,7 @@
// Check that there were no compilation problems.
List<ICompilerProblem> problems = mxmlc.getProblems().getProblems();
- StringBuilder sb = new StringBuilder(checkExitCode ? "Unexpected compilation problems:\n" : "");
+ StringBuilder sb = new StringBuilder(checkExitCode && problems.size() > 0 ? "Unexpected compilation problems:\n" : "");
for (ICompilerProblem problem : problems)
{
sb.append(problem.toString());
diff --git a/compiler/src/test/java/as/ASNamespaceTests.java b/compiler/src/test/java/as/ASNamespaceTests.java
index 0c91d58..40dca57 100644
--- a/compiler/src/test/java/as/ASNamespaceTests.java
+++ b/compiler/src/test/java/as/ASNamespaceTests.java
@@ -41,7 +41,7 @@
{
imports = new String[]
{
- "import chrome.app;",
+ "import Intl.Collator;",
};
}
String[] testCode;
@@ -60,10 +60,10 @@
else
{
testCode = new String[]{
- "var foo:app = new app();",
- "var bar:chrome.app = new chrome.app();",
- "var b1:Boolean = bar is app;",
- "var b2:Boolean = foo is chrome.app;",
+ "var foo:Collator = new Collator();",
+ "var bar:Intl.Collator = new Intl.Collator();",
+ "var b1:Boolean = bar is Collator;",
+ "var b2:Boolean = foo is Intl.Collator;",
"assertEqual('package qualifiers', b1, true);",
"assertEqual('package qualifiers', b2, true);",
};
diff --git a/compiler/src/test/java/as/ASPrivateConstructorTests.java b/compiler/src/test/java/as/ASPrivateConstructorTests.java
new file mode 100644
index 0000000..7981155
--- /dev/null
+++ b/compiler/src/test/java/as/ASPrivateConstructorTests.java
@@ -0,0 +1,631 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package as;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ASPrivateConstructorTests extends ASFeatureTestsBase
+{
+ @Test
+ public void testConstructorMustBePublicProblem_withPrivateConstructor_andAllowPrivateConstructorsDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because private constructors have not been enabled
+ "private function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=false"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public\n");
+ }
+
+ @Test
+ public void testConstructorMustBePublicProblem_withProtectedConstructor_andAllowPrivateConstructorsDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because protected constructors are not allowed
+ "protected function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=false"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public\n");
+ }
+
+ @Test
+ public void testConstructorMustBePublicProblem_withInternalConstructor_andAllowPrivateConstructorsDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because internal constructors are not allowed
+ "internal function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=false"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public\n");
+ }
+
+ @Test
+ public void testConstructorMustBePublicProblem_withMetadata_andAllowPrivateConstructorsDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ //error because private constructors have not been enabled
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "public function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=false"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public\n");
+ }
+
+ @Test
+ public void testConstructorMustBePublicProblemAndInaccessibleConstructorReferenceProblem_withPrivateConstructor_andAllowPrivateConstructorsDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ //no error because the constructor cannot be private
+ "new A()"
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because private constructors have not been enabled
+ "private function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=false"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public\n");
+ }
+
+ @Test
+ public void testConstructorMustBePublicProblemAndInaccessibleConstructorReferenceProblem_withMetadata_andAllowPrivateConstructorsDisabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ //no error because the constructor cannot be private
+ "new A()"
+ };
+ String[] extra = new String[]
+ {
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ //error because private constructors have not been enabled
+ "private function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=false"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public\n");
+ }
+
+ @Test
+ public void testNoConstructorMustBePublicOrPrivateProblem_withPrivateConstructor_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ "private function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testConstructorMustBePublicOrPrivateProblem_withProtectedConstructor_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because protected constructors are not allowed
+ "protected function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public or private\n");
+ }
+
+ @Test
+ public void testConstructorMustBePublicOrPrivateProblem_withInternalConstructor_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ //error because internal constructors are not allowed
+ "internal function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "A constructor can only be declared public or private\n");
+ }
+
+ @Test
+ public void testNoConstructorMustBePublicOrPrivateProblem_withMetadata_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ //error because private constructors have not been enabled
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "public function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testInaccessibleConstructorReferenceProblem_withPrivateConstructor_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ //error because the constructor is private
+ "new A()"
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ "private function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "Attempted access of inaccessible constructor through a reference with static type A.\n");
+ }
+
+ @Test
+ public void testInaccessibleConstructorReferenceProblem_withMetadata_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ //error because the constructor is private
+ "new A()"
+ };
+ String[] extra = new String[]
+ {
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "private function A() {",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "Attempted access of inaccessible constructor through a reference with static type A.\n");
+ }
+
+ @Test
+ public void testInaccessibleConstructorReferenceProblem_withPrivateConstructor_inFilePrivateArea_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ "private function A() {",
+ "}",
+ "}",
+ //error because the constructor is private
+ "new A()"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "Attempted access of inaccessible constructor through a reference with static type A.\n");
+ }
+
+ @Test
+ public void testInaccessibleConstructorReferenceProblem_withMetadata_inFilePrivateArea_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "private function A() {",
+ "}",
+ "}",
+ //error because the constructor is private
+ "new A()"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ compileAndExpectErrors(source, false, false, false, options, "Attempted access of inaccessible constructor through a reference with static type A.\n");
+ }
+
+ @Test
+ public void testNoInaccessibleConstructorReferenceProblem_withPrivateConstructor_inMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ "private function A() {",
+ "}",
+ "public function method():Object {",
+ "return new A()",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testNoInaccessibleConstructorReferenceProblem_withMetadata_inMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "private function A() {",
+ "}",
+ "public function method():Object {",
+ "return new A()",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testNoInaccessibleConstructorReferenceProblem_withPrivateConstructor_inStaticMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ "private function A() {",
+ "}",
+ "public static function method():Object {",
+ "return new A()",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testNoInaccessibleConstructorReferenceProblem_withMetadata_inStaticMethodOfSameClass_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "private function A() {",
+ "}",
+ "public static function method():Object {",
+ "return new A()",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testNoInaccessibleConstructorReferenceProblem_withPrivateConstructor_inGetterOfSameClass_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "class A {",
+ "private function A() {",
+ "}",
+ "public function get getter():Object {",
+ "return new A()",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+
+ @Test
+ public void testNoInaccessibleConstructorReferenceProblem_withMetadata_inGetterOfSameClass_andAllowPrivateConstructorsEnabled()
+ {
+ String[] imports = new String[]
+ {
+ };
+ String[] declarations = new String[]
+ {
+ };
+ String[] testCode = new String[]
+ {
+ };
+ String[] extra = new String[]
+ {
+ "[RoyalePrivateConstructor]",
+ "class A {",
+ "private function A() {",
+ "}",
+ "public function get getter():Object {",
+ "return new A()",
+ "}",
+ "}"
+ };
+ String source = getAS(imports, declarations, testCode, extra);
+ String[] options = new String[]
+ {
+ "-allow-private-constructors=true"
+ };
+ File tempASFile = generateTempFile(source);
+ String result = compile(tempASFile, source, false, false, false, options, true);
+ Assert.assertEquals("", result);
+ }
+}
\ No newline at end of file
diff --git a/compiler/src/test/java/mxml/tags/MXMLFeatureTestsBase.java b/compiler/src/test/java/mxml/tags/MXMLFeatureTestsBase.java
index 3c7e343..c46ba75 100644
--- a/compiler/src/test/java/mxml/tags/MXMLFeatureTestsBase.java
+++ b/compiler/src/test/java/mxml/tags/MXMLFeatureTestsBase.java
@@ -52,6 +52,7 @@
*
* @author Gordon Smith
*/
+@SuppressWarnings("deprecation")
public class MXMLFeatureTestsBase
{
private static boolean generateResultFile = false;
diff --git a/compiler/src/test/java/org/apache/royale/compiler/internal/css/CSSStringPropertyValueTests.java b/compiler/src/test/java/org/apache/royale/compiler/internal/css/CSSStringPropertyValueTests.java
index df1b1b8..930f03b 100644
--- a/compiler/src/test/java/org/apache/royale/compiler/internal/css/CSSStringPropertyValueTests.java
+++ b/compiler/src/test/java/org/apache/royale/compiler/internal/css/CSSStringPropertyValueTests.java
@@ -26,7 +26,6 @@
import java.util.List;
import org.apache.royale.compiler.css.ICSSPropertyValue;
-import org.junit.Ignore;
import org.junit.Test;
/**
diff --git a/compiler/src/test/resources/swfdumps/as_ASNamespaceTests_ASNamespace_package_swfdump.xml b/compiler/src/test/resources/swfdumps/as_ASNamespaceTests_ASNamespace_package_swfdump.xml
index 84fe835..159752e 100644
--- a/compiler/src/test/resources/swfdumps/as_ASNamespaceTests_ASNamespace_package_swfdump.xml
+++ b/compiler/src/test/resources/swfdumps/as_ASNamespaceTests_ASNamespace_package_swfdump.xml
@@ -72,20 +72,20 @@
succs=[]
0 getlocal0
1 pushscope
- 2 findpropstrict chrome::app
+ 2 findpropstrict Intl::Collator
3 constructprop
- 4 coerce chrome::app
+ 4 coerce Intl::Collator
5 setlocal2
- 6 findpropstrict chrome::app
+ 6 findpropstrict Intl::Collator
7 constructprop
- 8 coerce chrome::app
+ 8 coerce Intl::Collator
9 setlocal3
10 getlocal3
- 11 getlex chrome::app
+ 11 getlex Intl::Collator
12 istypelate
13 setlocal 4
14 getlocal2
- 15 getlex chrome::app
+ 15 getlex Intl::Collator
16 istypelate
17 setlocal 5
18 findpropstrict assertEqual
diff --git a/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_AnyInitializeUndefined_swfdump.xml b/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_AnyInitializeUndefined_swfdump.xml
index ec1d085..1bdb14a 100644
--- a/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_AnyInitializeUndefined_swfdump.xml
+++ b/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_AnyInitializeUndefined_swfdump.xml
@@ -67,15 +67,15 @@
// max_regs 2
// scope_depth 0
// max_scope 1
- // code_length 14
+ // code_length 12
bb0
succs=[]
0 getlocal0
1 pushscope
2 findpropstrict assertEqual
3 pushstring "null"
- 4 pushbyte 0
- 5 pushbyte 0
+ 4 pushundefined
+ 5 pushundefined
6 callpropvoid
7 returnvoid
}
@@ -108,7 +108,7 @@
0 returnvoid
}
- public static const foo:* = 0
+ public static const foo:*
}
function script0$init():*
diff --git a/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_stringInitializeUndefined_swfdump.xml b/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_stringInitializeUndefined_swfdump.xml
index 88f1f0d..f39f57a 100644
--- a/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_stringInitializeUndefined_swfdump.xml
+++ b/compiler/src/test/resources/swfdumps/as_ASVariableTests_ASVariableTests_stringInitializeUndefined_swfdump.xml
@@ -74,7 +74,7 @@
1 pushscope
2 findpropstrict assertEqual
3 pushstring "null"
- 4 pushbyte 0
+ 4 getlex foo
5 pushnull
6 callpropvoid
7 returnvoid
@@ -108,7 +108,7 @@
0 returnvoid
}
- public static const foo:String = "0"
+ public static const foo:String
}
function script0$init():*
diff --git a/compiler-externc/src/test/royale/XML.as b/compiler/src/test/royale/XML.as
similarity index 100%
rename from compiler-externc/src/test/royale/XML.as
rename to compiler/src/test/royale/XML.as
diff --git a/compiler-externc/src/test/royale/XMLList.as b/compiler/src/test/royale/XMLList.as
similarity index 100%
rename from compiler-externc/src/test/royale/XMLList.as
rename to compiler/src/test/royale/XMLList.as
diff --git a/debugger/pom.xml b/debugger/pom.xml
index 798627e..9bad8f8 100644
--- a/debugger/pom.xml
+++ b/debugger/pom.xml
@@ -1,133 +1,139 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>debugger</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: Debugger</name>
-
- <build>
- <plugins>
- <!--
-Do all the JBurg code generation.
--->
- <plugin>
- <groupId>net.sourceforge.jburg</groupId>
- <artifactId>jburg-maven-plugin</artifactId>
- <version>1.10.4</version>
- <extensions>true</extensions>
- <executions>
- <execution>
- <id>generate-debugger</id>
- <goals>
- <goal>generate</goal>
- </goals>
- <configuration>
- <includes>
- <include>AS3DebuggerBURM.jbg</include>
- <!--include>AS3DebuggerCompoundAssignmentRules.jbg</include>
- <include>AS3DebuggerRules.jbg</include-->
- </includes>
- <sourceDirectory>src/main/jburg/flash/tools/debugger/expression</sourceDirectory>
- <outputDirectory>target/generated-sources/jburg/flash/tools/debugger/expression</outputDirectory>
- </configuration>
- </execution>
- </executions>
- <configuration>
- <!-- debug=true generates the "dump" method for Emitters, which is used for debugging -->
- <!--debug>true</debug-->
- </configuration>
- <dependencies>
- <dependency>
- <groupId>net.sourceforge.jburg</groupId>
- <artifactId>jburg</artifactId>
- <version>1.10.3</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-jburg-types</artifactId>
- <version>${compiler-build-tools.version}</version>
- </dependency>
- </dependencies>
- </plugin>
- </plugins>
- </build>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>swfutils</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.6</version>
- </dependency>
-
- <dependency>
- <groupId>args4j</groupId>
- <artifactId>args4j</artifactId>
- <version>2.0.28</version>
- </dependency>
- <dependency>
- <groupId>org.codeartisans</groupId>
- <artifactId>org.json</artifactId>
- <version>20131017</version>
- </dependency>
- <dependency>
- <groupId>com.google.javascript</groupId>
- <artifactId>closure-compiler</artifactId>
- <version>v20151015</version>
- </dependency>
- <dependency>
- <groupId>org.clojure</groupId>
- <artifactId>google-closure-library</artifactId>
- <version>0.0-20150902-b129bb9e</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-build-tools</artifactId>
- <version>${compiler-build-tools.version}</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.10</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>debugger</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: Debugger</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <!--
+Do all the JBurg code generation.
+-->
+ <plugin>
+ <groupId>net.sourceforge.jburg</groupId>
+ <artifactId>jburg-maven-plugin</artifactId>
+ <version>1.10.4</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>generate-debugger</id>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>AS3DebuggerBURM.jbg</include>
+ <!--include>AS3DebuggerCompoundAssignmentRules.jbg</include>
+ <include>AS3DebuggerRules.jbg</include-->
+ </includes>
+ <sourceDirectory>src/main/jburg/flash/tools/debugger/expression</sourceDirectory>
+ <outputDirectory>target/generated-sources/jburg/flash/tools/debugger/expression</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ <configuration>
+ <!-- debug=true generates the "dump" method for Emitters, which is used for debugging -->
+ <!--debug>true</debug-->
+ </configuration>
+ <dependencies>
+ <!-- this needs to be first in order to patch jburg -->
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-jburg-types</artifactId>
+ <version>${compiler-build-tools.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.sourceforge.jburg</groupId>
+ <artifactId>jburg</artifactId>
+ <version>1.10.3</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>swfutils</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
+
+ <dependency>
+ <groupId>args4j</groupId>
+ <artifactId>args4j</artifactId>
+ <version>2.0.28</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codeartisans</groupId>
+ <artifactId>org.json</artifactId>
+ <version>20131017</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.javascript</groupId>
+ <artifactId>closure-compiler</artifactId>
+ <version>v20151015</version>
+ </dependency>
+ <dependency>
+ <groupId>org.clojure</groupId>
+ <artifactId>google-closure-library</artifactId>
+ <version>0.0-20150902-b129bb9e</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-build-tools</artifactId>
+ <version>${compiler-build-tools.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.10</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java
index c9dd112..6c07e10 100644
--- a/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java
+++ b/debugger/src/main/java/flash/tools/debugger/expression/DebuggerUtil.java
@@ -95,6 +95,11 @@
return 0;
}
+ @Override
+ public void setLastModified(long fileDate) {
+ // TODO Auto-generated method stub
+ }
+
public boolean isOpenDocument()
{
return false;
diff --git a/flex-compiler-oem/pom.xml b/flex-compiler-oem/pom.xml
index dd20460..ad80a59 100644
--- a/flex-compiler-oem/pom.xml
+++ b/flex-compiler-oem/pom.xml
@@ -1,52 +1,62 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>flex-compiler-oem</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: OEM Layer</name>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-jx</artifactId>
- <version>0.9.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>swfutils</artifactId>
- <version>0.9.4</version>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>flex-compiler-oem</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: OEM Layer</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-jx</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>swfutils</artifactId>
+ <version>0.9.6</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/jenkins.xml b/jenkins.xml
index 20adafb..ee47846 100644
--- a/jenkins.xml
+++ b/jenkins.xml
@@ -46,7 +46,7 @@
<target name="jflex-download" description="Copies JFlex from JFlex website">
<echo message="Be patient. This takes a few minutes..." />
- <get src="http://jflex.de/${jflex.filename}.zip" dest="${jflex.temp.filename}" verbose="false" />
+ <get src="https://jflex.de/${jflex.filename}.zip" dest="${jflex.temp.filename}" verbose="false" />
<unzip dest="${jflex.root}" src="${jflex.temp.filename}" />
</target>
diff --git a/pom.xml b/pom.xml
index cfe9ec7..7e1dbce 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,634 +1,749 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache</groupId>
- <artifactId>apache</artifactId>
- <version>18</version>
- </parent>
-
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- <packaging>pom</packaging>
-
- <name>Apache Royale: Compiler: Parent</name>
- <description>The Apache Royale Project</description>
-
- <scm>
- <connection>scm:git:git@github.com:apache/royale-compiler.git</connection>
- <developerConnection>scm:git:git@github.com:apache/royale-compiler.git</developerConnection>
- <url>scm:git:git@github.com:apache/royale-compiler.git</url>
- <tag>org.apache.royale.compiler-0.9.4-rc2</tag>
- </scm>
-
- <properties>
- <java.version>1.6</java.version>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <project.reporting.outputencoding>UTF-8</project.reporting.outputencoding>
- <maven.version>3.3.1</maven.version>
-
- <flex.version>4.15.0</flex.version>
- <flash.version>20.0</flash.version>
- <air.version>20.0</air.version>
-
- <jburgTypesRequired>true</jburgTypesRequired>
- <compiler-build-tools.version>1.0.0</compiler-build-tools.version>
- <compiler-jburg-types.version>1.0.0</compiler-jburg-types.version>
-
- <!-- URL of the ASF SonarQube server -->
- <sonar.host.url>https://builds.apache.org/analysis</sonar.host.url>
- <!-- Tell sonar where the coverage reports are located -->
- <sonar.jacoco.reportPath>${project.build.directory}/coverage-reports/jacoco-ut.exec</sonar.jacoco.reportPath>
- <sonar.jacoco.itReportPath>${project.build.directory}/coverage-reports/jacoco-it.exec</sonar.jacoco.itReportPath>
- <!-- Exclude all generated code -->
- <sonar.exclusions>file:**/generated-sources/**</sonar.exclusions>
-
- <website.path>latest-dev</website.path>
- </properties>
-
- <!-- Only configure the site distribution as the rest is handled by the apache parent -->
- <distributionManagement>
- <site>
- <id>apache.website</id>
- <url>scm:git:https://github.com/apache/royale-compiler.git</url>
- </site>
- </distributionManagement>
-
- <issueManagement>
- <system>GitHub</system>
- <url>https://github.com/apache/royale-compiler/issues</url>
- </issueManagement>
-
- <mailingLists>
- <mailingList>
- <name>Apache Royale User List</name>
- <subscribe>users-subscribe@royale.apache.org</subscribe>
- <unsubscribe>users-unsubscribe@royale.apache.org</unsubscribe>
- <post>users@royale.apache.org</post>
- <archive>http://mail-archives.apache.org/mod_mbox/royale-users/</archive>
- </mailingList>
- <mailingList>
- <name>Apache Royale Developer List</name>
- <subscribe>dev-subscribe@royale.apache.org</subscribe>
- <unsubscribe>dev-unsubscribe@royale.apache.org</unsubscribe>
- <post>dev@royale.apache.org</post>
- <archive>http://mail-archives.apache.org/mod_mbox/royale-dev/</archive>
- </mailingList>
- </mailingLists>
-
- <!--
- As the compiler build uses the jburg plugin which has a dependency on
- the compiler-jburg-types artifact that are part of this project. We therefore have
- a utils profile, that builds these these artifacts so Maven doesn't fail
- as it resolves plugin dependencies before starting the build.
- After one build with "-P -main,utils" (don't use main profile, use utils profile
- has been built, the default build should be able to do it's job.
- -->
- <profiles>
- <profile>
- <id>utils</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <properties>
- <jburgTypesRequired>false</jburgTypesRequired>
- </properties>
- <modules>
- <module>compiler-build-tools</module>
- <module>compiler-jburg-types</module>
- </modules>
- </profile>
- <profile>
- <id>main</id>
- <activation>
- <activeByDefault>true</activeByDefault>
- </activation>
- <modules>
- <module>compiler-common</module>
- <module>compiler-externc</module>
- <module>compiler</module>
- <module>compiler-jx</module>
- <module>compiler-test-utils</module>
- <module>swfutils</module>
- <module>debugger</module>
- <module>flex-compiler-oem</module>
- <module>royale-ant-tasks</module>
- <!--<module>royale-maven-extension</module>-->
- <module>royale-maven-plugin</module>
- </modules>
- <build>
- <plugins>
- <plugin>
- <groupId>net.sourceforge.jburg</groupId>
- <artifactId>jburg-maven-plugin</artifactId>
- <version>1.10.4</version>
- <dependencies>
- <dependency>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>compiler-jburg-types</artifactId>
- <version>${compiler-jburg-types.version}</version>
- </dependency>
- </dependencies>
- </plugin>
- </plugins>
- </build>
- </profile>
- <profile>
- <id>apache-release</id>
- <activation>
- <activeByDefault>false</activeByDefault>
- </activation>
- <properties>
- <website.path>${project.version}</website.path>
- </properties>
- </profile>
- </profiles>
-
- <build>
- <plugins>
- <!-- Check if all source files have the required apache license headers -->
- <plugin>
- <groupId>org.apache.rat</groupId>
- <artifactId>apache-rat-plugin</artifactId>
- <version>0.12</version>
- <executions>
- <execution>
- <id>license-check</id>
- <phase>verify</phase>
- <goals>
- <goal>check</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <excludes>
- <exclude>LICENSE*</exclude>
- <exclude>NOTICE*</exclude>
- <exclude>README*</exclude>
- <exclude>RELEASE_NOTES*</exclude>
- <!-- Modules which are excluded from the build -->
- <!-- FlashBuilder settings. frameworks/fb.properties contains Alex' path entries and should be removed -->
- <exclude>fb.properties</exclude>
- <!-- FlashBuilder / Eclipse settings. If checked in, they should have apache headers -->
- <exclude>**/.settings/**</exclude>
- <exclude>**/*.classpath</exclude>
- <exclude>**/*.project</exclude>
- <!-- Ignore IntelliJ IDEA project files -->
- <exclude>**/*.iml</exclude>
- <exclude>**/.idea/**</exclude>
- <!-- Ignore VSCode/Java project files -->
- <exclude>**/.factorypath</exclude>
- <!--
- Exclude any eventually existing content of target directories.
- Some times when building with a bigger maven reactor and then
- with a smaller one, RAT will complain about stuff still in the
- target directories. We don't want that.
- -->
- <exclude>**/target/**</exclude>
- <!-- Stuff an Ant build might have left behind. -->
- <exclude>lib/**</exclude>
- <!--
- In case of an ANT based release the typedefs are included as a
- subdirectory. We need to exclude this directory from the compiler checks
- as the typedefs build will handle all content in that directory
- -->
- <exclude>royale-typedefs/**</exclude>
- </excludes>
- </configuration>
- <dependencies>
- <dependency>
- <groupId>org.apache.maven.doxia</groupId>
- <artifactId>doxia-core</artifactId>
- <version>1.6</version>
- <exclusions>
- <exclusion>
- <groupId>xerces</groupId>
- <artifactId>xercesImpl</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- </dependencies>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-dependency-plugin</artifactId>
- <version>3.0.0</version>
- <executions>
- <execution>
- <id>analyze</id>
- <goals>
- <goal>analyze-only</goal>
- </goals>
- <configuration>
- <failOnWarning>false</failOnWarning>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>3.5.1</version>
- <configuration>
- <source>${java.version}</source>
- <target>${java.version}</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.jacoco</groupId>
- <artifactId>jacoco-maven-plugin</artifactId>
- <version>0.7.9</version>
- <executions>
- <!--
- Prepares the property pointing to the JaCoCo runtime agent which
- is passed as VM argument when Maven the Surefire plugin is executed.
- -->
- <execution>
- <id>pre-unit-test</id>
- <goals>
- <goal>prepare-agent</goal>
- </goals>
- <configuration>
- <!-- Sets the path to the file which contains the execution data. -->
- <destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
- <!--
- Sets the name of the property containing the settings
- for JaCoCo runtime agent.
- -->
- <propertyName>surefireArgLine</propertyName>
- </configuration>
- </execution>
- <!--
- Ensures that the code coverage report for unit tests is created after
- unit tests have been run.
- -->
- <execution>
- <id>post-unit-test</id>
- <phase>test</phase>
- <goals>
- <goal>report</goal>
- </goals>
- <configuration>
- <!-- Sets the path to the file which contains the execution data. -->
- <dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
- <!-- Sets the output directory for the code coverage report. -->
- <outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
- </configuration>
- </execution>
- <!--
- Prepares the property pointing to the JaCoCo runtime agent which
- is passed as VM argument when Maven the Failsafe plugin is executed.
- -->
- <execution>
- <id>pre-integration-test</id>
- <phase>pre-integration-test</phase>
- <goals>
- <goal>prepare-agent</goal>
- </goals>
- <configuration>
- <!-- Sets the path to the file which contains the execution data. -->
- <destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
- <!--
- Sets the name of the property containing the settings
- for JaCoCo runtime agent.
- -->
- <propertyName>failsafeArgLine</propertyName>
- </configuration>
- </execution>
- <!--
- Ensures that the code coverage report for integration tests after
- integration tests have been run.
- -->
- <execution>
- <id>post-integration-test</id>
- <phase>post-integration-test</phase>
- <goals>
- <goal>report</goal>
- </goals>
- <configuration>
- <!-- Sets the path to the file which contains the execution data. -->
- <dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
- <!-- Sets the output directory for the code coverage report. -->
- <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <!-- Make the surefire execute all unit-tests -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <version>2.19</version>
- <configuration>
- <argLine>${surefireArgLine}</argLine>
- <systemPropertyVariables>
- <buildType>Maven</buildType>
- <flexVersion>${flex.version}</flexVersion>
- <flashVersion>${flash.version}</flashVersion>
- <airVersion>${air.version}</airVersion>
- <mavenLocalRepoDir>${settings.localRepository}</mavenLocalRepoDir>
- </systemPropertyVariables>
- <!--
- Currently some tests need this to be disabled,
- but actually this is a bug. For now I'll disable
- them to avoid problems during the maven migration.
- After this is finished, we should defnitely fix
- the tests so assertions can be enabled.
- -->
- <enableAssertions>false</enableAssertions>
- </configuration>
- </plugin>
-
- <!-- Make the failsafe execute all integration-tests -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-failsafe-plugin</artifactId>
- <version>2.18.1</version>
- <executions>
- <execution>
- <goals>
- <goal>integration-test</goal>
- <goal>verify</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <argLine>${failsafeArgLine}</argLine>
- <systemPropertyVariables>
- <buildType>Maven</buildType>
- <flexVersion>${flex.version}</flexVersion>
- <flashVersion>${flash.version}</flashVersion>
- <airVersion>${air.version}</airVersion>
- <mavenLocalRepoDir>${settings.localRepository}</mavenLocalRepoDir>
- <FLASHPLAYER_DEBUGGER>${env.FLASHPLAYER_DEBUGGER}</FLASHPLAYER_DEBUGGER>
- </systemPropertyVariables>
- </configuration>
- </plugin>
-
- <!-- Plugin to detect problems with JDK incompatibilities -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>animal-sniffer-maven-plugin</artifactId>
- <version>1.15</version>
- <executions>
- <execution>
- <id>check-jdk-1.6</id>
- <phase>test</phase>
- <goals>
- <goal>check</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <signature>
- <groupId>org.codehaus.mojo.signature</groupId>
- <artifactId>java16</artifactId>
- <version>1.1</version>
- </signature>
- </configuration>
- </plugin>
-
- <!-- Configure the Site generation -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-site-plugin</artifactId>
- <!-- Downgraded to 3.4 as 3.5 and 3.5.1 seem to have issues with the velocity tools -->
- <version>3.7.1</version>
- <configuration>
- <generateReports>true</generateReports>
- <generateSitemap>true</generateSitemap>
- <relativizeDecorationLinks>false</relativizeDecorationLinks>
- <locales>en</locales>
- <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
- <outputEncoding>${project.reporting.outputencoding}</outputEncoding>
- </configuration>
- <dependencies>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- <version>2.6</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven.doxia</groupId>
- <artifactId>doxia-core</artifactId>
- <version>1.6</version>
- </dependency>
- <!-- All dependencies needed by the reflow skin -->
- <dependency>
- <groupId>lt.velykis.maven.skins</groupId>
- <artifactId>reflow-velocity-tools</artifactId>
- <version>1.1.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.velocity</groupId>
- <artifactId>velocity</artifactId>
- <version>1.7</version>
- </dependency>
- </dependencies>
- </plugin>
-
- <!--
- Make the maven-site-plugin stage the output in the "asf-site" branch
- -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-scm-publish-plugin</artifactId>
- <version>3.0.0</version>
- <executions>
- <execution>
- <id>scm-publish</id>
- <phase>site-deploy</phase>
- <!-- deploy site with maven-scm-publish-plugin -->
- <goals>
- <goal>publish-scm</goal>
- </goals>
- <configuration>
- <!-- mono-module doesn't require site:stage -->
- <content>${project.build.directory}/site</content>
- <!-- branch where to deploy -->
- <scmBranch>asf-site</scmBranch>
- </configuration>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>2.10.4</version>
- </plugin>
-
- <plugin>
- <groupId>org.sonarsource.scanner.maven</groupId>
- <artifactId>sonar-maven-plugin</artifactId>
- <version>3.2</version>
- </plugin>
- </plugins>
-
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>2.10.4</version>
- <configuration>
- <tags>
- <tag>
- <name>goal</name>
- <placement>a</placement>
- <head>Goal:</head>
- </tag>
- <tag>
- <name>phase</name>
- <placement>a</placement>
- <head>Phase:</head>
- </tag>
- <tag>
- <name>threadSafe</name>
- <placement>a</placement>
- <head>Thread Safe:</head>
- </tag>
- <tag>
- <name>requiresDependencyResolution</name>
- <placement>a</placement>
- <head>Requires Dependency Resolution:</head>
- </tag>
- <tag>
- <name>requiresProject</name>
- <placement>a</placement>
- <head>Requires Project:</head>
- </tag>
- </tags>
- <!-- TODO: This should only be a measure of last resort -->
- <failOnError>false</failOnError>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-scm-plugin</artifactId>
- <version>1.10.0</version>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>3.1.0</version>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
-
- <reporting>
- <plugins>
-
- <!-- Generates a changelog report from GIT commits -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-changelog-plugin</artifactId>
- <version>2.3</version>
- <configuration>
- <!-- Automatically link Jira issues -->
- <issueLinkUrl>https://issues.apache.org/jira/browse/%ISSUE%</issueLinkUrl>
- </configuration>
- </plugin>
-
- <!-- Generates a report with the details of the unit- and integrationtests -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-report-plugin</artifactId>
- <version>2.19.1</version>
- </plugin>
-
- <!-- Generates a report with the test coverages -->
- <plugin>
- <groupId>org.jacoco</groupId>
- <artifactId>jacoco-maven-plugin</artifactId>
- <version>0.7.9</version>
- </plugin>
-
- <!-- Generates a report with the SonarQube analysis reports -->
- <plugin>
- <groupId>org.codehaus.sonar-plugins</groupId>
- <artifactId>maven-report</artifactId>
- <version>0.1</version>
- </plugin>
-
- <!-- Generate the JavaDoc API documentation -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <version>2.10.4</version>
- </plugin>
- </plugins>
- </reporting>
-
- <repositories>
- <repository>
- <id>apache-release</id>
- <url>https://repository.apache.org/content/repositories/releases</url>
- <releases>
- <enabled>true</enabled>
- </releases>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </repository>
- <repository>
- <id>apache-snapshots</id>
- <url>https://repository.apache.org/content/repositories/snapshots</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </repository>
- </repositories>
-
- <pluginRepositories>
- <pluginRepository>
- <id>apache-plugins-release</id>
- <url>https://repository.apache.org/content/repositories/releases</url>
- <releases>
- <enabled>true</enabled>
- </releases>
- <snapshots>
- <enabled>false</enabled>
- </snapshots>
- </pluginRepository>
- <pluginRepository>
- <id>apache-plugins-snapshots</id>
- <url>https://repository.apache.org/content/repositories/snapshots</url>
- <releases>
- <enabled>false</enabled>
- </releases>
- <snapshots>
- <enabled>true</enabled>
- </snapshots>
- </pluginRepository>
- </pluginRepositories>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache</groupId>
+ <artifactId>apache</artifactId>
+ <version>18</version>
+ </parent>
+
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ <packaging>pom</packaging>
+
+ <name>Apache Royale: Compiler: Parent</name>
+ <description>The Apache Royale Project</description>
+
+ <scm>
+ <connection>scm:git:https://github.com/apache/royale-compiler.git</connection>
+ <developerConnection>scm:git:https://github.com/apache/royale-compiler.git</developerConnection>
+ <url>scm:git:https://github.com/apache/royale-compiler.git</url>
+ <tag>org.apache.royale.compiler-0.9.6-rc3</tag>
+ </scm>
+
+ <properties>
+ <java.version>1.6</java.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputencoding>UTF-8</project.reporting.outputencoding>
+ <maven.version>3.3.1</maven.version>
+
+ <flex.version>4.15.0</flex.version>
+ <flash.version>20.0</flash.version>
+ <air.version>20.0</air.version>
+
+ <jburgTypesRequired>true</jburgTypesRequired>
+ <skipgpg>false</skipgpg>
+ <compiler-build-tools.version>1.1.0</compiler-build-tools.version>
+ <compiler-jburg-types.version>1.1.0</compiler-jburg-types.version>
+
+ <!-- URL of the ASF SonarQube server -->
+ <sonar.host.url>https://builds.apache.org/analysis</sonar.host.url>
+ <!-- Tell sonar where the coverage reports are located -->
+ <sonar.jacoco.reportPath>${project.build.directory}/coverage-reports/jacoco-ut.exec</sonar.jacoco.reportPath>
+ <sonar.jacoco.itReportPath>${project.build.directory}/coverage-reports/jacoco-it.exec</sonar.jacoco.itReportPath>
+ <!-- Exclude all generated code -->
+ <sonar.exclusions>file:**/generated-sources/**</sonar.exclusions>
+
+ <website.path>latest-dev</website.path>
+ </properties>
+
+ <!-- Only configure the site distribution as the rest is handled by the apache parent -->
+ <distributionManagement>
+ <site>
+ <id>apache.website</id>
+ <url>scm:git:https://github.com/apache/royale-compiler.git</url>
+ </site>
+ </distributionManagement>
+
+ <issueManagement>
+ <system>GitHub</system>
+ <url>https://github.com/apache/royale-compiler/issues</url>
+ </issueManagement>
+
+ <mailingLists>
+ <mailingList>
+ <name>Apache Royale User List</name>
+ <subscribe>users-subscribe@royale.apache.org</subscribe>
+ <unsubscribe>users-unsubscribe@royale.apache.org</unsubscribe>
+ <post>users@royale.apache.org</post>
+ <archive>http://mail-archives.apache.org/mod_mbox/royale-users/</archive>
+ </mailingList>
+ <mailingList>
+ <name>Apache Royale Developer List</name>
+ <subscribe>dev-subscribe@royale.apache.org</subscribe>
+ <unsubscribe>dev-unsubscribe@royale.apache.org</unsubscribe>
+ <post>dev@royale.apache.org</post>
+ <archive>http://mail-archives.apache.org/mod_mbox/royale-dev/</archive>
+ </mailingList>
+ </mailingLists>
+
+ <!--
+ As the compiler build uses the jburg plugin which has a dependency on
+ the compiler-jburg-types artifact that are part of this project. We therefore have
+ a utils profile, that builds these these artifacts so Maven doesn't fail
+ as it resolves plugin dependencies before starting the build.
+ After one build with "-P -main,utils" (don't use main profile, use utils profile
+ has been built, the default build should be able to do it's job.
+ -->
+ <profiles>
+ <profile>
+ <id>utils</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <properties>
+ <jburgTypesRequired>false</jburgTypesRequired>
+ </properties>
+ <modules>
+ <module>compiler-build-tools</module>
+ <module>compiler-jburg-types</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <configuration>
+ <skip>${skipgpg}</skip><!--true to skip gpg if building release on CI server -->
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.3</version>
+ <configuration>
+ <providerImplementations>
+ <git>jgit</git>
+ </providerImplementations>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.scm</groupId>
+ <artifactId>maven-scm-provider-jgit</artifactId>
+ <version>1.11.2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.scm</groupId>
+ <artifactId>maven-scm-api</artifactId>
+ <version>1.11.2-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>main</id>
+ <activation>
+ <activeByDefault>true</activeByDefault>
+ </activation>
+ <modules>
+ <module>compiler-common</module>
+ <module>compiler-externc</module>
+ <module>compiler</module>
+ <module>compiler-jx</module>
+ <module>compiler-test-utils</module>
+ <module>swfutils</module>
+ <module>debugger</module>
+ <module>flex-compiler-oem</module>
+ <module>royale-ant-tasks</module>
+ <module>royaleunit-ant-tasks</module>
+ <!--<module>royale-maven-extension</module>-->
+ <module>royale-maven-plugin</module>
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>net.sourceforge.jburg</groupId>
+ <artifactId>jburg-maven-plugin</artifactId>
+ <version>1.10.4</version>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>compiler-jburg-types</artifactId>
+ <version>${compiler-jburg-types.version}</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>2.5.3</version>
+ <configuration>
+ <providerImplementations>
+ <git>jgit</git>
+ </providerImplementations>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.scm</groupId>
+ <artifactId>maven-scm-provider-jgit</artifactId>
+ <version>1.11.2-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.scm</groupId>
+ <artifactId>maven-scm-api</artifactId>
+ <version>1.11.2-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>apache-release</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <properties>
+ <website.path>${project.version}</website.path>
+ </properties>
+ </profile>
+ <profile>
+ <id>upload-release-to-staging</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <modules><!-- only run on top-level, not for each module -->
+ </modules>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>wagon-maven-plugin</artifactId>
+ <version>2.0.0</version>
+ <configuration>
+ <includes>**</includes>
+ <serverId>apache.releases.https</serverId>
+ <url>https://repository.apache.org/service/local/staging/deploy/maven2</url>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>test-using-swf</id>
+ <dependencies>
+ <dependency>
+ <groupId>com.adobe.flash.framework</groupId>
+ <artifactId>playerglobal</artifactId>
+ <version>${flash.version}</version>
+ <type>swc</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ </profile>
+ </profiles>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <configuration>
+ <skip>${skipgpg}</skip><!--true to skip gpg if building release on CI server -->
+ </configuration>
+ </plugin>
+ <!-- Check if all source files have the required apache license headers -->
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <version>0.12</version>
+ <executions>
+ <execution>
+ <id>license-check</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <excludes>
+ <exclude>LICENSE*</exclude>
+ <exclude>NOTICE*</exclude>
+ <exclude>README*</exclude>
+ <exclude>RELEASE_NOTES*</exclude>
+ <!-- Modules which are excluded from the build -->
+ <!-- FlashBuilder settings. frameworks/fb.properties contains Alex' path entries and should be removed -->
+ <exclude>fb.properties</exclude>
+ <!-- FlashBuilder / Eclipse settings. If checked in, they should have apache headers -->
+ <exclude>**/.settings/**</exclude>
+ <exclude>**/*.classpath</exclude>
+ <exclude>**/*.project</exclude>
+ <!-- Ignore IntelliJ IDEA project files -->
+ <exclude>**/*.iml</exclude>
+ <exclude>**/.idea/**</exclude>
+ <!-- Ignore VSCode/Java project files -->
+ <exclude>**/.factorypath</exclude>
+ <!--
+ Exclude any eventually existing content of target directories.
+ Some times when building with a bigger maven reactor and then
+ with a smaller one, RAT will complain about stuff still in the
+ target directories. We don't want that.
+ -->
+ <exclude>**/target/**</exclude>
+ <exclude>**/release-dir/**</exclude>
+ <!-- Stuff an Ant build might have left behind. -->
+ <exclude>lib/**</exclude>
+ <!--
+ In case of an ANT based release the typedefs are included as a
+ subdirectory. We need to exclude this directory from the compiler checks
+ as the typedefs build will handle all content in that directory
+ -->
+ <exclude>royale-typedefs/**</exclude>
+ <!-- This file is used to get reproducible builds. See royale-maven-plugin/pom.xml
+ for more info.
+ -->
+ <exclude>**/src/main/sisu/javax.inject.Named</exclude>
+ </excludes>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ <version>1.6</version>
+ <exclusions>
+ <exclusion>
+ <groupId>xerces</groupId>
+ <artifactId>xercesImpl</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>3.0.0</version>
+ <executions>
+ <execution>
+ <id>analyze</id>
+ <goals>
+ <goal>analyze-only</goal>
+ </goals>
+ <configuration>
+ <failOnWarning>false</failOnWarning>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.5.1</version>
+ <configuration>
+ <source>${java.version}</source>
+ <target>${java.version}</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.7.9</version>
+ <executions>
+ <!--
+ Prepares the property pointing to the JaCoCo runtime agent which
+ is passed as VM argument when Maven the Surefire plugin is executed.
+ -->
+ <execution>
+ <id>pre-unit-test</id>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ <configuration>
+ <!-- Sets the path to the file which contains the execution data. -->
+ <destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
+ <!--
+ Sets the name of the property containing the settings
+ for JaCoCo runtime agent.
+ -->
+ <propertyName>surefireArgLine</propertyName>
+ </configuration>
+ </execution>
+ <!--
+ Ensures that the code coverage report for unit tests is created after
+ unit tests have been run.
+ -->
+ <execution>
+ <id>post-unit-test</id>
+ <phase>test</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ <configuration>
+ <!-- Sets the path to the file which contains the execution data. -->
+ <dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
+ <!-- Sets the output directory for the code coverage report. -->
+ <outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
+ </configuration>
+ </execution>
+ <!--
+ Prepares the property pointing to the JaCoCo runtime agent which
+ is passed as VM argument when Maven the Failsafe plugin is executed.
+ -->
+ <execution>
+ <id>pre-integration-test</id>
+ <phase>pre-integration-test</phase>
+ <goals>
+ <goal>prepare-agent</goal>
+ </goals>
+ <configuration>
+ <!-- Sets the path to the file which contains the execution data. -->
+ <destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
+ <!--
+ Sets the name of the property containing the settings
+ for JaCoCo runtime agent.
+ -->
+ <propertyName>failsafeArgLine</propertyName>
+ </configuration>
+ </execution>
+ <!--
+ Ensures that the code coverage report for integration tests after
+ integration tests have been run.
+ -->
+ <execution>
+ <id>post-integration-test</id>
+ <phase>post-integration-test</phase>
+ <goals>
+ <goal>report</goal>
+ </goals>
+ <configuration>
+ <!-- Sets the path to the file which contains the execution data. -->
+ <dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
+ <!-- Sets the output directory for the code coverage report. -->
+ <outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <!-- Make the surefire execute all unit-tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.19</version>
+ <configuration>
+ <argLine>${surefireArgLine}</argLine>
+ <systemPropertyVariables>
+ <buildType>Maven</buildType>
+ <flexVersion>${flex.version}</flexVersion>
+ <flashVersion>${flash.version}</flashVersion>
+ <airVersion>${air.version}</airVersion>
+ <mavenLocalRepoDir>${settings.localRepository}</mavenLocalRepoDir>
+ </systemPropertyVariables>
+ <!--
+ Currently some tests need this to be disabled,
+ but actually this is a bug. For now I'll disable
+ them to avoid problems during the maven migration.
+ After this is finished, we should defnitely fix
+ the tests so assertions can be enabled.
+ -->
+ <enableAssertions>false</enableAssertions>
+ </configuration>
+ </plugin>
+
+ <!-- Make the failsafe execute all integration-tests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.18.1</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <argLine>${failsafeArgLine}</argLine>
+ <systemPropertyVariables>
+ <buildType>Maven</buildType>
+ <flexVersion>${flex.version}</flexVersion>
+ <flashVersion>${flash.version}</flashVersion>
+ <airVersion>${air.version}</airVersion>
+ <mavenLocalRepoDir>${settings.localRepository}</mavenLocalRepoDir>
+ <FLASHPLAYER_DEBUGGER>${env.FLASHPLAYER_DEBUGGER}</FLASHPLAYER_DEBUGGER>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+
+ <!-- Plugin to detect problems with JDK incompatibilities -->
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>animal-sniffer-maven-plugin</artifactId>
+ <version>1.15</version>
+ <executions>
+ <execution>
+ <id>check-jdk-1.6</id>
+ <phase>test</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <signature>
+ <groupId>org.codehaus.mojo.signature</groupId>
+ <artifactId>java16</artifactId>
+ <version>1.1</version>
+ </signature>
+ </configuration>
+ </plugin>
+
+ <!-- Configure the Site generation -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-site-plugin</artifactId>
+ <!-- Downgraded to 3.4 as 3.5 and 3.5.1 seem to have issues with the velocity tools -->
+ <version>3.7.1</version>
+ <configuration>
+ <generateReports>true</generateReports>
+ <generateSitemap>true</generateSitemap>
+ <relativizeDecorationLinks>false</relativizeDecorationLinks>
+ <locales>en</locales>
+ <inputEncoding>${project.build.sourceEncoding}</inputEncoding>
+ <outputEncoding>${project.reporting.outputencoding}</outputEncoding>
+ </configuration>
+ <dependencies>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ <version>1.6</version>
+ </dependency>
+ <!-- All dependencies needed by the reflow skin -->
+ <dependency>
+ <groupId>lt.velykis.maven.skins</groupId>
+ <artifactId>reflow-velocity-tools</artifactId>
+ <version>1.1.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ <version>1.7</version>
+ </dependency>
+ </dependencies>
+ </plugin>
+
+ <!--
+ Make the maven-site-plugin stage the output in the "asf-site" branch
+ -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-publish-plugin</artifactId>
+ <version>3.0.0</version>
+ <executions>
+ <execution>
+ <id>scm-publish</id>
+ <phase>site-deploy</phase>
+ <!-- deploy site with maven-scm-publish-plugin -->
+ <goals>
+ <goal>publish-scm</goal>
+ </goals>
+ <configuration>
+ <!-- mono-module doesn't require site:stage -->
+ <content>${project.build.directory}/site</content>
+ <!-- branch where to deploy -->
+ <scmBranch>asf-site</scmBranch>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ </plugin>
+
+ <plugin>
+ <groupId>org.sonarsource.scanner.maven</groupId>
+ <artifactId>sonar-maven-plugin</artifactId>
+ <version>3.2</version>
+ </plugin>
+ </plugins>
+
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>strip-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ <configuration>
+ <tags>
+ <tag>
+ <name>goal</name>
+ <placement>a</placement>
+ <head>Goal:</head>
+ </tag>
+ <tag>
+ <name>phase</name>
+ <placement>a</placement>
+ <head>Phase:</head>
+ </tag>
+ <tag>
+ <name>threadSafe</name>
+ <placement>a</placement>
+ <head>Thread Safe:</head>
+ </tag>
+ <tag>
+ <name>requiresDependencyResolution</name>
+ <placement>a</placement>
+ <head>Requires Dependency Resolution:</head>
+ </tag>
+ <tag>
+ <name>requiresProject</name>
+ <placement>a</placement>
+ <head>Requires Project:</head>
+ </tag>
+ </tags>
+ <!-- TODO: This should only be a measure of last resort -->
+ <failOnError>false</failOnError>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-scm-plugin</artifactId>
+ <version>1.10.0</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.1.0</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+
+ <reporting>
+ <plugins>
+
+ <!-- Generates a changelog report from GIT commits -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-changelog-plugin</artifactId>
+ <version>2.3</version>
+ <configuration>
+ <!-- Automatically link Jira issues -->
+ <issueLinkUrl>https://issues.apache.org/jira/browse/%ISSUE%</issueLinkUrl>
+ </configuration>
+ </plugin>
+
+ <!-- Generates a report with the details of the unit- and integrationtests -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ <version>2.19.1</version>
+ </plugin>
+
+ <!-- Generates a report with the test coverages -->
+ <plugin>
+ <groupId>org.jacoco</groupId>
+ <artifactId>jacoco-maven-plugin</artifactId>
+ <version>0.7.9</version>
+ </plugin>
+
+ <!-- Generates a report with the SonarQube analysis reports -->
+ <plugin>
+ <groupId>org.codehaus.sonar-plugins</groupId>
+ <artifactId>maven-report</artifactId>
+ <version>0.1</version>
+ </plugin>
+
+ <!-- Generate the JavaDoc API documentation -->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.10.4</version>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <repositories>
+ <repository>
+ <id>apache-release</id>
+ <url>https://repository.apache.org/content/repositories/releases</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>apache-snapshots</id>
+ <url>https://repository.apache.org/content/repositories/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <pluginRepositories>
+ <pluginRepository>
+ <id>apache-plugins-release</id>
+ <url>https://repository.apache.org/content/repositories/releases</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </pluginRepository>
+ <pluginRepository>
+ <id>apache-plugins-snapshots</id>
+ <url>https://repository.apache.org/content/repositories/snapshots</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </pluginRepository>
+ </pluginRepositories>
+
+</project>
diff --git a/releasecandidate.xml b/releasecandidate.xml
index e4a50a8..d26e637 100644
--- a/releasecandidate.xml
+++ b/releasecandidate.xml
@@ -52,8 +52,8 @@
<property name="rat.report" value="${basedir}/rat-report.txt"/>
<property name="apache.rat.jar" value="apache-rat-0.11.jar" />
<property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.11.jar" />
- <property name="apache.rat.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" />
- <property name="apache.rat.tasks.url" value="http://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11" />
+ <property name="apache.rat.url" value="https://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" />
+ <property name="apache.rat.tasks.url" value="https://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11" />
<property file="${basedir}/local.properties" />
<property file="${basedir}/build.properties" />
diff --git a/releasesteps.xml b/releasesteps.xml
new file mode 100644
index 0000000..0cc9681
--- /dev/null
+++ b/releasesteps.xml
@@ -0,0 +1,707 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+
+<project name="CreateCompilerReleaseCandidate" default="main" basedir=".">
+
+ <!-- use -Dtag=<tag or commit hash> to build from other than the head -->
+
+ <!-- Required for OSX 10.6 / Snow Leopard Performance. -->
+ <!-- Java 7 on Mac requires OSX 10.7.3 or higher and is 64-bit only -->
+ <!-- local.d32 is set/used in build.properties so this needs to be done first. -->
+ <condition property="local.d32" value="-d32">
+ <and>
+ <os family="windows"/>
+ <equals arg1="${sun.arch.data.model}" arg2="64"/>
+ <equals arg1="${os.arch}" arg2="x86_64"/>
+ <equals arg1="${ant.java.version}" arg2="1.6"/>
+ </and>
+ </condition>
+
+ <condition property="isMac" value="mac">
+ <os family="mac" />
+ </condition>
+ <condition property="isWindows" value="windows">
+ <os family="windows" />
+ </condition>
+ <condition property="isLinux" value="linux">
+ <and>
+ <os family="unix" />
+ <not>
+ <isset property="isMac" />
+ </not>
+ </and>
+ </condition>
+
+ <property name="rat.report" value="${basedir}/rat-report.txt"/>
+ <property name="apache.rat.jar" value="apache-rat-0.11.jar" />
+ <property name="apache.rat.tasks.jar" value="apache-rat-tasks-0.11.jar" />
+ <property name="apache.rat.url" value="https://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat/0.11" />
+ <property name="apache.rat.tasks.url" value="https://search.maven.org/remotecontent?filepath=org/apache/rat/apache-rat-tasks/0.11" />
+
+ <property file="${basedir}/local.properties" />
+ <property file="${basedir}/build.properties" />
+
+ <property environment="env"/>
+
+ <condition property="do.copy.downloads" >
+ <isset property="download.cache.dir" />
+ </condition>
+
+ <condition property="CRLF" value="%0D%0A">
+ <isset property="isWindows" />
+ </condition>
+ <property name="CRLF" value="%0A" />
+
+ <condition property="mvn" value="mvn.cmd">
+ <isset property="isWindows" />
+ </condition>
+ <property name="mvn" value="mvn" />
+
+ <available file="${env.ANT_HOME}/lib/${apache.rat.jar}"
+ type="file"
+ property="apache.rat.found"/>
+ <available file="${env.ANT_HOME}/lib/${apache.rat.tasks.jar}"
+ type="file"
+ property="apache.rat.tasks.found"/>
+
+ <fail message="The release version number is not set. Specify -Drelease.version=<release version (e.g. 0.9.0, 1.0.0, etc)>"
+ unless="release.version"/>
+
+ <target name="install-rat" depends="install-rat.jar,install-rat.tasks.jar" />
+ <target name="install-rat.jar" unless="apache.rat.found">
+ <get src="${apache.rat.url}/${apache.rat.jar}" dest="${env.ANT_HOME}/lib/${apache.rat.jar}" />
+ </target>
+ <target name="install-rat.tasks.jar" unless="apache.rat.tasks.found">
+ <get src="${apache.rat.url}/${apache.rat.tasks.jar}" dest="${env.ANT_HOME}/lib/${apache.rat.tasks.jar}" />
+ </target>
+
+ <target name="rat-taskdef" description="Rat taskdef">
+ <typedef resource="org/apache/rat/anttasks/antlib.xml"
+ uri="antlib:org.apache.rat.anttasks"
+ classpathref="anttask.classpath"/>
+ </target>
+
+ <target name="checkout_tag" if="tag" >
+ <exec executable="${git}" dir="${basedir}" failonerror="true" >
+ <arg value="checkout" />
+ <arg value="${tag}" />
+ </exec>
+ </target>
+
+ <target name="Release_Step_003" depends="get-temp-folder,download-artifacts,unzip-artifacts,build-source,validate-bits">
+ </target>
+ <target name="get-temp-folder">
+ <input
+ message="Enter a temporary folder to store the downloaded artifacts:"
+ addproperty="artifactfolder"/>
+ <mkdir dir="${artifactfolder}" />
+ <available file="${artifactfolder}"
+ type="dir"
+ property="artifact.folder.found"/>
+ <fail message="Could not create artifact folder"
+ unless="artifact.folder.found"/>
+ </target>
+
+ <target name="download-artifacts-utils" if="utils">
+ <get src="http://apacheroyaleci.westus2.cloudapp.azure.com:8080/job/Royale_Release_Step_002a_if_utils/lastSuccessfulBuild/artifact/*zip*/archive.zip" dest="${artifactfolder}/archive_utils.zip" />
+ </target>
+
+ <target name="download-artifacts" if="artifactfolder">
+ <antcall target="download-artifacts-utils" />
+ <get src="http://apacheroyaleci.westus2.cloudapp.azure.com:8080/job/Royale_Release_Step_003/lastSuccessfulBuild/artifact/*zip*/archive.zip" dest="${artifactfolder}/archive.zip" />
+ </target>
+
+ <target name="unzip-artifacts-utils" if="utils">
+ <mkdir dir="${artifactfolder}/artifacts" />
+ <unzip src="${artifactfolder}/archive_utils.zip" dest="${artifactfolder}/artifacts"/>
+ </target>
+ <target name="unzip-artifacts" if="artifactfolder">
+ <antcall target="unzip-artifacts-utils" />
+ <mkdir dir="${artifactfolder}/artifacts" />
+ <unzip src="${artifactfolder}/archive.zip" dest="${artifactfolder}/artifacts"/>
+ </target>
+ <target name="build-source-utils" if="utils">
+ <!-- build these modules -->
+ <exec executable="${mvn}" dir="${artifactfolder}/sources" failonerror="true" >
+ <arg value="clean" />
+ <arg value="install" />
+ <arg value="-P" />
+ <arg value="-main,utils" />
+ </exec>
+ </target>
+ <target name="build-source" >
+ <mkdir dir="${artifactfolder}/sources" />
+ <unzip src="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/royale-compiler-parent/${release.version}/royale-compiler-parent-${release.version}-source-release.zip" dest="${artifactfolder}/sources" >
+ <cutdirsmapper dirs="1" />
+ </unzip>
+
+ <antcall target="build-source-utils" />
+ <!-- build these modules -->
+ <exec executable="${mvn}" dir="${artifactfolder}/sources" failonerror="true" >
+ <arg value="clean" />
+ <arg value="install" />
+ </exec>
+ </target>
+
+ <target name="get-artifact-folder" unless="artifactfolder">
+ <input
+ message="Enter the temporary folder to store the downloaded artifacts:"
+ addproperty="artifactfolder"/>
+ <available file="${artifactfolder}"
+ type="dir"
+ property="artifact.folder.found"/>
+ <fail message="Could not find artifact folder"
+ unless="artifact.folder.found"/>
+ </target>
+
+ <target name="get-utils-version">
+ <xmlproperty file="${artifactfolder}/sources/compiler-jburg-types/pom.xml" prefix="jburg" />
+ <property name="utils.version" value="${jburg.project.version}" />
+ <echo>utils version is ${utils.version}</echo>
+ </target>
+
+ <target name="check-for-utils" unless="utils">
+ <available file="${artifactfolder}/sources/compiler-jburg-types/target/compiler-jburg-types-${utils.version}.jar" property="utils" value="true" />
+ </target>
+
+ <target name="validate-bits" depends="get-artifact-folder,get-utils-version,compare-jars">
+ </target>
+
+ <target name="write-out-maven-utils-jars-list" if="utils" >
+ <delete file="${artifactfolder}/jars.txt" />
+ <!-- this is a comma-delimited, no spaces, no-line-breaks list used to decide which jars
+ to skip in the rat-check of the binaries and which jars to examine before approval -->
+ <property name="jars-list-with-utils" value="compiler-jburg-types,compiler-build-tools,${jars-list}"/>
+ <echo file="${artifactfolder}/jars.txt" message="${jars-list-with-utils}"/>
+ </target>
+
+ <target name="write-out-maven-jars-list" >
+ <delete file="${artifactfolder}/jars.txt" />
+ <!-- this is a comma-delimited, no spaces, no-line-breaks list used to decide which jars
+ to skip in the rat-check of the binaries and which jars to examine before approval -->
+ <property name="jars-list" value="compiler,compiler-common,compiler-externc,compiler-jx,compiler-test-utils,swfutils,debugger,flex-compiler-oem,royale-ant-tasks,royale-maven-plugin"/>
+ <echo file="${artifactfolder}/jars.txt" message="${jars-list}"/>
+ <antcall target="write-out-maven-utils-jars-list" />
+ </target>
+
+ <target name="compare-jars" depends="write-out-maven-jars-list">
+ <!-- comma delimited list, no spaces, not one file per line -->
+ <copy file="${artifactfolder}/jars.txt" tofile="${artifactfolder}/loop.txt" />
+ <ant antfile="releasesteps.xml" target="loopOnce" inheritAll="false" >
+ <property name="artifactfolder" value="${artifactfolder}" />
+ <property name="release.version" value="${release.version}" />
+ <property name="utils.version" value="${utils.version}" />
+ </ant>
+ </target>
+
+ <target name="get-jar-version" >
+ <condition property="jar.version" value="${utils.version}"
+ else="${release.version}">
+ <or>
+ <equals arg1="${thisFile}" arg2="compiler-jburg-types" />
+ <equals arg1="${thisFile}" arg2="compiler-build-tools" />
+ </or>
+ </condition>
+ </target>
+
+ <target name="loopOnce" >
+ <!-- make a copy of the list so we can munge it to
+ get the first item in the list -->
+ <delete file="${artifactfolder}/loop1.txt" />
+ <copy file="${artifactfolder}/loop.txt" tofile="${artifactfolder}/loop1.txt" />
+ <loadfile srcFile="${artifactfolder}/loop.txt" property="checkiflast" />
+ <condition property="islast" value="true">
+ <not>
+ <contains string="${checkiflast}" substring="," />
+ </not>
+ </condition>
+ <antcall target="notlast" />
+ <antcall target="lastone" />
+ </target>
+ <target name="notlast" unless="islast">
+ <loadfile srcFile="${artifactfolder}/loop1.txt" property="echoFile" />
+ <replaceregexp file="${artifactfolder}/loop1.txt" match="^(.*),(.*)" replace="\2" />
+ <loadfile srcFile="${artifactfolder}/loop1.txt" property="thisFile" />
+ <antcall target="compare_files" />
+ <replaceregexp file="${artifactfolder}/loop.txt" match="^(.*),(.*)" replace="\1" />
+ <ant antfile="releasesteps.xml" target="loopOnce" inheritAll="false">
+ <property name="artifactfolder" value="${artifactfolder}" />
+ <property name="release.version" value="${release.version}" />
+ <property name="utils.version" value="${utils.version}" />
+ </ant>
+ </target>
+ <target name="lastone" if="islast">
+ <loadfile srcFile="${artifactfolder}/loop1.txt" property="thisFile" />
+ <antcall target="compare_files" />
+ <delete file="${artifactfolder}/loop.txt" />
+ <delete file="${artifactfolder}/loop1.txt" />
+ </target>
+
+ <target name="compare_files" depends="get-jar-version">
+ <echo>comparing ${thisFile}-${jar.version}</echo>
+ <fail message="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${thisFile}/${jar.version}/${thisFile}-${jar.version}.jar does not exist" >
+ <condition>
+ <not>
+ <resourceexists><file file="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${thisFile}/${jar.version}/${thisFile}-${jar.version}.jar"/></resourceexists>
+ </not>
+ </condition>
+ </fail>
+ <fail message="${artifactfolder}/sources/${thisFile}/target/${thisFile}-${jar.version}.jar does not exist" >
+ <condition>
+ <not>
+ <resourceexists><file file="${artifactfolder}/sources/${thisFile}/target/${thisFile}-${jar.version}.jar"/></resourceexists>
+ </not>
+ </condition>
+ </fail>
+ <condition property="filesmatch" value="true">
+ <filesmatch file1="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${thisFile}/${jar.version}/${thisFile}-${jar.version}.jar"
+ file2="${artifactfolder}/sources/${thisFile}/target/${thisFile}-${jar.version}.jar" />
+ </condition>
+ <fail message="${thisFile}-${jar.version}.jar does not match" unless="filesmatch" />
+ </target>
+
+ <target name="Release_Step_003_Sign" depends="get-artifact-folder">
+ <fail message="release.version not specified"
+ unless="release.version"/>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/royale-compiler-parent/${release.version}/royale-compiler-parent-${release.version}-source-release.zip" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/royale-compiler-parent/${release.version}/royale-compiler-parent-${release.version}.pom" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="compiler" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="compiler-common" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="compiler-externc" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/compiler-externc/${release.version}/compiler-externc-${release.version}-tests.jar" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="compiler-jx" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="compiler-test-utils" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="debugger" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="flex-compiler-oem" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="royale-ant-tasks" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="royale-maven-plugin" />
+ </antcall>
+ <antcall target="sign-jar-artifacts">
+ <param name="jarname" value="royaleunit-ant-tasks" />
+ </antcall>
+ <antcall target="sign-jar-artifacts" >
+ <param name="jarname" value="swfutils" />
+ </antcall>
+ <antcall target="sign-utils" />
+ </target>
+
+ <target name="sign-utils" depends="get-utils-version,check-for-utils" if="utils">
+ <antcall target="sign-utils-jar-artifacts" >
+ <param name="jarname" value="compiler-build-tools" />
+ </antcall>
+ <antcall target="sign-utils-jar-artifacts" >
+ <param name="jarname" value="compiler-jburg-types" />
+ </antcall>
+ </target>
+
+ <target name="sign-jar-artifacts">
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${release.version}/${jarname}-${release.version}.pom" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${release.version}/${jarname}-${release.version}-javadoc.jar" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${release.version}/${jarname}-${release.version}-sources.jar" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${release.version}/${jarname}-${release.version}.jar" />
+ </antcall>
+ </target>
+
+ <target name="sign-utils-jar-artifacts">
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${utils.version}/${jarname}-${utils.version}.pom" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${utils.version}/${jarname}-${utils.version}-javadoc.jar" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${utils.version}/${jarname}-${utils.version}-sources.jar" />
+ </antcall>
+ <antcall target="sign-file" >
+ <param name="file" value="${artifactfolder}/artifacts/archive/target/checkout/release-dir/org/apache/royale/compiler/${jarname}/${utils.version}/${jarname}-${utils.version}.jar" />
+ </antcall>
+ </target>
+
+
+ <target name="sign-file">
+ <exec executable="gpg">
+ <arg value="--armor" />
+ <arg value="--output" />
+ <arg value="${file}.asc" />
+ <arg value="--detach-sig" />
+ <arg value="${file}" />
+ </exec>
+ </target>
+
+ <target name="Release_Step_003_Upload" depends="get-artifact-folder">
+ <fail message="release.version not specified"
+ unless="release.version"/>
+ <exec executable="${mvn}" dir="${artifactfolder}/sources" failonerror="true" >
+ <arg value="wagon:upload" />
+ <arg value="-X" />
+ <arg value="-Dwagon.fromDir=${artifactfolder}/artifacts/archive/target/checkout/release-dir" />
+ <arg value="-P" />
+ <arg value="upload-release-to-staging,-main" />
+ </exec>
+ </target>
+
+ <target name="main" depends="install-rat,credentials" description="Perform required release approval steps">
+ <antcall target="check-new-version" />
+ <exec executable="${git}" dir="${basedir}" failonerror="true" >
+ <arg value="pull" />
+ <arg value="--rebase" />
+ </exec>
+ <antcall target="checkout_tag" />
+ <ant antfile="build.xml" target="release" />
+ <ant antfile="build.xml" target="create-md5" />
+ <ant antfile="build.xml" target="sign" />
+ <mkdir dir="${dist.dev}/royale/compiler/${release.version}/rc${rc}/binaries" />
+ <copy todir="${dist.dev}/royale/compiler/${release.version}/rc${rc}" >
+ <fileset dir="${basedir}/out" >
+ <include name="apache-royale-compiler-${release.version}-src*" />
+ </fileset>
+ </copy>
+ <copy todir="${dist.dev}/royale/compiler/${release.version}/rc${rc}/binaries" >
+ <fileset dir="${basedir}/out" >
+ <include name="apache-royale-compiler-${release.version}-bin*" />
+ </fileset>
+ </copy>
+ <copy file="${basedir}/README" tofile="${dist.dev}/royale/compiler/${release.version}/rc${rc}/READme" />
+ <copy file="${basedir}/ApproveCompiler.xml" tofile="${dist.dev}/royale/compiler/${release.version}/rc${rc}/ApproveCompiler.xml" />
+ <copy file="${basedir}/apache-royale-compiler-installer-config.xml" tofile="${dist.dev}/royale/compiler/${release.version}/rc${rc}/binaries/apache-royale-compiler-installer-config.xml" />
+ <exec executable="${svn}" dir="${dist.dev}/royale/compiler" failonerror="true" >
+ <arg value="update" />
+ </exec>
+ <exec executable="${svn}" dir="${dist.dev}/royale/compiler" failonerror="true" >
+ <arg value="add" />
+ <arg value="${dist.dev}/royale/compiler/${release.version}/rc${rc}" />
+ </exec>
+ <exec executable="${svn}" dir="${dist.dev}/royale/compiler" failonerror="true" >
+ <arg value="commit" />
+ <arg value="--username" />
+ <arg value="${apache.username}" />
+ <arg value="--password" />
+ <arg value="${apache.password}" />
+ <arg value="-m" />
+ <arg value="rc${rc} of Apache Royale Compiler ${release.version}" />
+ </exec>
+ <antcall target="tag_release" />
+ <antcall target="update-installer-config" />
+ <antcall target="mail" />
+ </target>
+
+ <target name="tag_release" unless="tag" >
+ <exec executable="${git}" dir="${basedir}" failonerror="true" >
+ <arg value="tag" />
+ <arg value="-a" />
+ <arg value="apache-royale-compiler-${release.version}-rc${rc}" />
+ <arg value="-m" />
+ <arg value=""rc${rc} of apache-royale-compiler-${release.version}"" />
+ </exec>
+ <exec executable="${git}" dir="${basedir}" failonerror="true" >
+ <arg value="push" />
+ <arg value="--tags" />
+ </exec>
+ </target>
+
+ <target name="credentials" depends="get-username,get-password">
+ <echo>${apache.username}</echo>
+ <echo>${apache.password}</echo>
+ </target>
+ <target name="get-username" unless="apache.username" >
+ <input
+ message="Enter Apache account username:"
+ addproperty="apache.username"/>
+ <condition property="have.username">
+ <not>
+ <equals trim="true" arg1="" arg2="${apache.username}"/>
+ </not>
+ </condition>
+ <fail message="The apache.username property is not set. It should be the username for Apache SVN and Git."
+ unless="have.username"/>
+ </target>
+ <target name="get-password" unless="apache.password" >
+ <input
+ message="Enter Apache account password:"
+ addproperty="apache.password"/>
+ <condition property="have.password">
+ <not>
+ <equals trim="true" arg1="" arg2="${apache.password}"/>
+ </not>
+ </condition>
+ <fail message="The apache.password property is not set. It should be the password for Apache SVN and Git."
+ unless="have.password"/>
+ </target>
+
+ <target name="update-installer-config" >
+ <exec executable="${svn}" dir="${site}" failonerror="true" >
+ <arg value="update" />
+ <arg value="trunk/content/installer/sdk-installer-config-4.0.xml" />
+ </exec>
+ <replaceregexp byline="true">
+ <regexp pattern="developmentVersion="${release.version}" rc="rc.*" latestVersion"/>
+ <substitution expression="developmentVersion="${release.version}" rc="rc${rc}" latestVersion"/>
+ <fileset dir="${site}/trunk/content/installer">
+ <include name="sdk-installer-config-4.0.xml"/>
+ </fileset>
+ </replaceregexp>
+ <exec executable="${svn}" dir="${site}" failonerror="true" >
+ <arg value="commit" />
+ <arg value="--username" />
+ <arg value="${apache.username}" />
+ <arg value="--password" />
+ <arg value="${apache.password}" />
+ <arg value="-m" />
+ <arg value=""update sdk-installer-config-4.0 for Compiler ${release.version} rc${rc}"" />
+ </exec>
+ <!-- pause to give buildbot chance to react -->
+ <sleep seconds="5" />
+ <get src="https://cms.apache.org/royale/publish" username="${apache.username}" password="${apache.password}" dest="${basedir}/getresult.txt" />
+ <delete file="${basedir}/getresult.txt" />
+ </target>
+
+ <target name="update-installer-config-release" depends="credentials">
+ <exec executable="${svn}" dir="${site}" failonerror="true" >
+ <arg value="update" />
+ <arg value="trunk/content/installer/sdk-installer-config-4.0.xml" />
+ </exec>
+ <xmlproperty file="${site}/trunk/content/installer/sdk-installer-config-4.0.xml" semanticAttributes="true" collapseAttributes="true"/>
+ <property name="latest.release" value="${config.products.ApacheRoyaleCompiler.latestVersion}" />
+ <replaceregexp byline="true" flags="g">
+ <regexp pattern="ApacheRoyaleCompiler(.*)latestVersion="${latest.release}"(.*)"/>
+ <substitution expression="ApacheRoyaleCompiler\1latestVersion="${release.version}"\2"/>
+ <fileset dir="${site}/trunk/content/installer">
+ <include name="sdk-installer-config-4.0.xml"/>
+ </fileset>
+ </replaceregexp>
+ <exec executable="${svn}" dir="${site}" failonerror="true" >
+ <arg value="commit" />
+ <arg value="--username" />
+ <arg value="${apache.username}" />
+ <arg value="--password" />
+ <arg value="${apache.password}" />
+ <arg value="-m" />
+ <arg value=""update sdk-installer-config-4.0 and other files for royale sdk ${release.version} rc${rc}"" />
+ </exec>
+ <!-- pause to give buildbot chance to react -->
+ <sleep seconds="5" />
+ <get src="https://cms.apache.org/royale/publish" username="${apache.username}" password="${apache.password}" dest="${basedir}/getresult.txt" />
+ <delete file="${basedir}/getresult.txt" />
+ </target>
+
+ <target name="check-new-version" description="check if svn folder needs to be added" >
+ <condition property="version.folder" value="${dist.dev}/royale/compiler/${release.version}" >
+ <not>
+ <available file="${dist.dev}/royale/compiler/${release.version}" />
+ </not>
+ </condition>
+ <antcall target="add-version-folder" />
+ </target>
+
+ <target name="add-version-folder" description="adds svn folder if needed" if="version.folder" >
+ <mkdir dir="${version.folder}" />
+ <exec executable="${svn}" dir="${dist.dev}/royale/compiler" failonerror="true" >
+ <arg value="add" />
+ <arg value="${version.folder}" />
+ </exec>
+ </target>
+
+ <target name="mail" >
+ <!-- try to set line breaks before the vertical line | -->
+ <echo file="${basedir}/discussthread.properties">discuss.thread.body=This is the discussion thread.\n\
+\n\
+Changes in this RC include:\n\
+\n\
+\n\
+Thanks,\n\
+${my.name}
+</echo>
+ <replace file="${basedir}/discussthread.properties">
+ <replacefilter token=" " value="%20" />
+ <replacefilter token="\n" value="${CRLF}" />
+ </replace>
+ <property file="${basedir}/discussthread.properties" />
+
+ <!-- try to set line breaks before the vertical line | -->
+ <echo file="${basedir}/votethread.properties">vote.thread.body=Hi,\n\
+\n\
+This is vote for the ${release.version} release of the Royale\n\
+compilers. The only purpose of the Compiler packages are to serve as\n\
+upstream packages for the Royale release.\n\
+\n\
+The release candidate can be found here;\n\
+https://dist.apache.org/repos/dist/dev/royale/compiler/${release.version}/rc${rc}/\n\
+\n\
+Before voting please review the section, 'What are the ASF requirements on\n\
+approving a release?', at:\n\
+http://www.apache.org/dev/release.html#approving-a-release\n\
+\n\
+At a minimum you would be expected to check that:\n\
+- MD5 and signed packages are correct\n\
+- README, RELEASE_NOTES, NOTICE and LICENSE files are all fine\n\
+- That the build script completes successfully\n\
+- That you can compile using the results of building the source package\n\
+\n\
+The source package is set up the same way as the repo. This means that\n\
+the results of the build are not the same as the binary package. The\n\
+compiled source package can be used to build Royale apps via the command\n\
+line and Ant, but not in Flash Builder or other IDEs. You can test the source\n\
+package by building it, then pointing to it from the source package of the\n\
+Royale release candidate and building the examples in the Royale package.\n\
+\n\
+The binary package is set up as an upstream package for the Royale\n\
+release. The most convenient way to use the binary package is to install\n\
+a Royale SDK via Ant or the Installer.\n\
+\n\
+Please vote to approve this release:\n\
++1 Approve the release\n\
+-1 Disapprove the release (please provide specific comments to why)\n\
+\n\
+This vote will be open for 72 hours or until a result can be called.\n\
+\n\
+The vote passes if there is:\n\
+- At least 3 +1 votes from the PMC\n\
+- More positive votes than negative votes\n\
+\n\
+Remember that this is a 'beta-quality' release so there\n\
+will be many bugs found. The goal is not to try to find and fix bugs\n\
+in the RC, but to make sure we have the packaging right, and enough\n\
+functionality that folks will have some success trying to use it.\n\
+\n\
+People who are not in PMC are also encouraged to test out the release and\n\
+vote, although their votes will not be binding, they can influence how the\n\
+PMC votes.\n\
+\n\
+When voting please indicate what OS, IDE, Flash Player version and AIR\n\
+version you tested with.\n\
+\n\
+Please put all discussion about this release in the DISCUSSION thread not\n\
+this VOTE thread.\n\
+\n\
+For your convenience there is an ant script that automates the common\n\
+steps to validate a release. Instead of individually downloading the\n\
+package and signature files, unzipping, etc, you can instead:\n\
+1) create an empty folder,\n\
+2) download into that folder this file:\n\
+https://dist.apache.org/repos/dist/dev/royale/compiler/${release.version}/rc${rc}/ApproveCompiler.xml\n\
+3) run the script:\n\
+ ant -e -f ApproveCompiler.xml -Drelease.version=${release.version} -Drc=${rc}\n\
+\n\
+You are not required to use this script, and more testing of the packages\n\
+and build results are always encouraged.\n\
+\n\
+Thanks,\n\
+${my.name}
+</echo>
+ <replace file="${basedir}/votethread.properties">
+ <replacefilter token=" " value="%20" />
+ <replacefilter token="\n" value="${CRLF}" />
+ </replace>
+ <property file="${basedir}/votethread.properties" />
+ <echo file="${basedir}/votethread.html"><html><body><a href="mailto:dev@royale.apache.org?subject=[DISCUSS]%20Discuss%20Release%20Apache%20Royale%20Compiler%20${release.version}%20RC${rc}&body=${discuss.thread.body}">Click here to review discuss thread</a><br/><a href="mailto:dev@royale.apache.org?subject=[VOTE]%20Release%20Apache%20Royale%20Compiler%20${release.version}%20RC${rc}&body=${vote.thread.body}">Click here to review vote thread</a></body></html></echo>
+ <makeurl file="${basedir}/votethread.html" property="vote.thread.url" />
+ <exec executable="${browser}">
+ <arg value="${vote.thread.url}" />
+ </exec>
+ <delete file="${basedir}/votethread.properties" />
+ <delete file="${basedir}/votethread.html" />
+ <delete file="${basedir}/discussthread.properties" />
+ </target>
+
+ <target name="release" depends="credentials" >
+ <available file="${svn.dist.release}"
+ type="dir"
+ property="dist.release" value="${svn.dist.release}" />
+
+ <fail message="The svn.dist.release property is not set to the working copy for https://dist.apache.org/repos/dist/release."
+ unless="dist.release"/>
+
+ <exec executable="${svn}" dir="${dist.release}/royale" failonerror="true" >
+ <arg value="update" />
+ </exec>
+ <exec executable="${svn}" dir="${dist.release}/royale/compiler" failonerror="true" >
+ <arg value="mv" />
+ <arg value="${dist.dev}/royale/compiler/${release.version}/rc${rc}" />
+ <arg value="${dist.release}/royale/compiler/${release.version}" />
+ </exec>
+ <exec executable="${svn}" dir="${dist.release}/.." failonerror="true" >
+ <arg value="commit" />
+ <arg value="--username" />
+ <arg value="${apache.username}" />
+ <arg value="--password" />
+ <arg value="${apache.password}" />
+ <arg value="-m" />
+ <arg value="Apache Royale Compiler ${release.version}" />
+ </exec>
+ <antcall target="release.tag" />
+ <exec executable="${git}" dir="${basedir}" failonerror="true" >
+ <arg value="push" />
+ <arg value="--tags" />
+ </exec>
+ <echo>Wait at least 24 hours before running update-installer-config-release target</echo>
+ </target>
+
+ <target name="release.tag" >
+ <condition property="tag" value="apache-royale-compiler-${release.version}-rc${rc}">
+ <not>
+ <isset property="tag" />
+ </not>
+ </condition>
+ <exec executable="${git}" dir="${basedir}" failonerror="true" output="${basedir}/taghash.txt">
+ <arg value="show" />
+ <arg value="${tag}" />
+ </exec>
+ <replaceregexp file="${basedir}/taghash.txt" match="(.*).commit (.*).Author(.*)" replace="\2" byline="false" flags="s" />
+ <loadfile srcFile="${basedir}/taghash.txt" property="releasehash" />
+ <exec executable="${git}" dir="${basedir}" failonerror="true" >
+ <arg value="tag" />
+ <arg value="-a" />
+ <arg value="apache-royale-compiler-${release.version}" />
+ <arg value="${releasehash}" />
+ <arg value="-m" />
+ <arg value=""Official release of apache-royale-compiler-${release.version}"" />
+ </exec>
+ </target>
+</project>
diff --git a/royale-ant-tasks/pom.xml b/royale-ant-tasks/pom.xml
index ba50956..b15f4d0 100644
--- a/royale-ant-tasks/pom.xml
+++ b/royale-ant-tasks/pom.xml
@@ -1,42 +1,52 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>royale-ant-tasks</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Royale Ant Tasks</name>
-
- <dependencies>
- <dependency>
- <groupId>org.apache.ant</groupId>
- <artifactId>ant</artifactId>
- <version>1.7.0</version>
- </dependency>
- </dependencies>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>royale-ant-tasks</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Royale Ant Tasks</name>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/royale-ant-tasks/src/main/java/org/apache/royale/compiler/ant/FlexTask.java b/royale-ant-tasks/src/main/java/org/apache/royale/compiler/ant/FlexTask.java
index 79f7060..40e119f 100644
--- a/royale-ant-tasks/src/main/java/org/apache/royale/compiler/ant/FlexTask.java
+++ b/royale-ant-tasks/src/main/java/org/apache/royale/compiler/ant/FlexTask.java
@@ -308,9 +308,9 @@
try
{
- Method toolMethod = toolClass.getMethod(toolMethodName, new Class[] {String[].class});
+ Method toolMethod = toolClass.getMethod(toolMethodName, String[].class);
Object result = toolMethod.invoke(null, new Object[] {cmdline.getArguments()});
- exitCode = ((Integer)result).intValue();
+ exitCode = ((Integer)result);
}
catch (Exception e)
{
@@ -337,9 +337,9 @@
try
{
- Method toolFailureMethod = toolClass.getMethod(toolFailureMethodName, new Class[] {int.class});
- Object result = toolFailureMethod.invoke(null, new Object[] {exitCode});
- fatal = ((Boolean)result).booleanValue();
+ Method toolFailureMethod = toolClass.getMethod(toolFailureMethodName, int.class);
+ Object result = toolFailureMethod.invoke(null, exitCode);
+ fatal = ((Boolean)result);
}
catch (Exception e)
{
diff --git a/royale-maven-plugin/pom.xml b/royale-maven-plugin/pom.xml
index e94aa2e..31e6e98 100644
--- a/royale-maven-plugin/pom.xml
+++ b/royale-maven-plugin/pom.xml
@@ -1,135 +1,140 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>royale-maven-plugin</artifactId>
- <version>0.9.4</version>
- <packaging>maven-plugin</packaging>
-
- <name>Apache Royale: Royale Maven Plugin</name>
-
- <properties>
- <maven.version>3.3.1</maven.version>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>javax.inject</groupId>
- <artifactId>javax.inject</artifactId>
- <version>1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-plugin-api</artifactId>
- <version>${maven.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven.plugin-tools</groupId>
- <artifactId>maven-plugin-annotations</artifactId>
- <version>3.4</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Apache Velocity templating engine for generating config files -->
- <dependency>
- <groupId>org.apache.velocity</groupId>
- <artifactId>velocity</artifactId>
- <version>1.7</version>
- </dependency>
-
- <dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-project</artifactId>
- <version>2.2.1</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven</groupId>
- <artifactId>maven-core</artifactId>
- <version>${maven.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.maven.shared</groupId>
- <artifactId>file-management</artifactId>
- <version>3.0.0</version>
- </dependency>
- <dependency>
- <groupId>commons-io</groupId>
- <artifactId>commons-io</artifactId>
- <version>2.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.4</version>
- </dependency>
- <dependency>
- <groupId>org.apache.flex</groupId>
- <artifactId>flex-tool-api</artifactId>
- <version>1.0.0</version>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-plugin-plugin</artifactId>
- <version>3.4</version>
- <configuration>
- <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
- </configuration>
- <executions>
- <execution>
- <id>mojo-descriptor</id>
- <goals>
- <goal>descriptor</goal>
- </goals>
- </execution>
- <execution>
- <id>help-goal</id>
- <goals>
- <goal>helpmojo</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.sonatype.plugins</groupId>
- <artifactId>sisu-maven-plugin</artifactId>
- <version>1.1</version>
- <executions>
- <execution>
- <id>generate-index</id>
- <goals>
- <goal>main-index</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>royale-maven-plugin</artifactId>
+ <version>0.9.6</version>
+ <packaging>maven-plugin</packaging>
+
+ <name>Apache Royale: Royale Maven Plugin</name>
+
+ <properties>
+ <maven.version>3.3.1</maven.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.inject</groupId>
+ <artifactId>javax.inject</artifactId>
+ <version>1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-plugin-api</artifactId>
+ <version>${maven.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.plugin-tools</groupId>
+ <artifactId>maven-plugin-annotations</artifactId>
+ <version>3.4</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Apache Velocity templating engine for generating config files -->
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity</artifactId>
+ <version>1.7</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-project</artifactId>
+ <version>2.2.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-core</artifactId>
+ <version>${maven.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.shared</groupId>
+ <artifactId>file-management</artifactId>
+ <version>3.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ <version>2.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.4</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.flex</groupId>
+ <artifactId>flex-tool-api</artifactId>
+ <version>1.0.0</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-plugin-plugin</artifactId>
+ <version>3.4</version>
+ <configuration>
+ <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
+ </configuration>
+ <executions>
+ <execution>
+ <id>mojo-descriptor</id>
+ <goals>
+ <goal>descriptor</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>help-goal</id>
+ <goals>
+ <goal>helpmojo</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>sisu-maven-plugin</artifactId>
+ <version>1.1</version>
+ <executions>
+ <execution>
+ <id>generate-index</id>
+ <goals>
+ <goal>main-index</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/royale-maven-plugin/src/main/java/org/apache/royale/maven/BaseMojo.java b/royale-maven-plugin/src/main/java/org/apache/royale/maven/BaseMojo.java
index 74af100..c4c91c2 100644
--- a/royale-maven-plugin/src/main/java/org/apache/royale/maven/BaseMojo.java
+++ b/royale-maven-plugin/src/main/java/org/apache/royale/maven/BaseMojo.java
@@ -236,16 +236,22 @@
List<String> args = new LinkedList<String>();
args.add("-load-config=" + configFile.getPath());
if(additionalCompilerOptions != null) {
+ if (additionalCompilerOptions.contains("\n")) {
+ additionalCompilerOptions = additionalCompilerOptions.replace("\n", "");
+ }
if (additionalCompilerOptions.contains(";"))
{
String[] options = additionalCompilerOptions.split(";");
for (String option : options)
{
- args.add(option);
+ if (option.trim().length() > 0)
+ args.add(option.trim());
}
}
- else
- args.add(additionalCompilerOptions);
+ else {
+ if (additionalCompilerOptions.trim().length() > 0)
+ args.add(additionalCompilerOptions.trim());
+ }
}
return args;
}
@@ -331,11 +337,17 @@
}
protected List<Artifact> getJSLibraries(List<Artifact> artifacts) {
- return internalGetLibrariesJS(artifacts);
+ if(!isForceSwcExternalLibraryPath()) {
+ return internalGetLibrariesJS(artifacts);
+ }
+ return Collections.emptyList();
}
protected List<Artifact> getSWFLibraries(List<Artifact> artifacts) {
- return internalGetLibrariesSWF(artifacts);
+ if(!isForceSwcExternalLibraryPath()) {
+ return internalGetLibrariesSWF(artifacts);
+ }
+ return Collections.emptyList();
}
protected List<Artifact> getThemeLibraries(List<Artifact> artifacts) {
@@ -374,6 +386,9 @@
}
}
}
+ if(isForceSwcExternalLibraryPath()) {
+ externalLibraries.addAll(internalGetLibrariesJS(artifacts));
+ }
return externalLibraries;
}
@@ -387,6 +402,9 @@
}
}
}
+ if(isForceSwcExternalLibraryPath()) {
+ externalLibraries.addAll(internalGetLibrariesSWF(artifacts));
+ }
return externalLibraries;
}
diff --git a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASDocMojo.java b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASDocMojo.java
index e2da7dd..5554304 100644
--- a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASDocMojo.java
+++ b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASDocMojo.java
@@ -37,6 +37,9 @@
@Parameter(defaultValue = "false")
private boolean skipASDoc;
+ @Parameter(defaultValue = "false")
+ private boolean skipAS;
+
private ThreadLocal<Type> type = new ThreadLocal<Type>();
@Override
@@ -90,17 +93,20 @@
// compiler will be instantiated in the future. This method is safe in
// any way it could be used (Multiple executions in parallel with Maven).
try {
- // Execute the ASDoc generation for SWF
- getLog().info("Generating SWF apidocs");
- type.set(Type.SWF);
- File outputDirectory = getOutput();
- if (!outputDirectory.exists()) {
- if (!outputDirectory.mkdirs()) {
- throw new MojoExecutionException("Could not create output directory for apidocs " + outputDirectory.getPath());
+ if (!skipAS)
+ {
+ // Execute the ASDoc generation for SWF
+ getLog().info("Generating SWF apidocs");
+ type.set(Type.SWF);
+ File outputDirectory = getOutput();
+ if (!outputDirectory.exists()) {
+ if (!outputDirectory.mkdirs()) {
+ throw new MojoExecutionException("Could not create output directory for apidocs " + outputDirectory.getPath());
+ }
}
+ super.execute();
+ getLog().info("Finished");
}
- super.execute();
- getLog().info("Finished");
// Execute the ASDoc generation for JavaScript
getLog().info("Generating JS apidocs");
diff --git a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASMojo.java b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASMojo.java
index 8f549d5..05c4212 100644
--- a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASMojo.java
+++ b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileASMojo.java
@@ -124,7 +124,7 @@
@Override
protected boolean includeLibrary(Artifact library) {
String classifier = library.getClassifier();
- return (classifier == null) && !("provided".equalsIgnoreCase(library.getScope()));
+ return (classifier == null) && !("runtime".equalsIgnoreCase(library.getScope()));
}
@Override
@@ -138,7 +138,7 @@
protected boolean includeLibrarySWF(Artifact library) {
String classifier = library.getClassifier();
return "swf".equalsIgnoreCase(classifier) ||
- ((classifier == null) && "provided".equalsIgnoreCase(library.getScope()));
+ ((classifier == null) && "runtime".equalsIgnoreCase(library.getScope()));
}
}
diff --git a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileAppMojo.java b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileAppMojo.java
index 7ddfd39..bfc40aa 100644
--- a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileAppMojo.java
+++ b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileAppMojo.java
@@ -170,7 +170,7 @@
@Override
protected boolean includeLibrary(Artifact library) {
String classifier = library.getClassifier();
- return (classifier == null) && !("provided".equalsIgnoreCase(library.getScope()));
+ return (classifier == null) && !("runtime".equalsIgnoreCase(library.getScope()));
}
@Override
@@ -186,7 +186,7 @@
protected boolean includeLibrarySWF(Artifact library) {
String classifier = library.getClassifier();
return "swf".equalsIgnoreCase(classifier) ||
- ((classifier == null) && "provided".equalsIgnoreCase(library.getScope()));
+ ((classifier == null) && "runtime".equalsIgnoreCase(library.getScope()));
// || library.getDependencyTrail().size() == 2;
}
diff --git a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileJSMojo.java b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileJSMojo.java
index 03246c7..5f80ccb 100644
--- a/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileJSMojo.java
+++ b/royale-maven-plugin/src/main/java/org/apache/royale/maven/CompileJSMojo.java
@@ -76,12 +76,6 @@
}
@Override
- protected boolean isForceSwcExternalLibraryPath() {
- // The forceSwcExternalLibraryPath should only apply to Flash compilations.
- return false;
- }
-
- @Override
protected List<String> getCompilerArgs(File configFile) throws MojoExecutionException {
List<String> args = super.getCompilerArgs(configFile);
args.add("-compiler.targets=SWF,JSRoyale");
@@ -122,7 +116,7 @@
@Override
protected boolean includeLibrary(Artifact library) {
String classifier = library.getClassifier();
- return (classifier == null) && !("provided".equalsIgnoreCase(library.getScope()));
+ return (classifier == null) && !("runtime".equalsIgnoreCase(library.getScope()));
}
@Override
diff --git a/royaleunit-ant-tasks/build.xml b/royaleunit-ant-tasks/build.xml
new file mode 100644
index 0000000..d7a7105
--- /dev/null
+++ b/royaleunit-ant-tasks/build.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project name="royaleunit-ant-tasks" default="main" basedir=".">
+
+ <!--
+
+ PROPERTIES
+
+ -->
+
+ <!-- The 'royaleunittasks' property is the absolute path, with forward slashes, -->
+ <!-- to the 'compiler' directory that contains this file. -->
+ <!-- All input paths are expressed as absolute paths starting with ${royaleunittasks}. -->
+ <pathconvert property="royaleunittasks" dirsep="/">
+ <path location="${basedir}"/>
+ </pathconvert>
+
+ <!-- The 'env' property contains all the environment variables -->
+ <property environment="env"/>
+
+ <!-- Properties can be overridden locally by loading a local.properties file -->
+ <!-- Java 8 users probably need javadoc.params=-Xdoclint:none -->
+ <property file="${royaleunittasks}/local.properties"/>
+ <property file="${royaleunittasks}/../build.properties"/>
+ <property name="javadoc.params" value="" />
+
+ <!-- The 'sdk' property is the absolute path, with forward slashes, to the compiler/lib directory -->
+ <!-- where a Royale SDK is built -->
+ <!-- All output paths are expressed as absolute paths starting with ${sdk} -->
+ <property name="sdk" value="${royaleunittasks}/../compiler-jx/lib"/>
+
+ <!-- Options for <javac> tasks -->
+ <property name="javac.debug" value="true"/>
+ <property name="javac.deprecation" value="false"/>
+ <property name="javac.src" value="1.6"/>
+
+ <!-- JAR manifest entries -->
+ <property name="manifest.sealed" value="false"/>
+ <property name="manifest.Implementation-Title" value="Apache Royale - RoyaleUnit Ant Tasks"/>
+ <property name="manifest.Implementation-Version" value="${release.version}"/>
+ <property name="manifest.Implementation-Vendor" value="Apache Software Foundation"/>
+
+ <property name="royaleunittasks.ant.binaries" value="**/*.class"/>
+
+ <!-- env.BUILD_NUMBER is set by Jenkins CI -->
+ <condition property="build.number" value="nightly-${env.BUILD_NUMBER}">
+ <isset property="env.BUILD_NUMBER"/>
+ </condition>
+
+ <!--
+
+ CLASSPATHS
+
+ -->
+
+ <path id="classpath">
+ <fileset dir="${sdk}" includes="**/*.jar"/>
+ </path>
+
+ <target name="download" description="Downloads third-party JARs">
+ <ant antfile="${royaleunittasks}/src/main/resources/downloads.xml" dir="${royaleunittasks}/src/main/resources" inheritAll="false"/>
+ </target>
+
+ <target name="compile" description="compile" depends="download">
+ <mkdir dir="${royaleunittasks}/target/classes"/>
+ <javac debug="${javac.debug}" deprecation="${javac.deprecation}"
+ includes="**/*.java" destdir="${royaleunittasks}/target/classes" classpathref="classpath" includeAntRuntime="true"
+ source="${javac.src}" target="${javac.src}">
+ <src path="${royaleunittasks}/src/main/java"/>
+ <compilerarg value="-Xlint:all,-path,-fallthrough,-cast"/>
+ </javac>
+ <copy todir="${royaleunittasks}/target/classes">
+ <fileset dir="${royaleunittasks}/src/main/resources" includes="**/*.properties"/>
+ </copy>
+ </target>
+
+ <target name="set.royale.royaleunittasks.jar.uptodate">
+ <uptodate property="royale.royaleunittasks.jar.uptodate"
+ targetfile="${sdk}/royaleUnitTasks.jar">
+ <srcfiles dir="${royaleunittasks}/target/classes">
+ <include name="**/*.class"/>
+ <include name="**/*.properties"/>
+ </srcfiles>
+ </uptodate>
+ </target>
+
+ <target name="royale.royaleunittasks.jar" depends="set.royale.royaleunittasks.jar.uptodate" unless="royale.royaleunittasks.jar.uptodate">
+ <mkdir dir="${royaleunittasks}/target/classes/META-INF"/>
+ <copy file="${basedir}/../LICENSE.base" tofile="${royaleunittasks}/target/classes/META-INF/LICENSE"/>
+ <copy file="${basedir}/../NOTICE.base" tofile="${royaleunittasks}/target/classes/META-INF/NOTICE"/>
+ <mkdir dir="${sdk}"/>
+ <jar file="${sdk}/royaleUnitTasks.jar" basedir="${royaleunittasks}/target/classes" >
+ <include name="META-INF/LICENSE"/>
+ <include name="META-INF/NOTICE"/>
+ <manifest>
+ <attribute name="Sealed" value="${manifest.sealed}"/>
+ <attribute name="Implementation-Title" value="${manifest.Implementation-Title}"/>
+ <attribute name="Implementation-Version" value="${manifest.Implementation-Version}.${build.number}"/>
+ <attribute name="Implementation-Vendor" value="${manifest.Implementation-Vendor}"/>
+ <attribute name="Class-Path" value="dom4j.jar java-websocket.jar slf4j-api.jar"/>
+ </manifest>
+ <fileset dir="${royaleunittasks}/src/main/resources" includes="royaleUnitTasks.tasks"/>
+ <fileset dir="${royaleunittasks}/src/main/resources" includes="TestRunner.template"/>
+ <fileset dir="${royaleunittasks}/src/main/resources" includes="royaleUnitDescriptor.template"/>
+ <fileset dir="${royaleunittasks}/target/classes" includes="${royaleunittasks.ant.binaries}"/>
+ </jar>
+ </target>
+
+ <target name="jar" depends="compile,royale.royaleunittasks.jar"
+ description="Creates JAR files"/>
+
+ <!--
+
+ SDK
+
+ -->
+
+ <target name="sdk" depends="jar, test" description="Builds the royaleUnitTasks.jar"/>
+
+ <target name="main" depends="sdk" description="Default target - Builds the royaleUnitTasks.jar">
+ <tstamp>
+ <format property="build.datetime" pattern="MM/dd/yyyy hh:mm:ss aa"/>
+ </tstamp>
+ <echo>RoyaleUnit Ant Tasks main completed on ${build.datetime}</echo>
+ </target>
+
+ <target name="test" depends="jar" description="Runs JUnit tests">
+ <!--<ant dir="src/test" />-->
+ </target>
+
+ <!--
+
+ CLEANUP
+
+ -->
+
+ <target name="clean" description="clean">
+ <ant antfile="${basedir}/src/main/resources/downloads.xml" target="clean" dir="${basedir}" />
+ <delete dir="${royaleunittasks}/target" failonerror="false"/>
+ <delete file="${sdk}/royaleUnitTasks.jar" failonerror="false"/>
+ </target>
+
+ <target name="wipe" depends="clean" description="Wipes everything that didn't come from Git.">
+ </target>
+</project>
\ No newline at end of file
diff --git a/royaleunit-ant-tasks/pom.xml b/royaleunit-ant-tasks/pom.xml
new file mode 100644
index 0000000..f7f96ef
--- /dev/null
+++ b/royaleunit-ant-tasks/pom.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>royaleunit-ant-tasks</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: RoyaleUnit Ant Tasks</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant-launcher</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.ant</groupId>
+ <artifactId>ant-testutil</artifactId>
+ <version>1.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>dom4j</groupId>
+ <artifactId>dom4j</artifactId>
+ <version>1.6.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.java-websocket</groupId>
+ <artifactId>Java-WebSocket</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>1.7.25</version>
+ </dependency>
+ </dependencies>
+
+</project>
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/IRoyaleUnitServer.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/IRoyaleUnitServer.java
new file mode 100644
index 0000000..e6f542b
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/IRoyaleUnitServer.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant;
+
+import java.io.IOException;
+
+public interface IRoyaleUnitServer
+{
+ public void start() throws IOException;
+ public void stop() throws IOException, InterruptedException;
+ public boolean isPending();
+ public String readNextTokenFromSocket() throws IOException;
+ public Exception getException();
+}
\ No newline at end of file
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/LoggingUtil.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/LoggingUtil.java
new file mode 100644
index 0000000..0f1e8f4
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/LoggingUtil.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant;
+
+public class LoggingUtil
+{
+ public static boolean VERBOSE = false;
+
+ public static void log(String message)
+ {
+ log(message, false);
+ }
+
+ public static void log(String message, boolean force)
+ {
+ if(VERBOSE || force)
+ {
+ System.out.println(message);
+ }
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitSocketServer.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitSocketServer.java
new file mode 100644
index 0000000..0152d9d
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitSocketServer.java
@@ -0,0 +1,282 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.text.MessageFormat;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Class responsible for managing the connections to the test runner and any boiler plate in the network interactivity.
+ */
+public class RoyaleUnitSocketServer implements IRoyaleUnitServer
+{
+
+ private static final char NULL_BYTE = '\u0000';
+ private static final String POLICY_FILE_REQUEST = "<policy-file-request/>";
+
+ //Uncomment to use DTD for validation rather than schema
+ //private static final String DOMAIN_POLICY = "<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"{0}\" /></cross-domain-policy>";
+
+ private static final String DOMAIN_POLICY =
+ "<?xml version=\"1.0\"?>"
+ + "<cross-domain-policy xmlns=\"http://localhost\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.adobe.com/xml/schemas PolicyFileSocket.xsd\">"
+ + "<allow-access-from domain=\"*\" to-ports=\"{0}\" />"
+ + "</cross-domain-policy>";
+
+ private static final String START_OF_TEST_RUN_ACK = "<startOfTestRunAck/>";
+ private static final String END_OF_TEST_RUN_ACK = "<endOfTestRunAck/>";
+
+ private int port;
+ private int timeout;
+ private int inboundBufferSize; //if this is not set high enough, incoming data may clobber unread data in the buffer
+ private boolean waitForPolicyFile;
+
+ private ServerSocket serverSocket = null;
+ private Socket clientSocket = null;
+ private InputStreamReader inboundReader = null;
+ private OutputStreamWriter outboundWriter = null;
+
+ public RoyaleUnitSocketServer(int port, int timeout, int inboundBufferSize, boolean waitForPolicyFile)
+ {
+ this.port = port;
+ this.timeout = timeout;
+ this.inboundBufferSize = inboundBufferSize;
+ this.waitForPolicyFile = waitForPolicyFile;
+ }
+
+ /**
+ * Starts the socket server, managing policy file requests, and starting the test process.
+ */
+ public void start() throws IOException
+ {
+ LoggingUtil.log("Starting server ...");
+
+ try
+ {
+ openServerSocket();
+ openClientSocket();
+ prepareClientSocket();
+ }
+ catch (SocketTimeoutException e)
+ {
+ throw new BuildException("Socket timeout waiting for royaleunit report", e);
+ }
+ }
+
+ public boolean isPending()
+ {
+ return false;
+ }
+
+ public Exception getException()
+ {
+ return null;
+ }
+
+ /**
+ * Resets the client connection.
+ */
+ private void resetInboundStream() throws IOException
+ {
+ LoggingUtil.log("Resetting client connection ...");
+
+ closeClientSocket();
+ openClientSocket();
+ }
+
+ /**
+ * Creates a connection on the specified socket. Waits {socketTimeout}
+ * seconds for a client connection before throwing an error
+ */
+ private void openServerSocket() throws IOException
+ {
+ serverSocket = new ServerSocket(port);
+ serverSocket.setSoTimeout(timeout);
+
+ LoggingUtil.log("Opening server socket on port [" + port + "].");
+ }
+
+ /**
+ * Creates the client connection. This method will pause until the connection
+ * is made or the timout limit is reached.
+ *
+ * Once a connection is established opens the in and out buffer.
+ */
+ private void openClientSocket() throws IOException
+ {
+ LoggingUtil.log("Waiting for client connection ...");
+
+ // This method blocks until a connection is made.
+ clientSocket = serverSocket.accept();
+
+ LoggingUtil.log("Client connected.");
+ LoggingUtil.log("Setting inbound buffer size to [" + inboundBufferSize + "] bytes.");
+
+ inboundReader = new InputStreamReader(new BufferedInputStream(clientSocket.getInputStream(), inboundBufferSize), "UTF-8");
+ outboundWriter = new OutputStreamWriter(new BufferedOutputStream(clientSocket.getOutputStream()), "UTF-8");
+
+ LoggingUtil.log("Receiving data ...");
+ }
+
+ /**
+ * Decides whether to send a policy request or a start ack
+ */
+ private void prepareClientSocket() throws IOException
+ {
+ // if it's a policy request, make sure the first thing we send is a policy response
+ if (waitForPolicyFile)
+ {
+ String request = readNextTokenFromSocket();
+ if (request.equals(POLICY_FILE_REQUEST))
+ {
+ LoggingUtil.log("Policy file requested.");
+
+ sendPolicyFile();
+ resetInboundStream();
+ }
+ }
+
+ //tell client to start the testing process
+ sendTestRunStartAcknowledgement();
+ }
+
+ /**
+ * Generate domain policy message and send
+ */
+ private void sendPolicyFile() throws IOException
+ {
+ sendOutboundMessage(MessageFormat.format(DOMAIN_POLICY, new Object[] { Integer.toString(port) }));
+
+ LoggingUtil.log("Policy file sent.");
+ }
+
+ /**
+ * Generate and send message to inform test runner to begin sending test data
+ */
+ private void sendTestRunStartAcknowledgement() throws IOException
+ {
+ LoggingUtil.log("Sending acknowledgement to player to start sending test data ...\n");
+
+ sendOutboundMessage(START_OF_TEST_RUN_ACK);
+ }
+
+ /**
+ * Reads tokens from the socket input stream based on NULL_BYTE as a delimiter
+ */
+ public String readNextTokenFromSocket() throws IOException
+ {
+ StringBuffer buffer = new StringBuffer();
+ int piece = -1;
+
+ while ((piece = inboundReader.read()) != NULL_BYTE)
+ {
+ //Did we reach the end of the buffer? Tell the user there is nothing more.
+ if (piece == -1)
+ {
+ return null;
+ }
+
+ final char chr = (char) piece;
+ buffer.append(chr);
+ }
+
+ //Did we recieve a message that the test run is over? Tell the user we have nothing more.
+ String token = buffer.toString();
+
+ return token;
+ }
+
+ private void sendOutboundMessage(String message) throws IOException
+ {
+ if(outboundWriter != null)
+ {
+ outboundWriter.write(message);
+ outboundWriter.write(NULL_BYTE);
+ outboundWriter.flush();
+ }
+ }
+
+ /**
+ * Stops the socket server, notifying the test runner, and closing the appropriate connections.
+ */
+ public void stop() throws IOException, InterruptedException
+ {
+ LoggingUtil.log("\nStopping server ...");
+
+ sendTestRunEndAcknowledgement();
+ closeClientSocket();
+ closeServerSocket();
+ }
+
+ /**
+ * Sends the end of test run to the listener to close the connection
+ */
+ private void sendTestRunEndAcknowledgement() throws IOException
+ {
+ LoggingUtil.log("End of test data reached, sending acknowledgement to player ...");
+
+ sendOutboundMessage(END_OF_TEST_RUN_ACK);
+ }
+
+ /**
+ * Closes the client connection and all buffers, ignoring any errors
+ */
+ private void closeClientSocket() throws IOException
+ {
+ LoggingUtil.log("Closing client connection ...");
+
+ // Close the output stream.
+ if (outboundWriter != null)
+ {
+ outboundWriter.close();
+ }
+
+ // Close the input stream.
+ if (inboundReader != null)
+ {
+ inboundReader.close();
+ }
+
+ // Close the client socket.
+ if (clientSocket != null)
+ {
+ clientSocket.close();
+ }
+ }
+
+ /**
+ * Closes the server socket. Ignores any errors if unable to close
+ */
+ private void closeServerSocket() throws IOException
+ {
+ LoggingUtil.log("Closing server on port [" + port + "] ...");
+
+ if (serverSocket != null)
+ {
+ serverSocket.close();
+ }
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitSocketThread.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitSocketThread.java
new file mode 100644
index 0000000..90e1211
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitSocketThread.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.Callable;
+
+import org.apache.tools.ant.BuildException;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.apache.royale.test.ant.report.Report;
+import org.apache.royale.test.ant.report.Suite;
+
+/**
+ * Managing class for the RoyaleUnitSocketServer and report aggregation.
+ */
+public class RoyaleUnitSocketThread implements Callable<Object>
+{
+ // Messages from CIListener
+ private static final String END_OF_SUCCESS = "status=\"success\" />";
+ private static final String END_OF_FAILURE = "</testcase>";
+ private static final String END_OF_IGNORE = "<skipped /></testcase>";
+ private static final String END_OF_TEST_RUN = "<endOfTestRun/>";
+
+ // XML attribute labels
+ private static final String SUITE_ATTRIBUTE = "classname";
+
+ private File reportDir;
+
+ private IRoyaleUnitServer server;
+ private Map<String, Report> reports;
+
+ public RoyaleUnitSocketThread(IRoyaleUnitServer server, File reportDir, Map<String, Report> reports)
+ {
+ this.server = server;
+ this.reportDir = reportDir;
+ this.reports = reports;
+ }
+
+ /**
+ * When excuted, the thread will start the socket server and wait for inbound data and delegate reporting
+ */
+ //TODO: Clean up exception handling
+ public Object call() throws Exception
+ {
+ try
+ {
+ server.start();
+ parseInboundMessages();
+ }
+ catch (IOException e)
+ {
+ throw new BuildException("error receiving report from royaleunit", e);
+ }
+ finally
+ {
+ try
+ {
+ server.stop();
+ }
+ catch (IOException e)
+ {
+ throw new BuildException("could not close client/server socket");
+ }
+ }
+
+ //All done, let the process that spawned me know I've returned.
+ return null;
+ }
+
+ /**
+ * Used to iterate and interpret byte sent over the socket.
+ */
+ private void parseInboundMessages() throws IOException
+ {
+ while (true)
+ {
+ if (server.isPending())
+ {
+ //try again later
+ try
+ {
+ Thread.sleep(100);
+ }
+ catch(Exception e) {}
+ continue;
+ }
+
+ if (server.getException() != null)
+ {
+ throw new BuildException(server.getException());
+ }
+
+ String request = server.readNextTokenFromSocket();
+ if (request == null)
+ {
+ break;
+ }
+ else if (request.equals(END_OF_TEST_RUN))
+ {
+ // The client has declared that the test run is complete
+ break;
+ }
+ else if (request.endsWith(END_OF_FAILURE) || request.endsWith(END_OF_SUCCESS) || request.endsWith(END_OF_IGNORE))
+ {
+ // Process all other known requests
+ processTestReport(request);
+ }
+ else
+ {
+ throw new BuildException("command [" + request + "] not understood");
+ }
+ }
+ }
+
+ /**
+ * Process the test report.
+ *
+ * @param report
+ * String that represents a complete test
+ */
+ private void processTestReport(String xml)
+ {
+ // Convert the string report into an XML document
+ Document test = parseReport(xml);
+
+ // Find the name of the suite
+ String suiteName = test.getRootElement().attributeValue(SUITE_ATTRIBUTE);
+
+ // Convert all instances of :: for file support
+ suiteName = suiteName.replaceAll("::", ".");
+
+ if (!reports.containsKey(suiteName))
+ {
+ reports.put(suiteName, new Report(new Suite(suiteName)));
+ }
+
+ // Fetch report, add test, and write to disk
+ Report report = reports.get(suiteName);
+ report.addTest(test);
+
+ report.save(reportDir);
+ }
+
+ /**
+ * Parse the parameter String and returns it as a document
+ *
+ * @param report
+ * String
+ * @return Document
+ */
+ private Document parseReport(String report)
+ {
+ try
+ {
+ final Document document = DocumentHelper.parseText(report);
+
+ return document;
+ }
+ catch (DocumentException e)
+ {
+ LoggingUtil.log(report);
+ throw new BuildException("Error parsing report.", e);
+ }
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitWebSocketServer.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitWebSocketServer.java
new file mode 100644
index 0000000..925e367
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/RoyaleUnitWebSocketServer.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.Callable;
+
+import org.apache.tools.ant.BuildException;
+import org.java_websocket.WebSocket;
+import org.java_websocket.handshake.ClientHandshake;
+import org.java_websocket.server.WebSocketServer;
+
+public class RoyaleUnitWebSocketServer extends WebSocketServer implements IRoyaleUnitServer
+{
+ private static final String START_OF_TEST_RUN_ACK = "<startOfTestRunAck/>";
+ private static final String END_OF_TEST_RUN_ACK = "<endOfTestRunAck/>";
+
+ public RoyaleUnitWebSocketServer(int port, int timeout)
+ {
+ super(new InetSocketAddress(port));
+ this.timeout = timeout;
+ //because we may be running many sets of tests in a short period of
+ //time, and the socket can end up in a timeout state after it is closed,
+ //this allows us to reuse the same port again quickly
+ this.setReuseAddr(true);
+ }
+
+ private int timeout;
+ private Timer timeoutTimer;
+ private List<String> queue = new ArrayList<String>();
+ private Exception resultException;
+
+ public Exception getException()
+ {
+ return resultException;
+ }
+
+ @Override
+ public void stop() throws IOException, InterruptedException
+ {
+ LoggingUtil.log("\nStopping server ...");
+
+ if(timeoutTimer != null)
+ {
+ timeoutTimer.cancel();
+ timeoutTimer = null;
+ }
+
+ for(WebSocket socket : getConnections())
+ {
+ sendTestRunEndAcknowledgement(socket);
+ }
+ super.stop();
+ }
+
+ @Override
+ public void onOpen(WebSocket connection, ClientHandshake handshake)
+ {
+ if(timeoutTimer != null)
+ {
+ timeoutTimer.cancel();
+ timeoutTimer = null;
+ }
+
+ LoggingUtil.log("Client connected.");
+ LoggingUtil.log("Receiving data ...");
+
+ sendTestRunStartAcknowledgement(connection);
+ }
+
+ @Override
+ public void onClose(WebSocket connection, int code, String reason, boolean remote)
+ {
+ Thread.currentThread().interrupt();
+ }
+
+ @Override
+ public void onMessage(WebSocket connection, String message)
+ {
+ queue.add(message);
+ }
+
+ @Override
+ public void onError(WebSocket connection, Exception ex)
+ {
+ resultException = ex;
+ }
+
+ @Override
+ public void onStart()
+ {
+ LoggingUtil.log("Starting server ...");
+ LoggingUtil.log("Waiting for client connection ...");
+
+ timeoutTimer = new Timer();
+ timeoutTimer.schedule(new TimerTask()
+ {
+ public void run()
+ {
+ resultException = new BuildException("Socket timeout waiting for royaleunit report");
+ }
+ }, timeout);
+ }
+
+ public boolean isPending()
+ {
+ return resultException == null && queue.size() == 0;
+ }
+
+ /**
+ * Reads tokens from the web socket
+ */
+ public String readNextTokenFromSocket() throws IOException
+ {
+ return queue.remove(0);
+ }
+
+ private void sendOutboundMessage(WebSocket connection, String message)
+ {
+ connection.send(message);
+ }
+
+ /**
+ * Generate and send message to inform test runner to begin sending test data
+ */
+ private void sendTestRunStartAcknowledgement(WebSocket connection)
+ {
+ LoggingUtil.log("Sending acknowledgement to player to start sending test data ...\n");
+
+ sendOutboundMessage(connection, START_OF_TEST_RUN_ACK);
+ }
+
+ /**
+ * Sends the end of test run to the listener to close the connection
+ */
+ private void sendTestRunEndAcknowledgement(WebSocket connection)
+ {
+ LoggingUtil.log("End of test data reached, sending acknowledgement to player ...");
+
+ sendOutboundMessage(connection, END_OF_TEST_RUN_ACK);
+ }
+}
\ No newline at end of file
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/OperatingSystem.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/OperatingSystem.java
new file mode 100644
index 0000000..7629055
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/OperatingSystem.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher;
+
+import org.apache.royale.test.ant.LoggingUtil;
+
+public enum OperatingSystem
+{
+ WINDOWS, MACOSX, LINUX;
+
+ private static final String SUN_WINDOWS = "windows";
+ private static final String SUN_MACOSX = "mac os x";
+ private static final String OPENJDK_MACOSX = "darwin";
+
+ /**
+ * Searches for Windows and Mac specificially and if not found defaults to Linux.
+ */
+ public static OperatingSystem identify()
+ {
+ OperatingSystem os = null;
+ String env = System.getProperty("os.name").toLowerCase();
+
+ if (env.startsWith(SUN_WINDOWS))
+ {
+ LoggingUtil.log("OS: [Windows]");
+ os = OperatingSystem.WINDOWS;
+ }
+ else if (env.contains(SUN_MACOSX) || env.contains(OPENJDK_MACOSX))
+ {
+ LoggingUtil.log("OS: [Mac]");
+ os = OperatingSystem.MACOSX;
+ }
+ else
+ {
+ LoggingUtil.log("OS: [Linux]");
+ os = OperatingSystem.LINUX;
+ }
+
+ return os;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/Command.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/Command.java
new file mode 100644
index 0000000..cc4f9ad
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/Command.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.royale.test.ant.LoggingUtil;
+
+public abstract class Command
+{
+ private Project project;
+ private Commandline commandLine;
+ private String[] environment;
+
+ public Command()
+ {
+ super();
+ this.commandLine = new Commandline();
+ environment = new String[0];
+ }
+
+ public void setProject(Project project)
+ {
+ this.project = project;
+ }
+
+ public Project getProject()
+ {
+ return project;
+ }
+
+ public Commandline getCommandLine()
+ {
+ return commandLine;
+ }
+
+ public int execute() throws IOException
+ {
+ Execute execute = new Execute();
+ execute.setCommandline(getCommandLine().getCommandline());
+ execute.setAntRun(getProject());
+ execute.setEnvironment(getEnvironment());
+
+ LoggingUtil.log(getCommandLine().describeCommand());
+
+ return execute.execute();
+ }
+
+ public Process launch() throws IOException
+ {
+ Execute execute = new Execute();
+ execute.setCommandline(getCommandLine().getCommandline());
+ execute.setAntRun(getProject());
+ execute.setEnvironment(getEnvironment());
+
+ LoggingUtil.log(getCommandLine().describeCommand());
+
+ execute.execute();
+
+ //By default we use the Ant Execute task which does not give us a handle to a process
+ return null;
+ }
+
+ public void setEnvironment(String[] variables)
+ {
+ this.environment = variables;
+ }
+
+ public String[] getEnvironment()
+ {
+ return environment;
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncException.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncException.java
new file mode 100644
index 0000000..e7362f8
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncException.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.headless;
+
+public class XvncException extends Exception
+{
+ private static final long serialVersionUID = -879079265370069307L;
+
+ public XvncException()
+ {
+ super("Could not find the vncserver command.");
+ }
+
+ public XvncException(int baseDisplayNumber, int finalDisplayNumber)
+ {
+ super("Could not start xvnc using displays "
+ + String.valueOf(baseDisplayNumber)
+ + "-"
+ + String.valueOf(finalDisplayNumber)
+ + "; Consider adding to your launch script: killall Xvnc Xrealvnc; rm -fv /tmp/.X*-lock /tmp/.X11-unix/X*");
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncStartCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncStartCommand.java
new file mode 100644
index 0000000..edbf01d
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncStartCommand.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.headless;
+
+import java.io.IOException;
+
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.launcher.commands.Command;
+
+public class XvncStartCommand extends Command
+{
+ private final String VNC_SERVER_COMMAND = "vncserver";
+ private final int MAX_DISPLAY_CYCLES = 2;
+
+ private int baseDisplay;
+ private int currentDisplay;
+
+ public XvncStartCommand(int display)
+ {
+ super();
+ this.baseDisplay = display;
+ this.currentDisplay = display;
+ }
+
+ public void cycle() throws XvncException
+ {
+ if((currentDisplay - baseDisplay) == MAX_DISPLAY_CYCLES)
+ {
+ throw new XvncException(baseDisplay, currentDisplay);
+ }
+
+ currentDisplay++;
+ }
+
+ public int getCurrentDisplay()
+ {
+ return currentDisplay;
+ }
+
+ @Override
+ public int execute() throws IOException
+ {
+ getCommandLine().setExecutable(VNC_SERVER_COMMAND);
+ getCommandLine().addArguments(new String[]{":" + String.valueOf(currentDisplay)});
+
+ LoggingUtil.log("Attempting start on :" + currentDisplay + " ...");
+
+ return super.execute();
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncStopCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncStopCommand.java
new file mode 100644
index 0000000..c94605e
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/headless/XvncStopCommand.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.headless;
+
+import java.io.IOException;
+
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.launcher.commands.Command;
+
+public class XvncStopCommand extends Command
+{
+ private final String VNC_SERVER_COMMAND = "vncserver";
+ private int display;
+
+ public XvncStopCommand(int display)
+ {
+ super();
+ this.display = display;
+ }
+
+ @Override
+ public int execute() throws IOException
+ {
+ LoggingUtil.log("Terminating xvnc on :" + display);
+
+ getCommandLine().setExecutable(VNC_SERVER_COMMAND);
+ getCommandLine().addArguments(new String[]{ "-kill", ":" + String.valueOf(display) });
+
+ return super.execute();
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/AdlCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/AdlCommand.java
new file mode 100644
index 0000000..734327f
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/AdlCommand.java
@@ -0,0 +1,163 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Commandline.Argument;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.URLResource;
+import org.apache.tools.ant.util.ResourceUtils;
+import org.apache.royale.test.ant.LoggingUtil;
+
+public class AdlCommand extends DefaultPlayerCommand
+{
+ private final String ADT_JAR_PATH = "lib" + File.separatorChar + "adt.jar";
+ private final String DESCRIPTOR_TEMPLATE = "royaleUnitDescriptor.template";
+ private final String DESCRIPTOR_FILE = "royaleUnitDescriptor.xml";
+
+ private File precompiledAppDescriptor;
+
+ @Override
+ public File getFileToExecute()
+ {
+ if(getPrecompiledAppDescriptor() != null)
+ {
+ return new File(getPrecompiledAppDescriptor().getAbsolutePath());
+ }
+ return new File(getSwf().getParentFile().getAbsolutePath() + File.separatorChar + DESCRIPTOR_FILE);
+ }
+
+ /**
+ * Used to create the application descriptor used to invoke adl
+ */
+ private void createApplicationDescriptor()
+ {
+ try
+ {
+ //Template location in JAR
+ URLResource template = new URLResource(getClass().getResource("/" + DESCRIPTOR_TEMPLATE));
+
+ //Descriptor location, same location as SWF due to relative path required in descriptor
+ File descriptor = new File(getSwf().getParentFile().getAbsolutePath() + File.separatorChar + DESCRIPTOR_FILE);
+
+ //Create tokens to filter
+ Double versionNumber = getVersion();
+ FilterSet filters = new FilterSet();
+ filters.addFilter("ADL_SWF", getSwf().getName());
+ filters.addFilter("ADT_VERSION", Double.toString(versionNumber));
+ if(versionNumber > 2.0) {
+ filters.addFilter("VERSION_PROP", "versionNumber");
+ } else {
+ filters.addFilter("VERSION_PROP", "version");
+ }
+
+ //Copy descriptor template to SWF folder performing token replacement
+ ResourceUtils.copyResource(
+ template,
+ new FileResource(descriptor),
+ new FilterSetCollection(filters),
+ null,
+ true,
+ false,
+ null,
+ null,
+ getProject()
+ );
+
+ LoggingUtil.log("Created application descriptor at [" + descriptor.getAbsolutePath() + "]");
+ }
+ catch (Exception e)
+ {
+ throw new BuildException("Could not create application descriptor");
+ }
+ }
+
+ private double getVersion()
+ {
+ String outputProperty = "AIR_VERSION";
+
+ //Execute mxmlc to find SDK version number
+ Java task = new Java();
+ task.setFork(true);
+ task.setFailonerror(true);
+ task.setJar(new File(getProject().getProperty("ROYALE_HOME") + File.separatorChar + ADT_JAR_PATH));
+ task.setProject(getProject());
+ task.setDir(getProject().getBaseDir());
+ task.setOutputproperty(outputProperty);
+
+ Argument versionArgument = task.createArg();
+ versionArgument.setValue("-version");
+
+ task.execute();
+ double version = parseAdtVersionNumber( getProject().getProperty(outputProperty) );
+ LoggingUtil.log("Found AIR version: " + version);
+ return version;
+ }
+
+
+ private double parseAdtVersionNumber( String versionString )
+ {
+ double version;
+
+ //AIR 2.6 and greater only returns the version number.
+ if( versionString.startsWith("adt") )
+ {
+ //Parse version number and return as int
+ int prefixIndex = versionString.indexOf("adt version \"");
+ version = Double.parseDouble(versionString.substring(prefixIndex + 13, prefixIndex + 16));
+
+ }else
+ {
+ version = Double.parseDouble(versionString.substring(0, 3) );
+ }
+
+ return version;
+ }
+
+ @Override
+ public void prepare()
+ {
+ getCommandLine().setExecutable(generateExecutable());
+ getCommandLine().addArguments(new String[]{getFileToExecute().getAbsolutePath()});
+
+ if(getPrecompiledAppDescriptor() == null)
+ {
+ //Create Adl descriptor file
+ createApplicationDescriptor();
+ }
+ }
+
+ private String generateExecutable()
+ {
+ return getProject().getProperty("ROYALE_HOME") + "/bin/" + getDefaults().getAdlCommand();
+ }
+
+ public File getPrecompiledAppDescriptor()
+ {
+ return precompiledAppDescriptor;
+ }
+
+ public void setPrecompiledAppDescriptor(File precompiledAppDescriptor)
+ {
+ this.precompiledAppDescriptor = precompiledAppDescriptor;
+ }
+}
\ No newline at end of file
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/CustomPlayerCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/CustomPlayerCommand.java
new file mode 100644
index 0000000..830af6e
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/CustomPlayerCommand.java
@@ -0,0 +1,124 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+import org.apache.royale.test.ant.LoggingUtil;
+
+public class CustomPlayerCommand implements PlayerCommand
+{
+ private DefaultPlayerCommand proxiedCommand;
+ private File executable;
+
+ public PlayerCommand getProxiedCommand()
+ {
+ return proxiedCommand;
+ }
+
+ public void setProxiedCommand(DefaultPlayerCommand playerCommand)
+ {
+ this.proxiedCommand = playerCommand;
+ }
+
+ public File getExecutable()
+ {
+ return executable;
+ }
+
+ public void setExecutable(File executable)
+ {
+ this.executable = executable;
+ }
+
+ public void setProject(Project project)
+ {
+ proxiedCommand.setProject(project);
+ }
+
+ public void setSwf(File swf)
+ {
+ proxiedCommand.setSwf(swf);
+ }
+
+ public String getUrl() {
+ return proxiedCommand.getUrl();
+ }
+
+ public void setUrl(String url) {
+ proxiedCommand.setUrl(url);
+ }
+
+ public File getFileToExecute()
+ {
+ return proxiedCommand.getFileToExecute();
+ }
+
+ public void prepare()
+ {
+ proxiedCommand.prepare();
+
+ proxiedCommand.getCommandLine().setExecutable(executable.getAbsolutePath());
+ proxiedCommand.getCommandLine().clearArgs();
+
+ if(getUrl() != null)
+ {
+ proxiedCommand.getCommandLine().addArguments(new String[]{getUrl()});
+ }
+ else
+ {
+ proxiedCommand.getCommandLine().addArguments(new String[]{getFileToExecute().getAbsolutePath()});
+ }
+
+ }
+
+ public Process launch() throws IOException
+ {
+ LoggingUtil.log(proxiedCommand.getCommandLine().describeCommand());
+
+ //execute the command directly
+ return Runtime.getRuntime().exec(
+ proxiedCommand.getCommandLine().getCommandline(),
+ getJointEnvironment(),
+ proxiedCommand.getProject().getBaseDir());
+ }
+
+ public void setEnvironment(String[] variables)
+ {
+ proxiedCommand.setEnvironment(variables);
+ }
+
+ /**
+ * Combine process environment variables and command's environment to emulate the default
+ * behavior of the Execute task. Needed especially when user expects environment to be
+ * available to custom command (e.g. - xvnc with player not on path).
+ */
+ @SuppressWarnings("unchecked")
+ private String[] getJointEnvironment()
+ {
+ Vector procEnvironment = Execute.getProcEnvironment();
+ String[] environment = new String[procEnvironment.size() + proxiedCommand.getEnvironment().length];
+ System.arraycopy(procEnvironment.toArray(), 0, environment, 0, procEnvironment.size());
+ System.arraycopy(proxiedCommand.getEnvironment(), 0, environment, procEnvironment.size(), proxiedCommand.getEnvironment().length);
+
+ return environment;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/DefaultPlayerCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/DefaultPlayerCommand.java
new file mode 100644
index 0000000..92d0a83
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/DefaultPlayerCommand.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.royale.test.ant.launcher.commands.Command;
+import org.apache.royale.test.ant.launcher.platforms.PlatformDefaults;
+
+public abstract class DefaultPlayerCommand extends Command implements PlayerCommand
+{
+ private String url;
+ private File swf;
+ private PlatformDefaults defaults;
+
+ public DefaultPlayerCommand()
+ {
+ super();
+ }
+
+ public void setSwf(File swf)
+ {
+ this.swf = swf;
+ }
+
+ public File getSwf()
+ {
+ return swf;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void setDefaults(PlatformDefaults defaults)
+ {
+ this.defaults = defaults;
+ }
+
+ public PlatformDefaults getDefaults()
+ {
+ return defaults;
+ }
+
+ public abstract File getFileToExecute();
+
+ public abstract void prepare();
+
+ @Override
+ public Process launch() throws IOException
+ {
+ return super.launch();
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/FlashPlayerCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/FlashPlayerCommand.java
new file mode 100644
index 0000000..725becf
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/FlashPlayerCommand.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.File;
+
+
+/**
+ * Abstracts the assembly of a command-line call to the Flash player for all platforms.
+ */
+public class FlashPlayerCommand extends DefaultPlayerCommand
+{
+ public static final String TRUST_FILENAME = "royaleUnit.cfg";
+
+ private boolean localTrusted;
+
+ public FlashPlayerCommand()
+ {
+ super();
+ }
+
+ @Override
+ public File getFileToExecute()
+ {
+ return getSwf();
+ }
+
+ public void setLocalTrusted(boolean localTrusted)
+ {
+ this.localTrusted = localTrusted;
+ }
+
+ public boolean isLocalTrusted()
+ {
+ return localTrusted;
+ }
+
+ @Override
+ public void prepare()
+ {
+ //Determine if we have a URL value.
+ //This should be populated by setting the 'swf' property equal to a remote http hosted SWF.
+ if(getUrl() != null && getUrl() != "")
+ {
+ //setup the command line now for remote URL
+ getCommandLine().setExecutable(getDefaults().getOpenCommand());
+ getCommandLine().addArguments(getDefaults().getOpenSystemArguments());
+ getCommandLine().addArguments(new String[]{getUrl()});
+
+ //There is no need to add to the local trust because we're going to be loading the swf from a remote location.
+
+ }
+ //Determine if we have a local SWF to run.
+ //This should be populated by setting the 'swf' property equal to a swf on your local file system.
+ else if(getSwf() != null) {
+
+ //setup the command line now with local SWF file location
+ getCommandLine().setExecutable(getDefaults().getOpenCommand());
+ getCommandLine().addArguments(getDefaults().getOpenSystemArguments());
+ getCommandLine().addArguments(new String[]{getFileToExecute().getAbsolutePath()});
+
+ //handle local trust for locally stored swf file
+ TrustFile trustFile = new TrustFile(getProject(), getDefaults().getFlashPlayerUserTrustDirectory(), getDefaults().getFlashPlayerGlobalTrustDirectory());
+ if (localTrusted)
+ {
+ trustFile.add(getSwf());
+ }
+ else
+ {
+ trustFile.remove(getSwf());
+ }
+ }
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/PlayerCommand.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/PlayerCommand.java
new file mode 100644
index 0000000..157c198
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/PlayerCommand.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Execute;
+
+/**
+ * Class used to abstract an extension of {@link Execute} that has its own handle to a {@link Project}
+ * and can setup context for using the project
+ */
+public interface PlayerCommand
+{
+ public void setProject(Project project);
+ public void setEnvironment(String[] variables);
+ public File getFileToExecute();
+ public void setSwf(File swf);
+ public void setUrl(String url);
+ public void prepare();
+ public Process launch() throws IOException;
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/PlayerCommandFactory.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/PlayerCommandFactory.java
new file mode 100644
index 0000000..6961262
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/PlayerCommandFactory.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.File;
+
+import org.apache.royale.test.ant.launcher.OperatingSystem;
+import org.apache.royale.test.ant.launcher.platforms.LinuxDefaults;
+import org.apache.royale.test.ant.launcher.platforms.MacOSXDefaults;
+import org.apache.royale.test.ant.launcher.platforms.WindowsDefaults;
+
+public class PlayerCommandFactory
+{
+ /**
+ * Factory method to create the appropriate player and provide it with a set of defaults for
+ * the executing platform.
+ *
+ * @param os
+ * @param player "flash" or "air"
+ * @param customCommand
+ * @param localTrusted
+ * @return Desired player command with platform defaults possibly wrapped in a custom command
+ */
+ public static PlayerCommand createPlayer(OperatingSystem os, String player, File customCommand, boolean localTrusted)
+ {
+ PlayerCommand newInstance = null;
+
+ DefaultPlayerCommand defaultInstance = null;
+
+ //choose player
+ if (player.equals("flash") || player.equals("html"))
+ {
+ FlashPlayerCommand fpCommand = new FlashPlayerCommand();
+ fpCommand.setLocalTrusted(localTrusted);
+ defaultInstance = fpCommand;
+ }
+ else
+ {
+ defaultInstance = new AdlCommand();
+ }
+
+ //set defaults
+ if (os.equals(OperatingSystem.WINDOWS))
+ {
+ defaultInstance.setDefaults(new WindowsDefaults());
+ }
+ else if(os.equals(OperatingSystem.MACOSX))
+ {
+ defaultInstance.setDefaults(new MacOSXDefaults());
+ }
+ else
+ {
+ defaultInstance.setDefaults(new LinuxDefaults());
+ }
+
+ //if a custom command has been provide, use it to wrap the default command
+ if(customCommand != null)
+ {
+ CustomPlayerCommand customInstance = new CustomPlayerCommand();
+ customInstance.setProxiedCommand(defaultInstance);
+ customInstance.setExecutable(customCommand);
+ newInstance = customInstance;
+ }
+ else
+ {
+ newInstance = defaultInstance;
+ }
+
+ return newInstance;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/TrustFile.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/TrustFile.java
new file mode 100644
index 0000000..0e1653a
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/commands/player/TrustFile.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.commands.player;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.royale.test.ant.LoggingUtil;
+
+public class TrustFile
+{
+ public static final String TRUST_FILENAME = "royaleUnit.cfg";
+
+ private File trustDirectory;
+ private File trustFile;
+ private List<String> paths;
+
+ public TrustFile(Project project, File userTrustDirectory, File globaTrustDirectory)
+ {
+ // determine which trust directory to use
+ this.trustDirectory = userTrustDirectory != null ? userTrustDirectory : globaTrustDirectory;
+
+ // create it if it doesn't exist
+ if (!this.trustDirectory.exists())
+ {
+ try
+ {
+ trustDirectory.mkdirs();
+ }
+ catch (Exception e)
+ {
+ throw new BuildException("Could not create Flash Player trust directory at [" + trustDirectory.getAbsolutePath() + "]; permission denied.");
+ }
+ }
+
+ // locate trust file
+ this.trustFile = project.resolveFile(trustDirectory.getAbsolutePath() + "/" + TRUST_FILENAME);
+
+ // parse trust file contents
+ this.paths = read();
+ }
+
+ private List<String> read()
+ {
+ List<String> paths = new ArrayList<String>();
+
+ if (trustFile.exists())
+ {
+ try
+ {
+ BufferedReader reader = new BufferedReader(new FileReader(trustFile));
+ String path = null;
+
+ while ((path = reader.readLine()) != null)
+ {
+ paths.add(path);
+ }
+
+ reader.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ return paths;
+ }
+
+ public void add(String url)
+ {
+ String path = new File(url).getParentFile().getAbsolutePath();
+ addPath(path);
+ }
+
+ public void add(File swf)
+ {
+ String path = swf.getParentFile().getAbsolutePath();
+ addPath(path);
+ }
+
+ private void addPath(String path)
+ {
+ // create the appropriate FP trust directory is it doesn't exist
+ if (!trustDirectory.exists())
+ {
+ trustDirectory.mkdir();
+ }
+
+ // Add path if it doesn't exist
+ if (!paths.contains(path))
+ {
+ paths.add(path);
+
+ // Write file
+ write();
+
+ LoggingUtil.log("Updated local trust file at [" + trustFile.getAbsolutePath() + "], added [" + path + "].");
+ }
+ else
+ {
+ LoggingUtil.log("Entry [" + path + "] already available in local trust file at [" + trustFile.getAbsolutePath() + "].");
+ }
+ }
+
+ private void write()
+ {
+ try
+ {
+ FileWriter writer = new FileWriter(trustFile, false);
+
+ for (String path : paths)
+ {
+ writer.write(path + System.getProperty("line.separator"));
+ }
+
+ writer.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public void remove(String url) {
+ String path = new File(url).getParentFile().getAbsolutePath();
+ removePath(path);
+ }
+
+ public void remove(File swf)
+ {
+ // remove path if exists
+ String path = swf.getParentFile().getAbsolutePath();
+ removePath(path);
+ }
+
+ public void removePath(String path)
+ {
+ if (paths.contains(path))
+ {
+ paths.remove(path);
+
+ // write out new copy of file
+ write();
+
+ LoggingUtil.log("Updated local trust file at [" + trustFile.getAbsolutePath() + "], removed [" + path + "].");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/DefaultContext.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/DefaultContext.java
new file mode 100644
index 0000000..412eb35
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/DefaultContext.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.contexts;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.royale.test.ant.launcher.commands.player.PlayerCommand;
+
+public class DefaultContext implements ExecutionContext
+{
+ private PlayerCommand command;
+
+ @SuppressWarnings("unused")
+ private Project project;
+
+ public void setProject(Project project)
+ {
+ this.project = project;
+ }
+ public void setCommand(PlayerCommand command)
+ {
+ this.command = command;
+ }
+
+ public void start() throws IOException
+ {
+ //prep anything the command needs to run
+ command.prepare();
+ }
+
+ public void stop(Process playerProcess) throws IOException
+ {
+ //destroy the process related to the player if it exists
+ if(playerProcess != null)
+ {
+ playerProcess.destroy();
+ }
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/ExecutionContext.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/ExecutionContext.java
new file mode 100644
index 0000000..1b5c97d
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/ExecutionContext.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.contexts;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.royale.test.ant.launcher.commands.player.PlayerCommand;
+
+/**
+ * Basis for executing a player command.
+ */
+public interface ExecutionContext
+{
+ public void setProject(Project project);
+ public void setCommand(PlayerCommand command);
+
+ /**
+ * Starts the execution context and any work associated with the individual implementations.
+ *
+ * @throws IOException
+ */
+ public void start() throws IOException;
+
+ /**
+ * Stops the execution context and manages the player Process as well as any work associated
+ * with the individual implementations.
+ *
+ * @param playerProcess
+ * @throws IOException
+ */
+ public void stop(Process playerProcess) throws IOException;
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/ExecutionContextFactory.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/ExecutionContextFactory.java
new file mode 100644
index 0000000..89be35d
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/ExecutionContextFactory.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.contexts;
+
+import org.apache.royale.test.ant.launcher.OperatingSystem;
+
+public class ExecutionContextFactory
+{
+ /**
+ * Used to generate new instances of an execution context based on the OS and whether the build should run
+ * headlessly.
+ *
+ * @param os Current OS.
+ * @param headless Should the build run headlessly.
+ * @param display The vnc display number to use if headless
+ *
+ * @return
+ */
+ public static ExecutionContext createContext(OperatingSystem os, boolean headless, int display)
+ {
+ boolean trulyHeadless = headless && (os == OperatingSystem.LINUX);
+ ExecutionContext context = null;
+
+ if(trulyHeadless)
+ {
+ context = new HeadlessContext(display);
+ }
+ else
+ {
+ context = new DefaultContext();
+ }
+
+ return context;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/HeadlessContext.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/HeadlessContext.java
new file mode 100644
index 0000000..d18abe3
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/contexts/HeadlessContext.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.contexts;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.launcher.commands.headless.XvncException;
+import org.apache.royale.test.ant.launcher.commands.headless.XvncStartCommand;
+import org.apache.royale.test.ant.launcher.commands.headless.XvncStopCommand;
+import org.apache.royale.test.ant.launcher.commands.player.PlayerCommand;
+
+/**
+ * Context used to wrap a call to the player command in a start and stop of a vncserver.
+ * All vncserver commands are blocking.
+ */
+public class HeadlessContext implements ExecutionContext
+{
+ private PlayerCommand playerCommand;
+ private int startDisplay;
+ private int finalDisplay;
+ private Project project;
+
+ public HeadlessContext(int display)
+ {
+ this.startDisplay = display;
+ }
+
+ public void setProject(Project project)
+ {
+ this.project = project;
+ }
+
+ public void setCommand(PlayerCommand command)
+ {
+ this.playerCommand = command;
+ }
+
+ public void start() throws IOException
+ {
+ // setup vncserver on the provided display
+ XvncStartCommand xvncStart = new XvncStartCommand(startDisplay);
+ xvncStart.setProject(project);
+
+ LoggingUtil.log("Starting xvnc", true);
+
+ // execute the maximum number of cycle times before throwing an exception
+ while (xvncStart.execute() != 0)
+ {
+ LoggingUtil.log("Cannot start xnvc on :" + xvncStart.getCurrentDisplay() + ", cycling ...");
+
+ try
+ {
+ xvncStart.cycle();
+ }
+ catch (XvncException xe) {
+ throw new IOException(xe);
+ }
+ }
+
+ finalDisplay = xvncStart.getCurrentDisplay();
+
+ //setup player command to use the right display in its env when launching
+ playerCommand.setEnvironment(new String[]{ "DISPLAY=:" + finalDisplay });
+ LoggingUtil.log("Setting DISPLAY=:" + finalDisplay);
+
+ //prep anything the command needs to run
+ playerCommand.prepare();
+ }
+
+ public void stop(Process playerProcess) throws IOException
+ {
+ // destroy the process related to the player if it exists
+ if(playerProcess != null)
+ {
+ playerProcess.destroy();
+ }
+
+ // Now stop the vncserver that the player has been destroyed
+ XvncStopCommand xvncStop = new XvncStopCommand(finalDisplay);
+ xvncStop.setProject(project);
+ xvncStop.execute();
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/LinuxDefaults.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/LinuxDefaults.java
new file mode 100644
index 0000000..8d78688
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/LinuxDefaults.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.platforms;
+
+import java.io.File;
+
+public class LinuxDefaults implements PlatformDefaults
+{
+
+ public String getAdlCommand()
+ {
+ return "adl";
+ }
+
+ public File getFlashPlayerGlobalTrustDirectory()
+ {
+ return new File("/etc/adobe/FlashPlayerTrust/");
+ }
+
+ public File getFlashPlayerUserTrustDirectory()
+ {
+ File file = null;
+
+ String home = System.getenv("HOME");
+ if(home != null && !home.equals(""))
+ {
+ file = new File(home + "/.macromedia/Flash_Player/#Security/FlashPlayerTrust/");
+ }
+
+ return file;
+ }
+
+ public String getOpenCommand()
+ {
+ return "gflashplayer";
+ }
+
+ public String[] getOpenSystemArguments()
+ {
+ return new String[]{};
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/MacOSXDefaults.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/MacOSXDefaults.java
new file mode 100644
index 0000000..385cb28
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/MacOSXDefaults.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.platforms;
+
+import java.io.File;
+
+public class MacOSXDefaults implements PlatformDefaults
+{
+
+ public String getAdlCommand()
+ {
+ return "adl";
+ }
+
+ public File getFlashPlayerGlobalTrustDirectory()
+ {
+ return new File("/Library/Application Support/Macromedia/FlashPlayerTrust/");
+ }
+
+ public File getFlashPlayerUserTrustDirectory()
+ {
+ File file = null;
+
+ String home = System.getenv("HOME");
+ if(home != null && !home.equals(""))
+ {
+ file = new File(home + "/Library/Preferences/Macromedia/Flash Player/#Security/FlashPlayerTrust/");
+ }
+
+ return file;
+ }
+
+ public String getOpenCommand()
+ {
+ return "open";
+ }
+
+ public String[] getOpenSystemArguments()
+ {
+ return new String[]{};
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/PlatformDefaults.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/PlatformDefaults.java
new file mode 100644
index 0000000..49f2e44
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/PlatformDefaults.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.platforms;
+
+import java.io.File;
+
+public interface PlatformDefaults
+{
+ public File getFlashPlayerUserTrustDirectory();
+ public File getFlashPlayerGlobalTrustDirectory();
+ public String getOpenCommand();
+ public String[] getOpenSystemArguments();
+ public String getAdlCommand();
+ //public String getFlashPlayerCommand();
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/WindowsDefaults.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/WindowsDefaults.java
new file mode 100644
index 0000000..fd7def0
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/launcher/platforms/WindowsDefaults.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.launcher.platforms;
+
+import java.io.File;
+
+public class WindowsDefaults implements PlatformDefaults
+{
+
+ public String getAdlCommand()
+ {
+ return "adl.exe";
+ }
+
+ public File getFlashPlayerGlobalTrustDirectory()
+ {
+ return new File(System.getenv("SYSTEMROOT") + "\\system32\\Macromed\\Flash\\FlashPlayerTrust\\");
+ }
+
+ public File getFlashPlayerUserTrustDirectory()
+ {
+ File file = null;
+
+ String appData = System.getenv("APPDATA");
+ if(appData != null && !appData.equals(""))
+ {
+ file = new File(appData + "\\Macromedia\\Flash Player\\#Security\\FlashPlayerTrust\\");
+ }
+
+ return file;
+ }
+
+ public String getOpenCommand()
+ {
+ return "rundll32";
+ }
+
+ public String[] getOpenSystemArguments()
+ {
+ return new String[]{"url.dll,FileProtocolHandler"};
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Report.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Report.java
new file mode 100644
index 0000000..a608072
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Report.java
@@ -0,0 +1,252 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.report;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.DateUtils;
+import org.dom4j.Document;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.dom4j.io.OutputFormat;
+import org.dom4j.io.XMLWriter;
+import org.apache.royale.test.ant.LoggingUtil;
+
+public class Report
+{
+ private static final String FAILURE = "failure";
+ private static final String ERROR = "error";
+ private static final String IGNORE = "ignore";
+
+ private static final String TEST_SUITE = "testsuite";
+ private static final String NAME_ATTRIBUTE_LABEL = "name";
+ private static final String FAILURE_ATTRIBUTE_LABEL = "failures";
+ private static final String ERROR_ATTRIBUTE_LABEL = "errors";
+ private static final String IGNORE_ATTRIBUTE_LABEL = "skipped";
+ private static final String TIME_ATTRIBUTE_LABEL = "time";
+ private static final String TESTS_ATTRIBUTE_LABEL = "tests";
+ private static final String HOSTNAME_ATTRIBUTE_LABEL = "hostname";
+ private static final String TIMESTAMP_ATTRIBUTE_LABEL = "timestamp";
+
+ private static final String FILENAME_PREFIX = "TEST-";
+ private static final String FILENAME_EXTENSION = ".xml";
+
+ // Exception messages
+ private static final String FAILED_TEST = "RoyaleUnit test {0} in suite {1} failed.";
+ private static final String ERRORED_TEST = "RoyaleUnit test {0} in suite {1} had errors.";
+ private static final String IGNORED_TEST = "RoyaleUnit test {0} in suite {1} was ignored.";
+ private static final String TEST_INFO = "Suite: {0}\nTests run: {1}, Failures: {2}, Errors: {3}, Skipped: {4}, Time elapsed: {5} sec";
+ private static final String ERROR_SAVING_REPORT = "Error saving report.";
+
+ // XML attribute labels
+ private static final String CLASSNAME_ATTRIBUTE = "classname";
+ private static final String NAME_ATTRIBUTE = "name";
+ private static final String STATUS_ATTRIBUTE = "status";
+ private static final String TIME_ATTRIBUTE = "time";
+
+ protected Suite suite;
+ private Document document;
+ private List<String> recordedRuns;
+
+ public Report(Suite suite)
+ {
+ this.recordedRuns = new ArrayList<String>();
+ this.suite = suite;
+
+ // Create a new XML document
+ document = DocumentHelper.createDocument();
+
+ // Add the test suite attributes to the document
+ document
+ .addElement(TEST_SUITE)
+ .addAttribute(NAME_ATTRIBUTE_LABEL, suite.getName())
+ .addAttribute(TESTS_ATTRIBUTE_LABEL,
+ String.valueOf(suite.getTests()))
+ .addAttribute(FAILURE_ATTRIBUTE_LABEL,
+ String.valueOf(suite.getFailures()))
+ .addAttribute(ERROR_ATTRIBUTE_LABEL,
+ String.valueOf(suite.getErrors()))
+ .addAttribute(IGNORE_ATTRIBUTE_LABEL,
+ String.valueOf(suite.getSkips()))
+ .addAttribute(TIME_ATTRIBUTE_LABEL, String.valueOf(suite.getTime()));
+ }
+
+ /**
+ * Adds the test to the suite report given an XML test document
+ */
+ public void addTest(Document test)
+ {
+ Element root = test.getRootElement();
+
+ // Add to the number of tests in this suite if not seen and not null
+ String testMethod = root.attributeValue(NAME_ATTRIBUTE);
+ if(!recordedRuns.contains(testMethod) && !testMethod.equals("null"))
+ {
+ recordedRuns.add(testMethod);
+ suite.addTest();
+ }
+
+ //add test time to total time
+ long time = Long.parseLong(root.attributeValue(TIME_ATTRIBUTE));
+ suite.addTime(time);
+ root.attribute(TIME_ATTRIBUTE).setText(formatTime(time));
+
+ //If the test method name is null, then make it the classname
+ if(root.attributeValue(NAME_ATTRIBUTE).equals("null"))
+ {
+ root.attribute(NAME_ATTRIBUTE).setText(root.attributeValue(CLASSNAME_ATTRIBUTE));
+ }
+
+ // Add the test to the report document
+ document.getRootElement().add(root);
+
+ // Check for special status adjustments to make to suite
+ checkForStatus(test);
+
+ //remove status attribute since it's only used by the report
+ root.remove(root.attribute(STATUS_ATTRIBUTE));
+ }
+
+ private String formatTime(long time)
+ {
+ return String.format("%.3f", new Double(time / 1000.0000));
+ }
+
+ /**
+ * Updates counts for failed, error, and ignore on suite as well as logs what
+ * failed if told to use logging.
+ *
+ * @param test
+ * Test XML document
+ */
+ private void checkForStatus(Document test)
+ {
+ // Get the root element and pull the test name and status
+ final Element root = test.getRootElement();
+ final String name = root.attributeValue(NAME_ATTRIBUTE);
+ final String status = root.attributeValue(STATUS_ATTRIBUTE);
+
+ String format = null;
+ if (status.equals(FAILURE))
+ {
+ format = FAILED_TEST;
+ suite.addFailure();
+ }
+ else if (status.equals(ERROR))
+ {
+ format = ERRORED_TEST;
+ suite.addError();
+ }
+ else if (status.equals(IGNORE))
+ {
+ format = IGNORED_TEST;
+ suite.addSkip();
+ }
+
+ // Creates the fail message for use with verbose
+ if (format != null)
+ {
+ final String message = MessageFormat.format(format, new Object[]
+ { name, suite });
+ LoggingUtil.log(message);
+ }
+ }
+
+ /**
+ * Determines if any failures (errors or failures) have occurred in this
+ * report.
+ */
+ public boolean hasFailures()
+ {
+ return (suite.getErrors() > 0 || suite.getFailures() > 0);
+ }
+
+ /**
+ * Write the report XML document out to file
+ *
+ * @param reportDir
+ * Directory to hold report file.
+ */
+ public void save(File reportDir) throws BuildException
+ {
+ try
+ {
+ // Open the file matching the parameter suite
+ final File file = new File(reportDir, FILENAME_PREFIX + suite + FILENAME_EXTENSION);
+
+ // Retrieve the root element and adjust the failures and test attributes
+ Element root = document.getRootElement();
+ root.addAttribute(FAILURE_ATTRIBUTE_LABEL, String.valueOf(suite.getFailures()));
+ root.addAttribute(ERROR_ATTRIBUTE_LABEL, String.valueOf(suite.getErrors()));
+ root.addAttribute(TESTS_ATTRIBUTE_LABEL, String.valueOf(suite.getTests()));
+ root.addAttribute(IGNORE_ATTRIBUTE_LABEL, String.valueOf(suite.getSkips()));
+ root.addAttribute(TIME_ATTRIBUTE_LABEL, String.valueOf(formatTime(suite.getTime())));
+ root.addAttribute(HOSTNAME_ATTRIBUTE_LABEL, getHostname());
+
+ final String timestamp = DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN);
+ root.addAttribute(TIMESTAMP_ATTRIBUTE_LABEL, timestamp);
+
+ // Write the updated suite
+ final OutputFormat format = OutputFormat.createPrettyPrint();
+ final XMLWriter writer = new XMLWriter(new FileOutputStream(file), format);
+ writer.write(document);
+ writer.close();
+ }
+ catch (Exception e)
+ {
+ throw new BuildException(ERROR_SAVING_REPORT, e);
+ }
+ }
+
+ private String getHostname()
+ {
+ try
+ {
+ return InetAddress.getLocalHost().getHostName();
+ } catch (UnknownHostException e)
+ {
+ return "localhost";
+ }
+ }
+
+ public String getSummary()
+ {
+ String summary = "";
+
+ try
+ {
+ summary = MessageFormat.format(TEST_INFO, new Object[]
+ { new String(suite.getName()), new Integer(suite.getTests()),
+ new Integer(suite.getFailures()),
+ new Integer(suite.getErrors()), new Integer(suite.getSkips()),
+ formatTime(suite.getTime()) });
+ } catch (Exception e)
+ {
+ // ignore
+ }
+
+ return summary;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Reports.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Reports.java
new file mode 100644
index 0000000..3184097
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Reports.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.report;
+
+import java.text.MessageFormat;
+import java.util.HashMap;
+
+/**
+ * Aggregate class representing a collection of Reports stored in a Map<String, Report>
+ */
+public class Reports extends HashMap<String, Report>
+{
+ private static final long serialVersionUID = 2078272511659655555L;
+ private static final String TEST_INFO = "Tests run: {0}, Failures: {1}, Errors: {2}, Skipped: {3}, Time elapsed: {4} sec";
+
+ public Reports()
+ {
+ super();
+ }
+
+ /**
+ * String version of all reports.
+ */
+ public String getSummary()
+ {
+ String summary = "";
+ int runs = 0;
+ int errors = 0;
+ int failures = 0;
+ int skips = 0;
+ long time = 0;
+
+ for(Report report : this.values())
+ {
+ runs += report.suite.getTests();
+ errors += report.suite.getErrors();
+ failures += report.suite.getFailures();
+ skips += report.suite.getSkips();
+ time += report.suite.getTime();
+
+ summary += report.getSummary() + "\n";
+ }
+
+ summary += "\nResults :\n\n";
+
+ try
+ {
+ summary += MessageFormat.format(TEST_INFO, new Object[] {
+ new Integer(runs),
+ new Integer(failures),
+ new Integer(errors),
+ new Integer(skips),
+ formatTime(time)
+ });
+ }
+ catch(Exception e)
+ {
+ summary += "Error occurred while generating summary ...";
+ }
+
+ summary += "\n";
+
+ return summary;
+ }
+
+ private String formatTime(long time)
+ {
+ return String.format("%.3f", new Double(time / 1000.0000));
+ }
+
+ /**
+ * Determines if any reports have failures
+ */
+ public boolean hasFailures()
+ {
+ for(Report report : this.values())
+ {
+ if(report.hasFailures())
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Suite.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Suite.java
new file mode 100644
index 0000000..fe9bd28
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/report/Suite.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.report;
+
+public class Suite
+{
+ private String _name;
+ private int _tests = 0;
+ private int _failures = 0;
+ private int _errors = 0;
+ private int _skips = 0;
+ private long _time = 0;
+
+ public Suite(String name)
+ {
+ super();
+ _name = name;
+ }
+
+ public void addTest()
+ {
+ _tests++;
+ }
+
+ public void addFailure()
+ {
+ _failures++;
+ }
+
+ public void addError()
+ {
+ _errors++;
+ }
+
+ public void addSkip()
+ {
+ _skips++;
+ }
+
+ public String getName()
+ {
+ return _name;
+ }
+
+ public int getTests()
+ {
+ return _tests;
+ }
+
+ public int getFailures()
+ {
+ return _failures;
+ }
+
+ public int getErrors()
+ {
+ return _errors;
+ }
+
+ public int getSkips()
+ {
+ return _skips;
+ }
+
+ public long getTime()
+ {
+ return _time;
+ }
+
+ public void addTime(long time)
+ {
+ _time += time;
+ }
+
+ @Override
+ public String toString()
+ {
+ return _name;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/Compilation.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/Compilation.java
new file mode 100644
index 0000000..e20cf71
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/Compilation.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.taskdefs.Java;
+import org.apache.tools.ant.types.FilterSet;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Commandline.Argument;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.URLResource;
+import org.apache.tools.ant.util.ResourceUtils;
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.tasks.configuration.CompilationConfiguration;
+
+public class Compilation
+{
+ private final String BASIC_APPLICATION_CLASS = "Application";
+ private final String MXML2006_PREFIX = "mx";
+ private final String MXML2006_NAMESPACE="xmlns:" + MXML2006_PREFIX + "=\"http://www.adobe.com/2006/mxml\"";
+ private final String MXML2009_PREFIX = "fx";
+ private final String MXML2009_NAMESPACE="xmlns:" + MXML2009_PREFIX + "=\"http://ns.adobe.com/mxml/2009\"";
+ private final String BASIC_PREFIX = "js";
+ private final String BASIC_NAMESPACE = "xmlns:" + BASIC_PREFIX + "=\"library://ns.apache.org/royale/basic\"";
+ private final String CI_LISTENER = "CIListener";
+ private final String AIR_CI_LISTENER = "AirCIListener";
+ private final String TESTRUNNER_TEMPLATE = "TestRunner.template";
+ private final String TESTRUNNER_FILE = "TestRunner.mxml";
+ private final String MXMLC_RELATIVE_PATH = "lib/mxmlc.jar";
+ private final String FRAMEWORKS_RELATIVE_PATH = "frameworks";
+ private final String SWF_FILENAME = "TestRunner.swf";
+
+ private CompilationConfiguration configuration;
+ private Project project;
+ private String mxmlcPath;
+
+ public Compilation(Project project, CompilationConfiguration configuration)
+ {
+ this.project = project;
+ this.configuration = configuration;
+ mxmlcPath = configuration.getRoyaleHome().getAbsolutePath() + File.separatorChar + MXMLC_RELATIVE_PATH;
+ }
+
+ public File compile() throws BuildException
+ {
+ configuration.log();
+
+ File runnerFile = generateTestRunnerFromTemplate(configuration.getWorkingDir());
+ File finalFile = new File(configuration.getWorkingDir().getAbsolutePath() + File.separatorChar + SWF_FILENAME);
+
+ Java compilationTask = createJavaTask(runnerFile, finalFile);
+ LoggingUtil.log("Compiling test classes: [" + configuration.getTestSources().getCanonicalClasses(", ") + "]", true);
+ LoggingUtil.log(compilationTask.getCommandLine().describeCommand());
+
+ if(compilationTask.executeJava() != 0)
+ {
+ throw new BuildException("Compilation failed:\n" + project.getProperty("MXMLC_ERROR"));
+ }
+
+ return finalFile;
+ }
+
+ private File generateTestRunnerFromTemplate(File workingDir) throws BuildException
+ {
+ try
+ {
+ int sdkVersion = getSDKVersion();
+
+ String namespaces = MXML2009_NAMESPACE + "\n" + BASIC_NAMESPACE;
+ String ciListener = configuration.getPlayer().equals("flash") ? CI_LISTENER : AIR_CI_LISTENER;
+
+ File runner = new File(workingDir.getAbsolutePath() + File.separatorChar + TESTRUNNER_FILE);
+
+ //Template location in JAR
+ URLResource template = new URLResource(getClass().getResource("/" + TESTRUNNER_TEMPLATE));
+
+ //Create tokens to filter
+ FilterSet filters = new FilterSet();
+ filters.addFilter("APPLICATION_PREFIX", BASIC_PREFIX);
+ filters.addFilter("APPLICATION_CLASS", BASIC_APPLICATION_CLASS);
+ filters.addFilter("NAMESPACES", namespaces);
+ filters.addFilter("MXML_PREFIX", MXML2009_PREFIX);
+ filters.addFilter("CI_LISTENER_CLASS", ciListener);
+ filters.addFilter("CLASS_REFS", configuration.getTestSources().getClasses());
+ filters.addFilter("IMPORT_REFS", configuration.getTestSources().getImports());
+
+ //Copy descriptor template to SWF folder performing token replacement
+ ResourceUtils.copyResource(
+ template,
+ new FileResource(runner),
+ new FilterSetCollection(filters),
+ null,
+ true,
+ false,
+ null,
+ null,
+ project
+ );
+
+ LoggingUtil.log("Created test runner at [" + runner.getAbsolutePath() + "]");
+
+ return runner;
+ }
+ catch (Exception e)
+ {
+ throw new BuildException("Could not create test runner from template.", e);
+ }
+ }
+
+ private int getSDKVersion()
+ {
+ String outputProperty = "SDK_VERSION";
+
+ //Execute mxmlc to find SDK version number
+ Java task = new Java();
+ task.setFork(true);
+ task.setFailonerror(true);
+ task.setJar(new File(mxmlcPath));
+ task.setProject(project);
+ task.setDir(project.getBaseDir());
+ task.setOutputproperty(outputProperty);
+
+ Argument versionArgument = task.createArg();
+ versionArgument.setValue("--version");
+
+ task.execute();
+
+ //Parse version number and return as int
+ String output = project.getProperty(outputProperty);
+ int prefixIndex = output.indexOf("Version ");
+ int version = Integer.parseInt(output.substring(prefixIndex + 8, prefixIndex + 9));
+
+ LoggingUtil.log("Found SDK version: " + version);
+
+ return version;
+ }
+
+ private Java createJavaTask(File runnerFile, File finalFile)
+ {
+ String frameworksPath = configuration.getRoyaleHome().getAbsolutePath() + File.separatorChar + FRAMEWORKS_RELATIVE_PATH;
+
+ Java task = new Java();
+ task.setFork(true);
+ task.setFailonerror(true);
+ task.setJar(new File(mxmlcPath));
+ task.setProject(project);
+ task.setDir(project.getBaseDir());
+ task.setMaxmemory("256M"); //MXMLC needs to eat
+ task.setErrorProperty("MXMLC_ERROR");
+
+ Argument royaleLibArgument = task.createArg();
+ royaleLibArgument.setLine("+royalelib \"" + frameworksPath + "\"");
+
+ if(configuration.getPlayer().equals("air"))
+ {
+ Argument airConfigArgument = task.createArg();
+ airConfigArgument.setValue("+configname=air");
+ }
+
+ Argument outputFile = task.createArg();
+ outputFile.setLine("-output \"" + finalFile.getAbsolutePath() + "\"");
+
+ Argument sourcePath = task.createArg();
+ sourcePath.setLine("-source-path " + configuration.getSources().getPathElements(" ") + " " + configuration.getTestSources().getPathElements(" "));
+
+ determineLibraryPath( task );
+
+ determineLoadConfigArgument( task );
+
+ Argument debug = task.createArg();
+ debug.setLine( "-debug=" + configuration.getDebug() );
+
+ Argument headlessServer = task.createArg();
+ headlessServer.setLine("-headless-server=true");
+
+
+ Argument mainFile = task.createArg();
+ mainFile.setValue(runnerFile.getAbsolutePath());
+
+ return task;
+ }
+
+
+ private void determineLoadConfigArgument(Java java)
+ {
+ if(configuration.getLoadConfig() != null)
+ {
+ Argument argument = java.createArg();
+ argument.setLine(configuration.getLoadConfig().getCommandLineArgument());
+ }
+ }
+
+ private void determineLibraryPath(Java java)
+ {
+ if(!configuration.getLibraries().getPathElements(" -library-path+=").isEmpty())
+ {
+ Argument libraryPath = java.createArg();
+ libraryPath.setLine("-library-path+=" + configuration.getLibraries().getPathElements(" -library-path+="));
+ }
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/RoyaleUnitTask.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/RoyaleUnitTask.java
new file mode 100644
index 0000000..d01e03a
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/RoyaleUnitTask.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicElement;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.royale.test.ant.tasks.configuration.TaskConfiguration;
+import org.apache.royale.test.ant.tasks.types.LoadConfig;
+
+public class RoyaleUnitTask extends Task implements DynamicElement
+{
+ private TaskConfiguration configuration;
+
+ public RoyaleUnitTask()
+ {
+ }
+
+ @Override
+ public void setProject(Project project)
+ {
+ super.setProject(project);
+ configuration = new TaskConfiguration(project);
+ }
+
+ /**
+ * Sets local trusted, default is false
+ *
+ * @param localTrusted
+ */
+ public void setLocalTrusted(final boolean localTrusted)
+ {
+ configuration.setLocalTrusted(localTrusted);
+ }
+
+ /**
+ * Set the port to receive the test results on. Default is 1024
+ *
+ * @param serverPort
+ * the port to set.
+ */
+ public void setPort(final int serverPort)
+ {
+ configuration.setPort(serverPort);
+ }
+
+ /**
+ * Set the timeout for receiving the royaleunit report.
+ *
+ * @param timeout
+ * in milliseconds.
+ */
+ public void setTimeout(final int timeout)
+ {
+ configuration.setSocketTimeout(timeout);
+ }
+
+ /**
+ * The buffer size the {@RoyaleUnitSocketServer} uses
+ * for its inbound data stream.
+ */
+ public void setBuffer(final int size)
+ {
+ configuration.setServerBufferSize(size);
+ }
+
+ /**
+ * The SWF for the RoyaleUnit tests to run.
+ *
+ * @param testSWF
+ * the SWF to set.
+ */
+ public void setSWF(final String testSWF)
+ {
+ configuration.setSwf(testSWF);
+ }
+
+ /**
+ * Set the directory to output the test reports to.
+ *
+ * @param toDir
+ * the directory to set.
+ */
+ public void setToDir(final String toDir)
+ {
+ configuration.setReportDir(toDir);
+ }
+
+ /**
+ * Should we fail the build if the royale tests fail?
+ *
+ * @param fail
+ */
+ public void setHaltonfailure(final boolean fail)
+ {
+ configuration.setFailOnTestFailure(fail);
+ }
+
+ /**
+ * Custom ant property noting test failure
+ *
+ * @param failprop
+ */
+ public void setFailureproperty(final String failprop)
+ {
+ configuration.setFailureProperty(failprop);
+ }
+
+ /**
+ * Toggle display of descriptive messages
+ *
+ * @param verbose
+ */
+ public void setVerbose(final boolean verbose)
+ {
+ configuration.setVerbose(verbose);
+ }
+
+ public void setPlayer(String player)
+ {
+ configuration.setPlayer(player);
+ }
+
+ public void setCommand(String executableFilePath)
+ {
+ configuration.setCommand(executableFilePath);
+ }
+
+ public void setHeadless(boolean headless)
+ {
+ configuration.setHeadless(headless);
+ }
+
+ public void setDisplay(int number)
+ {
+ configuration.setDisplay(number);
+ }
+
+ public void addSource(FileSet fileset)
+ {
+ configuration.addSource(fileset);
+ }
+
+ public void addTestSource(FileSet fileset)
+ {
+ configuration.addTestSource(fileset);
+ }
+
+ public void addLibrary(FileSet fileset)
+ {
+ configuration.addLibrary(fileset);
+ }
+
+ public void setWorkingDir(String workingDirPath)
+ {
+ configuration.setWorkingDir(workingDirPath);
+ }
+
+ /**
+ * Called by Ant to execute the task.
+ */
+ public void execute() throws BuildException
+ {
+ //verify entire configuration
+ configuration.verify();
+
+ //compile tests if necessary
+ if(configuration.shouldCompile())
+ {
+ Compilation compilation = new Compilation(getProject(), configuration.getCompilationConfiguration());
+ configuration.setSwf(compilation.compile());
+ }
+
+ //executes tests
+ TestRun testRun = new TestRun(getProject(), configuration.getTestRunConfiguration());
+ testRun.run();
+ }
+
+ public void setDebug(boolean value)
+ {
+ configuration.setDebug(value);
+ }
+
+ public Object createDynamicElement(String arg0) throws BuildException
+ {
+ if("load-config".equals(arg0))
+ {
+ LoadConfig loadconfig = new LoadConfig();
+ configuration.setLoadConfig(loadconfig);
+ return loadconfig;
+ }
+ else
+ {
+ throw new BuildException( "The <royaleUnit> type doesn't support the " + arg0 + "nested element");
+ }
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/TestRun.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/TestRun.java
new file mode 100644
index 0000000..531474b
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/TestRun.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.royale.test.ant.RoyaleUnitSocketServer;
+import org.apache.royale.test.ant.RoyaleUnitSocketThread;
+import org.apache.royale.test.ant.RoyaleUnitWebSocketServer;
+import org.apache.royale.test.ant.IRoyaleUnitServer;
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.launcher.commands.player.AdlCommand;
+import org.apache.royale.test.ant.launcher.commands.player.PlayerCommand;
+import org.apache.royale.test.ant.launcher.commands.player.PlayerCommandFactory;
+import org.apache.royale.test.ant.launcher.contexts.ExecutionContext;
+import org.apache.royale.test.ant.launcher.contexts.ExecutionContextFactory;
+import org.apache.royale.test.ant.report.Reports;
+import org.apache.royale.test.ant.tasks.configuration.TestRunConfiguration;
+
+public class TestRun
+{
+ private final String TRUE = "true";
+
+ private TestRunConfiguration configuration;
+ private Project project;
+
+ private Reports reports;
+
+ public TestRun(Project project, TestRunConfiguration configuration)
+ {
+ this.project = project;
+ this.configuration = configuration;
+ this.reports = new Reports();
+ }
+
+ public void run() throws BuildException
+ {
+ configuration.log();
+
+ try
+ {
+ // setup daemon
+ Future<Object> daemon = setupSocketThread();
+
+ // run the execution context and player
+ PlayerCommand player = obtainPlayer();
+ ExecutionContext context = obtainContext(player);
+
+ //start the execution context
+ context.start();
+
+ //launch the player
+ Process process = player.launch();
+
+ try
+ {
+ // block until daemon is completely done with all test data
+ daemon.get();
+ }
+ finally
+ {
+ //stop the execution context now that socket thread is done
+ context.stop(process);
+ }
+
+ // print summaries and check for failure
+ analyzeReports();
+
+ }
+ catch (Exception e)
+ {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Fetch the player command to execute the SWF.
+ *
+ * @return PlayerCommand based on user config
+ */
+ protected PlayerCommand obtainPlayer()
+ {
+ // get command from factory
+ PlayerCommand command = PlayerCommandFactory.createPlayer(
+ configuration.getOs(),
+ configuration.getPlayer(),
+ configuration.getCommand(),
+ configuration.isLocalTrusted());
+
+ command.setProject(project);
+ command.setSwf(configuration.getSwf());
+ command.setUrl(configuration.getUrl());
+
+ if(command instanceof AdlCommand)
+ {
+ ((AdlCommand)command).setPrecompiledAppDescriptor(configuration.getPrecompiledAppDescriptor());
+ }
+
+ return command;
+ }
+
+ /**
+ *
+ * @param player PlayerCommand which should be executed
+ * @return Context to wrap the execution of the PlayerCommand
+ */
+ protected ExecutionContext obtainContext(PlayerCommand player)
+ {
+ ExecutionContext context = ExecutionContextFactory.createContext(
+ configuration.getOs(),
+ configuration.isHeadless(),
+ configuration.getDisplay());
+
+ context.setProject(project);
+ context.setCommand(player);
+
+ return context;
+ }
+
+ /**
+ * Create a server socket for receiving the test reports from RoyaleUnit. We
+ * read and write the test reports inside of a Thread.
+ */
+ protected Future<Object> setupSocketThread()
+ {
+ LoggingUtil.log("Setting up server process ...");
+
+ // Create server for use by thread
+ IRoyaleUnitServer server = null;
+ if(configuration.getPlayer().equals("html"))
+ {
+ server = new RoyaleUnitWebSocketServer(
+ configuration.getPort(), configuration.getSocketTimeout());
+ }
+ else
+ {
+ server = new RoyaleUnitSocketServer(configuration.getPort(),
+ configuration.getSocketTimeout(), configuration.getServerBufferSize(),
+ configuration.usePolicyFile());
+ }
+
+ // Get handle to specialized object to run in separate thread.
+ Callable<Object> operation = new RoyaleUnitSocketThread(server,
+ configuration.getReportDir(), reports);
+
+ // Get handle to service to run object in thread.
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ // Run object in thread and return Future.
+ return executor.submit(operation);
+ }
+
+ /**
+ * End of test report run. Called at the end of a test run. If verbose is set
+ * to true reads all suites in the suite list and prints out a descriptive
+ * message including the name of the suite, number of tests run and number of
+ * tests failed, ignores any errors. If any tests failed during the test run,
+ * the build is halted.
+ */
+ protected void analyzeReports()
+ {
+ LoggingUtil.log("Analyzing reports ...");
+
+ // print out all report summaries
+ LoggingUtil.log("\n" + reports.getSummary(), true);
+
+ if (reports.hasFailures())
+ {
+ project.setNewProperty(configuration.getFailureProperty(), TRUE);
+
+ if (configuration.isFailOnTestFailure())
+ {
+ throw new BuildException("RoyaleUnit tests failed during the test run.");
+ }
+ }
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/CompilationConfiguration.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/CompilationConfiguration.java
new file mode 100644
index 0000000..9013625
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/CompilationConfiguration.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.configuration;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.tasks.types.LibraryPaths;
+import org.apache.royale.test.ant.tasks.types.LoadConfig;
+import org.apache.royale.test.ant.tasks.types.SourcePaths;
+
+public class CompilationConfiguration implements StepConfiguration
+{
+ private SourcePaths sources;
+ private SourcePaths testSources;
+ private LibraryPaths libraries;
+ private File royaleHome;
+ private String player;
+ private File workingDir;
+
+ public CompilationConfiguration()
+ {
+ sources = new SourcePaths();
+ testSources = new SourcePaths();
+ libraries = new LibraryPaths();
+ debug = false;
+ }
+
+ public File getRoyaleHome()
+ {
+ return royaleHome;
+ }
+
+ public void setRoyaleHome(File royaleHome)
+ {
+ this.royaleHome = royaleHome;
+ }
+
+ public void addLibrary(FileSet fileset)
+ {
+ this.libraries.add(fileset);
+ }
+
+ public LibraryPaths getLibraries()
+ {
+ return libraries;
+ }
+
+ public String getPlayer()
+ {
+ return player;
+ }
+
+ public void setPlayer(String player)
+ {
+ this.player = player;
+ }
+
+ public void addSource(FileSet fileset)
+ {
+ this.sources.add(fileset);
+ }
+
+ public SourcePaths getSources()
+ {
+ return sources;
+ }
+
+ public void addTestSource(FileSet fileset)
+ {
+ this.testSources.add(fileset);
+ }
+
+ public SourcePaths getTestSources()
+ {
+ return testSources;
+ }
+
+ public void setWorkingDir(File workingDir)
+ {
+ this.workingDir = workingDir;
+ }
+
+ public File getWorkingDir()
+ {
+ return workingDir;
+ }
+
+ public void validate() throws BuildException
+ {
+ if(!testSources.exists())
+ {
+ throw new BuildException("One of the directories specified as a 'testSource' element does not exist.");
+ }
+
+ if(testSources.exists() && testSources.isEmpty())
+ {
+ throw new BuildException("No test files could be found for the provided 'testSource' elements.");
+ }
+
+ if(!libraries.exists())
+ {
+ throw new BuildException("One of the directories specified as a 'library' element does not exist.");
+ }
+
+ if(libraries.exists() && libraries.isEmpty() && loadConfig == null)
+ {
+ throw new BuildException("'library' elements not specified or 'load-config' element not specified. Also possible no SWC files could be found for the provided 'library' elements.");
+ }
+ }
+
+ public void log()
+ {
+ LoggingUtil.log("Using the following settings for compilation:");
+ LoggingUtil.log("\tROYALE_HOME: [" + royaleHome.getAbsolutePath() + "]");
+ LoggingUtil.log("\tplayer: [" + player + "]");
+ LoggingUtil.log("\tsourceDirectories: [" + sources.getPathElements(",") + "]");
+ LoggingUtil.log("\ttestSourceDirectories: [" + testSources.getPathElements(",") + "]");
+ LoggingUtil.log("\tlibraries: [" + libraries.getPathElements(",") + "]");
+ }
+
+ private boolean debug;
+ public boolean getDebug()
+ {
+ return debug;
+ }
+
+ public void setDebug(boolean value)
+ {
+ debug = value;
+ }
+
+ private LoadConfig loadConfig;
+ public void setLoadConfig(LoadConfig loadconfig)
+ {
+ loadConfig = loadconfig;
+ }
+
+ public LoadConfig getLoadConfig()
+ {
+ return loadConfig;
+ }
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/StepConfiguration.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/StepConfiguration.java
new file mode 100644
index 0000000..ea58a9c
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/StepConfiguration.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.configuration;
+
+import org.apache.tools.ant.BuildException;
+
+public interface StepConfiguration
+{
+ public void validate() throws BuildException;
+ public void log();
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/TaskConfiguration.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/TaskConfiguration.java
new file mode 100644
index 0000000..4bf24d0
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/TaskConfiguration.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.configuration;
+
+import java.io.File;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.FileSet;
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.tasks.types.LoadConfig;
+
+public class TaskConfiguration
+{
+ private final String DEFAULT_WORKING_PATH = ".";
+ private final String DEFAULT_REPORT_PATH = ".";
+ private final List<String> VALID_PLAYERS = Arrays.asList(new String[]{"flash", "air", "html"});
+
+ private String player = "flash";
+ private File reportDir = null;
+ private File workingDir = null;
+ private boolean verbose = false;
+ private File royaleHome = null;
+
+ private Project project;
+ private CompilationConfiguration compilationConfiguration;
+ private TestRunConfiguration testRunConfiguration;
+
+ public TaskConfiguration(Project project)
+ {
+ this.project = project;
+ this.compilationConfiguration = new CompilationConfiguration();
+ this.testRunConfiguration = new TestRunConfiguration();
+
+ if(project.getProperty("ROYALE_HOME") != null)
+ {
+ this.royaleHome = new File(project.getProperty("ROYALE_HOME"));
+ }
+ }
+
+ //Used to verify that a string is also a properly formatted URL
+ //When determining if the passed 'swf' property value is remote or local this is crucial.
+ protected boolean isValidURL(String urlStr ) {
+ try {
+ URL url = new URL( urlStr );
+ LoggingUtil.log("my protocol " + url.getProtocol().toString() );
+ if( url.getProtocol().toUpperCase().equals("HTTP") || url.getProtocol().toUpperCase().equals("HTTPS") ) {
+ LoggingUtil.log("Valid URL returning TRUE" );
+ return true;
+ } else {
+ //no protocol so this isn't a URL at all, it might a local path or an invalid address
+ LoggingUtil.log("Valid URL returning FALSE" );
+ return false;
+ }
+
+ }
+ catch( MalformedURLException e ) {
+ return false;
+ }
+ }
+
+ public CompilationConfiguration getCompilationConfiguration()
+ {
+ return compilationConfiguration;
+ }
+
+ public TestRunConfiguration getTestRunConfiguration()
+ {
+ return testRunConfiguration;
+ }
+
+ public void setCommand(String commandPath)
+ {
+ testRunConfiguration.setCommand(project.resolveFile(commandPath));
+ }
+
+ public void setDisplay(int display)
+ {
+ testRunConfiguration.setDisplay(display);
+ }
+
+ public void setFailOnTestFailure(boolean failOnTestFailure)
+ {
+ testRunConfiguration.setFailOnTestFailure(failOnTestFailure);
+ }
+
+ public void setFailureProperty(String failureProperty)
+ {
+ testRunConfiguration.setFailureProperty(failureProperty);
+ }
+
+ public void addSource(FileSet fileset)
+ {
+ fileset.setProject(project);
+ compilationConfiguration.addSource(fileset);
+ }
+
+ public void addTestSource(FileSet fileset)
+ {
+ fileset.setProject(project);
+ compilationConfiguration.addTestSource(fileset);
+ }
+
+ public void addLibrary(FileSet fileset)
+ {
+ fileset.setProject(project);
+ compilationConfiguration.addLibrary(fileset);
+ }
+
+ public void setHeadless(boolean headless)
+ {
+ testRunConfiguration.setHeadless(headless);
+ }
+
+ public void setLocalTrusted(boolean isLocalTrusted)
+ {
+ testRunConfiguration.setLocalTrusted(isLocalTrusted);
+ }
+
+ public void setPlayer(String player)
+ {
+ this.player = player;
+ }
+
+ public void setPort(int port)
+ {
+ testRunConfiguration.setPort(port);
+ }
+
+ public void setReportDir(String reportDirPath)
+ {
+ this.reportDir = project.resolveFile(reportDirPath);
+ }
+
+ public void setServerBufferSize(int serverBufferSize)
+ {
+ testRunConfiguration.setServerBufferSize(serverBufferSize);
+ }
+
+ public void setSocketTimeout(int socketTimeout)
+ {
+ testRunConfiguration.setSocketTimeout(socketTimeout);
+ }
+
+ public void setSwf(String swf)
+ {
+ //match the swf URL to see if it's a remote location, if so, set the url instead of swf.
+
+ File localFile = project.resolveFile(swf);
+
+ if( localFile.exists() ) {
+ testRunConfiguration.setSwf(localFile);
+ LoggingUtil.log("Local path to SWF was given and SWF property will be used.");
+ } else if( isValidURL( swf ) ) {
+ testRunConfiguration.setUrl(swf);
+ LoggingUtil.log("Remote path to SWF was given, setting URL property instead of SWF");
+ } else {
+ LoggingUtil.log("SWF and URL not set, file did not resolve to a local path or a remote path, please verify your format and try again.");
+ }
+
+ }
+
+ public void setSwf(File swf)
+ {
+ testRunConfiguration.setSwf(swf);
+ }
+
+ public boolean isVerbose()
+ {
+ return verbose;
+ }
+
+ public void setVerbose(boolean verbose)
+ {
+ this.verbose = verbose;
+ LoggingUtil.VERBOSE = verbose;
+ }
+
+ public void setWorkingDir(String workingDirPath)
+ {
+ this.workingDir = project.resolveFile(workingDirPath);
+ }
+
+ public boolean shouldCompile()
+ {
+ File swf = testRunConfiguration.getSwf();
+ boolean noTestSources = !compilationConfiguration.getTestSources().provided();
+ return !noTestSources && (swf == null || !swf.exists());
+ }
+
+ public void verify() throws BuildException
+ {
+ validateSharedProperties();
+
+ if(shouldCompile())
+ {
+ compilationConfiguration.validate();
+ }
+
+ testRunConfiguration.validate();
+
+ propagateSharedConfiguration();
+ }
+
+ protected void validateSharedProperties() throws BuildException
+ {
+ LoggingUtil.log("Validating task attributes ...");
+
+ if(!VALID_PLAYERS.contains(player))
+ {
+ throw new BuildException("The provided 'player' property value [" + player + "] must be either of the following values: " + VALID_PLAYERS.toString() + ".");
+ }
+
+ File swf = testRunConfiguration.getSwf();
+ boolean noTestSources = !compilationConfiguration.getTestSources().provided();
+ String swfURL = testRunConfiguration.getUrl();
+
+ //Check to make sure we have a valid swf, testsource or remote url before proceeding.
+ //Otherwise, notify the user to fix this before continuing.
+ if ((swf == null || !swf.exists()) && noTestSources && ( swfURL == null || swfURL.equals("") ) )
+ {
+ throw new BuildException("The provided 'swf' property value [" + (swf == null ? "" : swf.getPath()) + "] could not be found or is not a valid remote URL.");
+ }
+
+ //Including a check for the swfURL
+ if( ( swf == null ) && (swfURL != null && swfURL != "") && testRunConfiguration.isLocalTrusted() )
+ {
+ throw new BuildException("The provided 'swf' property points to a remote location. Please set localTrusted = false or change the location of your swf to a local path.");
+ }
+
+ if(swf != null && !noTestSources)
+ {
+ throw new BuildException("Please specify the 'swf' property or use the 'testSource' element(s), but not both.");
+ }
+
+ //if we can't find the ROYALE_HOME and we're using ADL or compilation
+ if((royaleHome == null || !royaleHome.exists()) && (new String("air").equals(testRunConfiguration.getPlayer()) || shouldCompile()))
+ {
+ throw new BuildException("Please specify, or verify the location for, the ROYALE_HOME property. "
+ + "It is required when testing with 'air' as the player or when using the 'testSource' element. "
+ + "It should point to the installation directory for an Apache Royale SDK.");
+ }
+ }
+
+ protected void propagateSharedConfiguration()
+ {
+ LoggingUtil.log("Generating default values ...");
+
+ //setup player
+ compilationConfiguration.setPlayer(player);
+ testRunConfiguration.setPlayer(player);
+
+ //set ROYALE_HOME property to respective configs
+ compilationConfiguration.setRoyaleHome(royaleHome);
+ testRunConfiguration.setRoyaleHome(royaleHome);
+
+ //create working directory if needed
+ if (workingDir == null || !workingDir.exists())
+ {
+ workingDir = project.resolveFile(DEFAULT_WORKING_PATH);
+ LoggingUtil.log("Using default working dir [" + workingDir.getAbsolutePath() + "]");
+ }
+
+ //create directory just to be sure it exists, already existing dirs will not be overwritten
+ workingDir.mkdirs();
+
+ compilationConfiguration.setWorkingDir(workingDir);
+
+ //create report directory if needed
+ if (reportDir == null || !reportDir.exists())
+ {
+ reportDir = project.resolveFile(DEFAULT_REPORT_PATH);
+ LoggingUtil.log("Using default reporting dir [" + reportDir.getAbsolutePath() + "]");
+ }
+
+ //create directory just to be sure it exists, already existing dirs will not be overwritten
+ reportDir.mkdir();
+
+ testRunConfiguration.setReportDir(reportDir);
+ }
+
+ public void setDebug(boolean value)
+ {
+ compilationConfiguration.setDebug(value);
+ }
+
+ public void setLoadConfig(LoadConfig loadconfig)
+ {
+ compilationConfiguration.setLoadConfig(loadconfig);
+ }
+
+}
\ No newline at end of file
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/TestRunConfiguration.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/TestRunConfiguration.java
new file mode 100644
index 0000000..ba88630
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/configuration/TestRunConfiguration.java
@@ -0,0 +1,274 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.configuration;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.royale.test.ant.LoggingUtil;
+import org.apache.royale.test.ant.launcher.OperatingSystem;
+
+public class TestRunConfiguration implements StepConfiguration
+{
+ private final int FLOOR_FOR_PORT = 1;
+ private final int SHORTEST_SOCKET_TIMEOUT = 5000; //ms
+
+ private String player;
+ private File command = null;
+ private int display = 99;
+ private boolean failOnTestFailure = false;
+ private String failureProperty = "royaleunit.failed";
+ private File royaleHome = null;
+ private boolean headless = false;
+ private boolean isLocalTrusted = true;
+ private int port = 1024;
+ private File reportDir = null;
+ private int serverBufferSize = 262144; //bytes
+ private int socketTimeout = 60000; //milliseconds
+ private File swf = null;
+ private String url = null;
+ private File precompiledAppDescriptor = null;
+ private OperatingSystem os = OperatingSystem.identify();
+
+ public File getCommand()
+ {
+ return command;
+ }
+
+ public void setCommand(File command)
+ {
+ this.command = command;
+ }
+
+ public boolean isCustomCommand()
+ {
+ return command != null;
+ }
+
+ public int getDisplay()
+ {
+ return display;
+ }
+
+ public void setDisplay(int display)
+ {
+ this.display = display;
+ }
+
+ public boolean isFailOnTestFailure()
+ {
+ return failOnTestFailure;
+ }
+
+ public void setFailOnTestFailure(boolean failOnTestFailure)
+ {
+ this.failOnTestFailure = failOnTestFailure;
+ }
+
+ public String getFailureProperty()
+ {
+ return failureProperty;
+ }
+
+ public void setFailureProperty(String failureProperty)
+ {
+ this.failureProperty = failureProperty;
+ }
+
+ public File getRoyaleHome()
+ {
+ return royaleHome;
+ }
+
+ public void setRoyaleHome(File royaleHome)
+ {
+ this.royaleHome = royaleHome;
+ }
+
+ public boolean isHeadless()
+ {
+ return headless;
+ }
+
+ public void setHeadless(boolean headless)
+ {
+ this.headless = headless;
+ }
+
+ public boolean isLocalTrusted()
+ {
+ return isLocalTrusted;
+ }
+
+ public boolean usePolicyFile()
+ {
+ return !isLocalTrusted && player.equals("flash");
+ }
+
+ public void setLocalTrusted(boolean isLocalTrusted)
+ {
+ this.isLocalTrusted = isLocalTrusted;
+ }
+
+ public String getPlayer()
+ {
+ return player;
+ }
+
+ public void setPlayer(String player)
+ {
+ this.player = player;
+ }
+
+ public int getPort()
+ {
+ return port;
+ }
+
+ public void setPort(int port)
+ {
+ this.port = port;
+ }
+
+ public File getReportDir()
+ {
+ return reportDir;
+ }
+
+ public void setReportDir(File reportDir)
+ {
+ this.reportDir = reportDir;
+ }
+
+ public int getServerBufferSize()
+ {
+ return serverBufferSize;
+ }
+
+ public void setServerBufferSize(int serverBufferSize)
+ {
+ this.serverBufferSize = serverBufferSize;
+ }
+
+ public int getSocketTimeout()
+ {
+ return socketTimeout;
+ }
+
+ public void setSocketTimeout(int socketTimeout)
+ {
+ this.socketTimeout = socketTimeout;
+ }
+
+ public File getSwf()
+ {
+ return swf;
+ }
+
+ public void setSwf(File swf)
+ {
+ this.swf = swf;
+ }
+
+ public String getUrl()
+ {
+ return url;
+ }
+
+ public void setUrl(String url)
+ {
+ this.url = url;
+ }
+
+ public File getPrecompiledAppDescriptor()
+ {
+ return precompiledAppDescriptor;
+ }
+
+ public void setPrecompiledAppDescriptor(File precompiledAppDescriptor)
+ {
+ this.precompiledAppDescriptor = precompiledAppDescriptor;
+ }
+
+ public OperatingSystem getOs()
+ {
+ return os;
+ }
+
+ public void validate() throws BuildException
+ {
+ if(port < FLOOR_FOR_PORT)
+ {
+ throw new BuildException("The provided 'port' property value [" + port + "] must be great than " + FLOOR_FOR_PORT + ".");
+ }
+
+ if(socketTimeout < SHORTEST_SOCKET_TIMEOUT)
+ {
+ throw new BuildException("The provided 'timeout' property value [" + socketTimeout + "] must be great than " + SHORTEST_SOCKET_TIMEOUT + ".");
+ }
+
+ if(reportDir != null && !reportDir.exists())
+ {
+ LoggingUtil.log("Provided report directory path [" + reportDir.getPath() + "] does not exist.");
+ }
+
+ if(command != null && !command.exists())
+ {
+ throw new BuildException("The provided command path [" + command + "] does not exist.");
+ }
+
+ if(headless)
+ {
+ if(OperatingSystem.identify() != OperatingSystem.LINUX)
+ {
+ throw new BuildException("Headless mode can only be used on Linux with vncserver installed.");
+ }
+
+ if(display < 1)
+ {
+ throw new BuildException("The provided 'display' number must be set higher than 0. 99 or higher is recommended.");
+ }
+ }
+ }
+
+ public void log()
+ {
+ LoggingUtil.log("Using the following settings for the test run:");
+
+ //ROYALE_HOME not required to run if not using ADL
+ if(royaleHome != null)
+ {
+ LoggingUtil.log("\tROYALE_HOME: [" + royaleHome.getAbsolutePath() + "]");
+ }
+
+ LoggingUtil.log("\thaltonfailure: [" + failOnTestFailure + "]");
+ LoggingUtil.log("\theadless: [" + headless + "]");
+ LoggingUtil.log("\tdisplay: [" + display + "]");
+ LoggingUtil.log("\tlocalTrusted: [" + isLocalTrusted + "]");
+ LoggingUtil.log("\tplayer: [" + player + "]");
+
+ if(isCustomCommand())
+ {
+ LoggingUtil.log("\tcommand: [" + command + "]");
+ }
+
+ LoggingUtil.log("\tport: [" + port + "]");
+ LoggingUtil.log("\tswf: [" + swf + "]");
+ LoggingUtil.log("\ttimeout: [" + socketTimeout + "ms]");
+ LoggingUtil.log("\ttoDir: [" + reportDir.getAbsolutePath() + "]");
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/CompilationFileSetCollection.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/CompilationFileSetCollection.java
new file mode 100644
index 0000000..bcfd5e7
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/CompilationFileSetCollection.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.types;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+
+public class CompilationFileSetCollection
+{
+ protected List<FileSet> filesets;
+
+ public CompilationFileSetCollection()
+ {
+ filesets = new ArrayList<FileSet>();
+ }
+
+ public void add(FileSet fileset)
+ {
+ filesets.add(fileset);
+ }
+
+ public boolean provided()
+ {
+ return filesets.size() != 0;
+ }
+
+ public boolean isEmpty()
+ {
+ if(filesets.isEmpty())
+ {
+ return true;
+ }
+
+ int includeCount = 0;
+
+ for(FileSet fileset : filesets)
+ {
+ if(fileset.getDir().exists())
+ {
+ DirectoryScanner scanner = fileset.getDirectoryScanner();
+ includeCount += scanner.getIncludedFilesCount();
+ }
+ }
+
+ return includeCount == 0;
+ }
+
+ public boolean exists()
+ {
+ for(FileSet fileset : filesets)
+ {
+ if(!fileset.getDir().exists())
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/LibraryPaths.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/LibraryPaths.java
new file mode 100644
index 0000000..ae347ea
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/LibraryPaths.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.types;
+
+import java.io.File;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+
+public class LibraryPaths extends CompilationFileSetCollection
+{
+ public LibraryPaths()
+ {
+ super();
+ }
+
+ @Override
+ public void add(FileSet fileset)
+ {
+ super.add(fileset);
+ }
+
+ public String getPathElements(String delimiter)
+ {
+ StringBuilder elements = new StringBuilder();
+
+ for(FileSet fileset : filesets)
+ {
+ DirectoryScanner ds = fileset.getDirectoryScanner();
+ String[] files = ds.getIncludedFiles();
+ for(int i=0; i<files.length; i++)
+ {
+ if(files[i].endsWith(".swc"))
+ {
+ elements.append("\"" + fileset.getDir().getAbsolutePath() + File.separator + files[i] + "\"");
+ elements.append(delimiter);
+ }
+ }
+ }
+
+ return elements.length() <= delimiter.length() ? "" : elements.substring(0, elements.length() - delimiter.length());
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/LoadConfig.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/LoadConfig.java
new file mode 100644
index 0000000..c460523
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/LoadConfig.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.types;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DynamicAttribute;
+
+public class LoadConfig implements DynamicAttribute
+{
+ public void setDynamicAttribute(String arg0, String arg1)
+ throws BuildException {
+ if("filename".equals(arg0))
+ {
+ filename = arg1;
+ }
+ else
+ {
+ throw new BuildException("filename is only allowed attribute for <load-config>");
+ }
+ }
+
+ public String getFilename()
+ {
+ return filename;
+ }
+
+ public String getCommandLineArgument()
+ {
+ String argument = "";
+ if(filename == null || "".equals(filename))
+ {
+ argument = "";
+ }
+ else
+ {
+
+ argument = "-load-config+=\"" + filename + "\"";
+
+ }
+
+ return argument;
+ }
+
+ private String filename;
+
+}
diff --git a/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/SourcePaths.java b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/SourcePaths.java
new file mode 100644
index 0000000..a0d0d40
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/java/org/apache/royale/test/ant/tasks/types/SourcePaths.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.royale.test.ant.tasks.types;
+
+import java.io.File;
+
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.types.FileSet;
+
+public class SourcePaths extends CompilationFileSetCollection
+{
+ public SourcePaths()
+ {
+ super();
+ }
+
+ @Override
+ public void add(FileSet fileset)
+ {
+ super.add(fileset);
+ }
+
+ public String getPathElements(String delimiter)
+ {
+ StringBuilder elements = new StringBuilder();
+
+ for(FileSet fileset : filesets)
+ {
+ elements.append("\"" + fileset.getDir().getAbsolutePath() + "\"");
+ elements.append(delimiter);
+ }
+
+ return elements.length() <= delimiter.length() ? "" : elements.substring(0, elements.length() - delimiter.length());
+ }
+
+ public String getImports()
+ {
+ StringBuilder elements = new StringBuilder();
+
+ for(FileSet fileset : filesets)
+ {
+ DirectoryScanner ds = fileset.getDirectoryScanner();
+ for(String file : ds.getIncludedFiles())
+ {
+ if(file.endsWith(".as") || file.endsWith(".mxml"))
+ {
+ String pathWithOutSuffix = file.substring(0, file.lastIndexOf('.'));
+ String canonicalClassName = pathWithOutSuffix.replace(File.separatorChar, '.');
+ elements.append("import ");
+ elements.append(canonicalClassName);
+ elements.append(";\n");
+ }
+ }
+ }
+
+ return elements.toString();
+ }
+
+ public String getClasses()
+ {
+ StringBuilder elements = new StringBuilder();
+
+ for(FileSet fileset : filesets)
+ {
+ DirectoryScanner ds = fileset.getDirectoryScanner();
+ for(String file : ds.getIncludedFiles())
+ {
+ String pathWithOutSuffix = file.substring(0, file.lastIndexOf('.'));
+ String canonicalClassName = pathWithOutSuffix.replace(File.separatorChar, '.');
+ String className = canonicalClassName.substring(canonicalClassName.lastIndexOf('.') + 1, canonicalClassName.length());
+ elements.append(className);
+ elements.append(',');
+ }
+ }
+
+ return elements.length() == 0 ? "" : elements.substring(0, elements.length() - 1);
+ }
+
+ public String getCanonicalClasses(String delimiter)
+ {
+ StringBuilder elements = new StringBuilder();
+
+ for(FileSet fileset : filesets)
+ {
+ DirectoryScanner ds = fileset.getDirectoryScanner();
+ for(String file : ds.getIncludedFiles())
+ {
+ String pathWithOutSuffix = file.substring(0, file.lastIndexOf('.'));
+ String canonicalClassName = pathWithOutSuffix.replace(File.separatorChar, '.');
+ elements.append(canonicalClassName);
+ elements.append(delimiter);
+ }
+ }
+
+ return elements.length() <= delimiter.length() ? "" : elements.substring(0, elements.length() - delimiter.length());
+ }
+}
diff --git a/royaleunit-ant-tasks/src/main/resources/TestRunner.template b/royaleunit-ant-tasks/src/main/resources/TestRunner.template
new file mode 100644
index 0000000..b4a4359
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/resources/TestRunner.template
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<@APPLICATION_PREFIX@:@APPLICATION_CLASS@
+@NAMESPACES@
+creationComplete="runTests();">
+
+ <@MXML_PREFIX@:Script>
+ <![CDATA[
+ import org.apache.royale.test.listeners.@CI_LISTENER_CLASS@;
+ import org.apache.royale.test.RoyaleUnitCore;
+
+@IMPORT_REFS@
+
+ public function runTests() : void {
+ var core : RoyaleUnitCore = new RoyaleUnitCore();
+ core.addListener(new @CI_LISTENER_CLASS@());
+ core.runClasses(
+[@CLASS_REFS@]
+ );
+ }
+ ]]>
+ </@MXML_PREFIX@:Script>
+</@APPLICATION_PREFIX@:@APPLICATION_CLASS@>
diff --git a/royaleunit-ant-tasks/src/main/resources/downloads.xml b/royaleunit-ant-tasks/src/main/resources/downloads.xml
new file mode 100644
index 0000000..73e8451
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/resources/downloads.xml
@@ -0,0 +1,396 @@
+<?xml version="1.0"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project name="downloads" default="main" basedir=".">
+ <echo>basedir is ${basedir}</echo>
+ <echo>ROYALE_COMPILER_HOME is ${ROYALE_COMPILER_HOME}</echo>
+
+ <!--
+ Notes:
+ For Apache, the JARS must be removed from the repository.
+
+ Licenses:
+ dom4j (1.6.1) - BSD
+ Java-WebSocket (1.4.0) - MIT
+ slf4j-api (1.7.25) - MIT
+ -->
+
+ <!-- this script supports the usingDownloadCache property and
+ downloadCacheFolder property to cache downloads in the
+ folder specified by downloadCacheFolder. This can make
+ a huge difference in future runs although there is some
+ risk around caching bad downloads and/or needing to
+ clean up the cache -->
+
+ <property name="ROYALE_COMPILER_HOME" location="${basedir}/../../../../compiler-jx"/>
+ <echo>ROYALE_COMPILER_HOME is ${ROYALE_COMPILER_HOME}</echo>
+
+ <property name="lib.dir" value="${ROYALE_COMPILER_HOME}/lib"/>
+ <property name="download.dir" value="${ROYALE_COMPILER_HOME}/in"/>
+
+ <property file="${ROYALE_COMPILER_HOME}/local.properties"/>
+
+ <property name="maven.search.url" value="https://repo1.maven.org/maven2"/>
+
+ <property file="${ROYALE_COMPILER_HOME}/env.properties"/>
+ <property environment="env"/>
+ <property file="${ROYALE_COMPILER_HOME}/local.properties"/>
+ <property file="${ROYALE_COMPILER_HOME}/build.properties"/>
+
+
+ <!--
+ Because the downloads requires a network connection and the JARs don't change very often,
+ they are each downloaded only if they don't already exist.
+ -->
+ <target name="main" depends="prepare, all" description="Downloads all the required thirdparty JARs"/>
+
+ <target name="prepare">
+ <echo message="Making lib directory ${lib.dir}"/>
+ <mkdir dir="${lib.dir}"/>
+ </target>
+
+ <!--
+ Downloads
+ -->
+
+ <target name="all" description="Downloads and copies all dependencies to the lib directory.">
+
+ <!-- dom4j -->
+ <property name="dom4j.name" value="dom4j"/>
+ <property name="dom4j.version" value="1.6.1"/>
+ <antcall target="download-dependency">
+ <param name="name" value="${dom4j.name}"/>
+ <param name="src.server" value="${maven.search.url}"/>
+ <param name="src.folder" value="dom4j/dom4j/${dom4j.version}"/>
+ <param name="src.filename" value="dom4j-${dom4j.version}.jar"/>
+ <param name="src.checksum" value="4d8f51d3fe3900efc6e395be48030d6d"/>
+ <param name="dest.folder" value=""/>
+ <param name="dest.filename" value="${dom4j.name}.jar"/>
+ <param name="license.use.url" value="https://raw.githubusercontent.com/dom4j/dom4j/master/LICENSE"/>
+ <param name="license.cacheName" value="dom4j-LICENSE.txt"/>
+ </antcall>
+
+ <!-- Java-WebSocket -->
+ <property name="javawebsocket.name" value="java-websocket"/>
+ <property name="javawebsocket.version" value="1.4.0"/>
+ <antcall target="download-dependency">
+ <param name="name" value="${javawebsocket.name}"/>
+ <param name="src.server" value="${maven.search.url}"/>
+ <param name="src.folder" value="org/java-websocket/Java-WebSocket/${javawebsocket.version}"/>
+ <param name="src.filename" value="Java-WebSocket-${javawebsocket.version}.jar"/>
+ <param name="src.checksum" value="59c1134b8c50ace9e074e9f1d5da4aaa"/>
+ <param name="dest.folder" value=""/>
+ <param name="dest.filename" value="${javawebsocket.name}.jar"/>
+ <param name="license.use.url" value="https://raw.githubusercontent.com/TooTallNate/Java-WebSocket/master/LICENSE"/>
+ <param name="license.cacheName" value="${javawebsocket.name}-LICENSE.txt"/>
+ </antcall>
+
+ <!-- slf4j-api -->
+ <property name="slf4j.name" value="slf4j-api"/>
+ <property name="slf4j.version" value="1.7.25"/>
+ <antcall target="download-dependency">
+ <param name="name" value="${slf4j.name}"/>
+ <param name="src.server" value="${maven.search.url}"/>
+ <param name="src.folder" value="org/slf4j/slf4j-api/${slf4j.version}"/>
+ <param name="src.filename" value="slf4j-api-${slf4j.version}.jar"/>
+ <param name="src.checksum" value="caafe376afb7086dcbee79f780394ca3"/>
+ <param name="dest.folder" value=""/>
+ <param name="dest.filename" value="${slf4j.name}.jar"/>
+ <param name="license.use.url" value="https://raw.githubusercontent.com/qos-ch/slf4j/master/LICENSE.txt"/>
+ <param name="license.cacheName" value="${slf4j.name}-LICENSE.txt"/>
+ </antcall>
+ </target>
+
+
+
+ <!--
+ Utilities
+ -->
+
+ <target name="check-dependency" description="Checks if project jar is in lib directory.">
+ <echo>checking for ${lib.dir}/${dest.folder}/${name}.jar</echo>
+ <available file="${lib.dir}/${dest.folder}/${name}.jar" property="project.jar.exists"/>
+ </target>
+
+ <target name="echo-project-jar">
+ <echo file="${basedir}/project.properties">project.echo=${INFO_DOWNLOADING_FILE_FROM}</echo>
+ <replace file="${basedir}/project.properties" token="{0}" value="${srcPath}"/>
+ <replace file="${basedir}/project.properties" token="{1}" value="${srcDomain}"/>
+ <property file="${basedir}/project.properties"/>
+ <delete file="${basedir}/project.properties"/>
+ <echo>${project.echo}</echo>
+ </target>
+
+ <target name="download-dependency" depends="check-dependency" unless="project.jar.exists" description="Downloads a jar + license to the lib directory.">
+ <antcall target="echo-project-jar">
+ <param name="srcDomain" value="${src.server}"/>
+ <param name="srcPath" value="${src.folder}/${src.filename}"/>
+ </antcall>
+ <mkdir dir="${lib.dir}/${dest.folder}"/>
+
+ <antcall target="download-apache-license" />
+ <antcall target="download-other-license" />
+
+ <!-- ant_on_air in Installer 3.1 doesn't support 'or' yet -->
+ <condition property="project.download.jar">
+ <and>
+ <not>
+ <contains string="${src.filename}" substring=".tar" />
+ </not>
+ <not>
+ <contains string="${src.filename}" substring=".zip" />
+ </not>
+ </and>
+ </condition>
+
+ <antcall target="download-dependency-jar">
+ <param name="server" value="${src.server}"/>
+ <param name="folder" value="${src.folder}"/>
+ <param name="srcFileName" value="${src.filename}"/>
+ <param name="destDir" value="${lib.dir}/${dest.folder}"/>
+ <param name="destFile" value="${dest.filename}"/>
+ <param name="checksum" value="${src.checksum}"/>
+ </antcall>
+
+ <antcall target="download-dependency-zip">
+ <param name="server" value="${src.server}"/>
+ <param name="folder" value="${src.folder}"/>
+ <param name="srcFileName" value="${src.filename}"/>
+ <param name="srcJarPath" value="${src.jarPath}"/>
+ <param name="destDir" value="${lib.dir}/${dest.folder}"/>
+ <param name="destFile" value="${dest.filename}"/>
+ <param name="checksum" value="${src.checksum}"/>
+ </antcall>
+ </target>
+
+ <target name="download-apache-license" if="license.use.apache" description="Downloads the Apache license to the lib directory.">
+ <get src="http://www.apache.org/licenses/LICENSE-2.0" dest="${lib.dir}/${dest.folder}/${name}-LICENSE.html" ignoreerrors="true"/>
+ <antcall target="get-from-cache-if-needed" >
+ <param name="srcFile" value="LICENSE-2.0.html" />
+ <param name="destFile" value="${name}-LICENSE.html" />
+ <param name="destDir" value="${lib.dir}/${dest.folder}" />
+ </antcall>
+ <antcall target="fail-if-not-found" >
+ <param name="destFile" value="${name}-LICENSE.html" />
+ <param name="destDir" value="${lib.dir}/${dest.folder}" />
+ </antcall>
+ </target>
+
+ <target name="download-other-license" if="license.use.url" description="Downloads a non-Apache license to the lib directory.">
+ <get src="${license.use.url}" dest="${lib.dir}/${dest.folder}/${name}-LICENSE.txt" ignoreerrors="true"/>
+ <antcall target="get-from-cache-if-needed" >
+ <param name="srcFile" value="${license.cacheName}" />
+ <param name="destFile" value="${name}-LICENSE.txt" />
+ <param name="destDir" value="${lib.dir}/${dest.folder}" />
+ </antcall>
+ <antcall target="fail-if-not-found" >
+ <param name="destFile" value="${name}-LICENSE.txt" />
+ <param name="destDir" value="${lib.dir}/${dest.folder}" />
+ </antcall>
+ </target>
+
+ <target name="download-dependency-jar" if="project.download.jar" description="Downloads a jar to the lib directory.">
+ <antcall target="download-jar">
+ <param name="srcDomain" value="${server}"/>
+ <param name="srcFolder" value="${folder}"/>
+ <param name="cacheFolder" value="${folder}"/>
+ <param name="srcFile" value="${srcFileName}"/>
+ <param name="md5" value="${checksum}"/>
+ </antcall>
+ </target>
+
+ <target name="download-dependency-zip" unless="project.download.jar" description="Downloads a zip to the lib directory.">
+ <antcall target="download-zip">
+ <param name="srcDomain" value="${server}"/>
+ <param name="srcFolder" value="${folder}"/>
+ <param name="srcFile" value="${srcFileName}"/>
+ <param name="srcJarPath" value="${srcJarPath}"/>
+ <param name="md5" value="${checksum}"/>
+ </antcall>
+ </target>
+
+ <!--
+ Download a zip or gz file, extracts the jar file, and optionally copies the jar
+ file to a different location and optinally verifies the checksum and optionally
+ caches the file, and optionally pulls the file from the cache instead of downloading.
+ If the checksum fails, this script fails.
+
+ Params are:
+ srcDomain - the domain
+ srcFolder - path to file
+ srcFile - a .gz file for untar with gzip, else unzip
+ [md5]
+ [srcJarPath] - both src and dest required for the copy
+ [destJarFile]
+
+ Note: This is purposely coded without <if><else><then> so that a dependency on
+ ant-contrib.jar isn't required.
+ -->
+ <target name="download-zip" depends="check-cache" description="Downloads tar/zip, and optionally verifies checksum and copies extracted jar.">
+ <mkdir dir="${download.dir}"/>
+ <antcall target="get-if-not-cached">
+ <param name="destDir" value="${download.dir}"/>
+ <param name="destFile" value="${srcFile}"/>
+ <param name="message" value="Checksum mismatch for ${download.dir}/${srcFile}"/>
+ </antcall>
+ <antcall target="copy-if-cached">
+ <param name="destDir" value="${download.dir}"/>
+ <param name="destFile" value="${srcFile}"/>
+ </antcall>
+ <condition property="zip.compressed">
+ <matches string="${srcFile}" pattern="^*.zip$"/>
+ </condition>
+ <antcall target="untar-file"/>
+ <antcall target="unzip-file"/>
+ <condition property="destination.known">
+ <and>
+ <isset property="srcJarPath"/>
+ <isset property="destDir"/>
+ <isset property="destFile"/>
+ </and>
+ </condition>
+ <antcall target="copy-downloaded-jar"/>
+ </target>
+
+ <target name="download-bz2" depends="check-cache" description="Downloads bz2, and optionally verifies checksum and copies extracted jar.">
+ <mkdir dir="${download.dir}"/>
+ <antcall target="get-if-not-cached">
+ <param name="dest" value="${download.dir}/${srcFile}"/>
+ <param name="message" value="Checksum mismatch for ${download.dir}/${srcFile}"/>
+ </antcall>
+ <antcall target="copy-if-cached">
+ <param name="dest" value="${download.dir}/${srcFile}"/>
+ </antcall>
+ <untar src="${download.dir}/${srcFile}" dest="${download.dir}/temp" compression="bzip2"/>
+ <condition property="destination.known">
+ <and>
+ <isset property="srcJarPath"/>
+ <isset property="destJarFile"/>
+ </and>
+ </condition>
+ <antcall target="copy-downloaded-jar"/>
+ </target>
+
+ <!--
+ Download a jar file and optionally verify the checksum.
+ If the checksum fails, this script fails.
+
+ Params are:
+ srcDomain
+ srcFolder
+ srcFile
+ destJarFile
+ [md5]
+ -->
+ <target name="download-jar" depends="check-cache" description="Downloads jar, and optionally verifies checksum.">
+ <antcall target="get-if-not-cached">
+ <param name="message" value="Checksum mismatch for ${destJarFile}"/>
+ </antcall>
+ <antcall target="copy-if-cached" />
+ </target>
+
+ <target name="untar-file" unless="zip.compressed" description="Untars zipFile">
+ <untar src="${download.dir}/${srcFile}" dest="${download.dir}/temp" compression="gzip"/>
+ </target>
+
+ <target name="unzip-file" if="zip.compressed" description="Unzips zipFile">
+ <unzip src="${download.dir}/${srcFile}" dest="${download.dir}/temp"/>
+ </target>
+
+ <target name="get-if-not-cached" unless="found-in-cache">
+ <get src="${srcDomain}/${srcFolder}/${srcFile}" dest="${destDir}/${destFile}" ignoreerrors="true"/>
+ <!-- this is a different cache for the CI servers. It tries the network first, then the cache if failure -->
+ <antcall target="get-from-cache-if-needed" />
+ <antcall target="fail-if-not-found" />
+ <antcall target="check-sum">
+ <param name="message" value="Checksum mismatch for ${destDir}/${destFile}"/>
+ </antcall>
+ <antcall target="put-in-cache"/>
+ </target>
+
+ <target name="copy-if-cached" if="found-in-cache">
+ <!-- this string comes from the Royale en_US.properties because for now, this
+ target won't get called unless this script is called from the Royale install -->
+ <echo>${INFO_USING_CACHED_FILE} ${downloadCacheFolder}/${srcFolder}/${srcFile}</echo>
+ <copy file="${downloadCacheFolder}/${srcFolder}/${srcFile}" tofile="${destDir}/${destFile}" overwrite="true"/>
+ </target>
+
+ <target name="check-cache" if="usingDownloadCache">
+ <echo>${downloadCacheFolder} ${srcFolder} ${srcFile}</echo>
+ <available file="${downloadCacheFolder}/${srcFolder}/${srcFile}" property="found-in-cache"/>
+ </target>
+
+ <target name="put-in-cache" if="usingDownloadCache">
+ <copy tofile="${downloadCacheFolder}/${srcFolder}/${srcFile}" file="${destDir}/${destFile}"/>
+ </target>
+
+ <target name="check-sum" if="md5" description="Verifies MD5 checksum, and fails if checksum doesn't match">
+ <checksum file="${destDir}/${destFile}" algorithm="MD5" verifyproperty="we.failed" property="${md5}"/>
+ <fail message="${message}">
+ <condition>
+ <equals arg1="${we.failed}" arg2="false"/>
+ </condition>
+ </fail>
+ </target>
+
+ <target name="copy-downloaded-jar" if="destination.known">
+ <mkdir dir="${lib.dir}"/>
+ <copy file="${download.dir}/temp/${srcJarPath}" toFile="${destDir}/${destFile}" verbose="true"/>
+ </target>
+
+ <target name="fail-with-message" if="we.failed" description="Conditionally fails with the specified message">
+ <fail message="${message}"/>
+ </target>
+
+ <target name="fail-if-not-found">
+ <fail message="${destDir}/${destFile} could not be downloaded or found in cache">
+ <condition>
+ <not>
+ <available file="${destDir}/${destFile}" />
+ </not>
+ </condition>
+ </fail>
+ </target>
+
+ <target name="double-check-file" >
+ <echo>${env.ROYALE_DOWNLOAD_CACHE}</echo>
+ <condition property="still-no-file" value="true">
+ <and>
+ <not>
+ <available file="${destDir}/${destFile}" />
+ </not>
+ <isset property="env.ROYALE_DOWNLOAD_CACHE" />
+ </and>
+ </condition>
+ <echo>Need file: ${still_no_file}</echo>
+ </target>
+ <target name="get-from-cache-if-needed" depends="double-check-file" if="still-no-file">
+ <copy file="${env.ROYALE_DOWNLOAD_CACHE}/${srcFile}" tofile="${destDir}/${destFile}" />
+ </target>
+
+
+ <!--
+ Cleanup
+ -->
+ <target name="clean" description="Removes thirdparty downloads.">
+ <delete failonerror="false" includeEmptyDirs="true">
+ <fileset dir="${download.dir}"/>
+ </delete>
+ </target>
+</project>
diff --git a/royaleunit-ant-tasks/src/main/resources/royaleUnitDescriptor.template b/royaleunit-ant-tasks/src/main/resources/royaleUnitDescriptor.template
new file mode 100644
index 0000000..e2e0207
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/resources/royaleUnitDescriptor.template
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<application xmlns="http://ns.adobe.com/air/application/@ADT_VERSION@">
+ <id>RoyaleUnitAdlWrapper</id>
+ <filename>RoyaleUnitAdlWrapper</filename>
+ <name>RoyaleUnit Adl Wrapper</name>
+ <@VERSION_PROP@>1.0.0</@VERSION_PROP@>
+ <description>Wrapper application for use with the RoyaleUnit Ant task.</description>
+ <initialWindow>
+ <title>RoyaleUnit Adl Wrapper</title>
+ <content>@ADL_SWF@</content>
+ <visible>true</visible>
+ <minimizable>true</minimizable>
+ <maximizable>false</maximizable>
+ <resizable>false</resizable>
+ <width>320</width>
+ <height>240</height>
+ </initialWindow>
+</application>
diff --git a/royaleunit-ant-tasks/src/main/resources/royaleUnitTasks.tasks b/royaleunit-ant-tasks/src/main/resources/royaleUnitTasks.tasks
new file mode 100644
index 0000000..4969030
--- /dev/null
+++ b/royaleunit-ant-tasks/src/main/resources/royaleUnitTasks.tasks
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+royaleunit=org.apache.royale.test.ant.tasks.RoyaleUnitTask
diff --git a/settings-template.xml b/settings-template.xml
index 07b2c2d..bc78230 100644
--- a/settings-template.xml
+++ b/settings-template.xml
@@ -42,7 +42,7 @@
<repositories>
<repository>
<id>apache-snapshots</id>
- <url>http://repository.apache.org/snapshots/</url>
+ <url>https://repository.apache.org/snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
@@ -54,7 +54,7 @@
<pluginRepositories>
<pluginRepository>
<id>apache-snapshots</id>
- <url>http://repository.apache.org/snapshots/</url>
+ <url>https://repository.apache.org/snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
diff --git a/swfutils/pom.xml b/swfutils/pom.xml
index bebc918..4d0d890 100644
--- a/swfutils/pom.xml
+++ b/swfutils/pom.xml
@@ -1,35 +1,45 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>org.apache.royale.compiler</groupId>
- <artifactId>royale-compiler-parent</artifactId>
- <version>0.9.4</version>
- </parent>
-
- <artifactId>swfutils</artifactId>
- <version>0.9.4</version>
-
- <name>Apache Royale: Compiler: SWFUtils</name>
- <description>The Apache Royale Compiler SWF Utility classes</description>
-
-</project>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.apache.royale.compiler</groupId>
+ <artifactId>royale-compiler-parent</artifactId>
+ <version>0.9.6</version>
+ </parent>
+
+ <artifactId>swfutils</artifactId>
+ <version>0.9.6</version>
+
+ <name>Apache Royale: Compiler: SWFUtils</name>
+ <description>The Apache Royale Compiler SWF Utility classes</description>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>io.github.zlika</groupId>
+ <artifactId>reproducible-build-maven-plugin</artifactId>
+ <version>0.9</version>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>