Merge branch 'develop' into reproducible
diff --git a/README b/README
index 4e5d8da..b40d44c 100644
--- a/README
+++ b/README
@@ -52,7 +52,7 @@
SOFTWARE
==================================================================================
- Java SDK 1.7 or greater (*1)
+ Java SDK 8 or greater (*1)
Maven 3.3.9 or greater (*1)
@@ -255,7 +255,7 @@
into an Apache Royale SDK and the lib folder in the repository working copy.
antlr - https://repo1.maven.org/maven2/org/antlr/antlr-complete/3.5.2/antlr-3.5.2-complete.jar
- args4j = http://search.maven.org/remotecontent?filepath=args4j/args4j/2.0.28/args4j-2.0.28.jar
+ args4j = http://search.maven.org/remotecontent?filepath=args4j/args4j/2.0.28/args4j-2.0.28.jar
commons-cli - https://repo1.maven.org/maven2/commons-cli/commons-cli/1.2/commons-cli-1.2-bin.tar.gz
commons-io - https://repo1.maven.org/maven2/commons-io/commons-io/2.4/commons-io-2.4.tar.gz
commons-lang - https://repo1.maven.org/maven2/commons-lang/commons-lang/2.6/commons-lang-2.6.tar.gz
@@ -265,7 +265,7 @@
jburg - https://repo1.maven.org/maven2/net/sourceforge/jburg/jburg/1.10.2/jburg-1.10.2.jar
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 20181210.zip
+ Google Closure Compiler - http://github.com/google/closure-compiler/archive/v20181210.zip
The Google Closure Compiler includes files originally from Rhino under MPL 1.1. For
details see:
diff --git a/compiler-build-tools/build.xml b/compiler-build-tools/build.xml
index b548f01..4ea1a61 100644
--- a/compiler-build-tools/build.xml
+++ b/compiler-build-tools/build.xml
@@ -81,6 +81,22 @@
</javac>
</target>
+ <!-- The OrderSwitches tool is used to order a switch statement from
+ JFlex for reproducible binaries -->
+ <target name="order.switches"
+ description="Compiles the OrderSwitches build tool" >
+ <mkdir dir="${compiler-build-tools}/target/classes"/>
+ <javac debug="${javac.debug}" deprecation="${javac.deprecation}" destdir="${compiler-build-tools}/target/classes" includeAntRuntime="true"
+ source="${javac.src}" target="${javac.src}">
+ <compilerarg value="-Xlint:all,-path,-fallthrough"/>
+ <src path="${compiler-build-tools}/src/main/java"/>
+ <include name="org/apache/royale/compiler/tools/annotate/OrderSwitches.java"/>
+ <classpath>
+ <pathelement location="${compiler-build-tools}/target/classes"/>
+ </classpath>
+ </javac>
+ </target>
+
<!-- The UnknownTreePatternInputOutput tool is used to compile an XML file containing unknown AST patterns to a Java class -->
<target name="unknown.tree.pattern.input.output"
description="Compiles the UnknownTreePatternInputOutput tool">
@@ -108,7 +124,7 @@
</javac>
</target>
- <target name="main" depends="annotate.class, unknown.tree.pattern.input.output" />
+ <target name="main" depends="annotate.class,order.switches, unknown.tree.pattern.input.output" />
<!--
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/OrderSwitches.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/OrderSwitches.java
new file mode 100644
index 0000000..f99c287
--- /dev/null
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/OrderSwitches.java
@@ -0,0 +1,260 @@
+/*
+ * 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.tools.annotate;
+
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+
+public class OrderSwitches
+{
+ public static void processFile(File file) throws AnnotateClass.AnnotateClassDeleteException, AnnotateClass.AnnotateClassRenameException {
+ if(!file.exists()) {
+ System.out.println("Missing file: " + file.getPath());
+ return;
+ }
+ try
+ {
+ // Prepare to read the file.
+ FileInputStream fileInputStream = new FileInputStream(file);
+ InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
+ BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+
+ File tmpOutputFile = new File(file.getParentFile(), file.getName() + ".tmp");
+ FileOutputStream fileOutputStream = new FileOutputStream(tmpOutputFile);
+ PrintStream outputStream = new PrintStream(fileOutputStream);
+ try
+ {
+ // Read it line-by-line.
+ String line;
+ ArrayList<String> lines = new ArrayList<String>();
+ boolean inSwitch = false;
+ while ((line = bufferedReader.readLine()) != null)
+ {
+ if (line.contains("The following code was generated by JFlex "))
+ {
+ int c = line.indexOf(" on ");
+ if (c != -1)
+ line = line.substring(0, c) + " */";
+ }
+ if (line.contains("* on ") && line.contains("from the specification file"))
+ line = " * from the specification file";
+ if (line.contains("<tt>") && line.contains("compiler/src/main/jflex"))
+ {
+ int t = line.indexOf("<tt>");
+ int rc = line.indexOf("compiler/src/main/jflex");
+ line = line.substring(0, t + 4) + line.substring(rc);
+ }
+ // If the line starts with "switch", and the cases are numbers, make sure they are in order.
+ if (line.contains(" switch (zzAction")) {
+ inSwitch = true;
+ System.out.println("Ordering Switch in file: " + file.getPath());
+ }
+ if (inSwitch)
+ {
+ lines.add(line);
+ if (line.startsWith(" }")) {
+ orderSwitch(lines);
+ for (String orderedLine : lines)
+ {
+ outputStream.println(orderedLine);
+ }
+ inSwitch = false;
+ }
+ }
+ else
+ outputStream.println(line);
+ }
+ }
+ finally
+ {
+ try {
+ bufferedReader.close();
+ } catch(Exception e) {
+ // Ignore.
+ }
+ try {
+ outputStream.close();
+ } catch(Exception e) {
+ // Ignore.
+ }
+ try {
+ fileOutputStream.close();
+ } 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()) {
+ // 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 AnnotateClass.AnnotateClassDeleteException("Error deleting original file at: " + file.getPath());
+ }
+ }
+
+ // Rename the temp file to the name of the original file.
+ if(!tmpOutputFile.renameTo(file)) {
+ throw new AnnotateClass.AnnotateClassRenameException("Error renaming the temp file from: " + tmpOutputFile.getPath() +
+ " to: " + file.getPath());
+ }
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ private static void orderSwitch(ArrayList<String> lines) {
+ HashMap<String,List<String>> switchMap = new HashMap<String,List<String>>();
+ ArrayList<String> defaultCase = new ArrayList<String>();
+ ArrayList<String> breaks = new ArrayList<String>();
+ String line0 = lines.get(0); // first line should be switch statement
+ boolean inDefault = false;
+ int n = lines.size();
+ for (int i = 1; i < n; i++)
+ {
+ String line = lines.get(i);
+ int c = line.indexOf(" case ");
+ if (!inDefault && (c != -1))
+ {
+ String cayse = line.substring(c);
+ if (line.contains("break;"))
+ {
+ // some cases just contain a break statement.
+ // the are used to make sure the prior case
+ // ends with a break without having to check
+ // if the break statement would be reachable
+ // due to return statements in the case.
+ breaks.add(line);
+ continue;
+ }
+ else
+ {
+ ArrayList<String> caseLines = new ArrayList<String>();
+ for (int j = i + 1; j < n; j++)
+ {
+ line = lines.get(j);
+ if (line.contains(" case "))
+ {
+ switchMap.put(cayse, caseLines);
+ i = j - 1;
+ break;
+ }
+ else if (line.contains("default:"))
+ {
+ switchMap.put(cayse, caseLines);
+ inDefault = true;
+ i = j;
+ // assumes no break at end of default case
+ defaultCase.add(line);
+ break;
+ }
+ caseLines.add(line);
+ }
+ }
+ }
+ else if (line.contains("default:"))
+ {
+ inDefault = true;
+ // assumes no break at end of default case
+ defaultCase.add(line);
+ }
+ else if (inDefault)
+ defaultCase.add(line);
+ }
+ Set<String> keys = switchMap.keySet();
+ ArrayList<String> keyList = new ArrayList<String>();
+ keyList.addAll(keys);
+ Collections.sort(keyList);
+ lines.clear();
+ lines.add(line0);
+ int breakIndex = 0;
+ for (String key : keyList)
+ {
+ lines.add(" " + key);
+ List<String> caseLines = switchMap.get(key);
+ lines.addAll(caseLines);
+ lines.add(breaks.get(breakIndex++));
+ }
+ boolean inSwitch = false;
+ boolean sawDefault = false;
+ ArrayList<String> switchLines = new ArrayList<String>();
+ for (String defaultLine : defaultCase)
+ {
+ // If the line starts with "switch", and the cases are numbers, make sure they are in order.
+ if (defaultLine.contains("switch (zzLexicalState)")) {
+ inSwitch = true;
+ System.out.println("Ordering Switch in default: ");
+ }
+ if (inSwitch)
+ {
+ switchLines.add(defaultLine);
+ if (defaultLine.contains("default:"))
+ sawDefault = true;
+ if (sawDefault && defaultLine.startsWith(" }")) {
+ orderSwitch(switchLines);
+ for (String orderedLine : switchLines)
+ {
+ lines.add(orderedLine);
+ }
+ inSwitch = false;
+ }
+ }
+ else
+ lines.add(defaultLine);
+
+ }
+
+ }
+
+ public static void main(String[] args)
+ {
+ File f = new File(args[0]);
+ try {
+ processFile(f);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ }
+}
diff --git a/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/OrderSwitchesMojo.java b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/OrderSwitchesMojo.java
new file mode 100644
index 0000000..041ac33
--- /dev/null
+++ b/compiler-build-tools/src/main/java/org/apache/royale/compiler/tools/annotate/OrderSwitchesMojo.java
@@ -0,0 +1,74 @@
+/*
+ * 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.tools.annotate;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
+import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
+import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
+
+import java.io.*;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Goal which orders switch statement in JFlex output.
+ */
+@Mojo(name="order-jflex-switches",defaultPhase = LifecyclePhase.PROCESS_SOURCES)
+public class OrderSwitchesMojo
+ extends AbstractMojo
+{
+ @Parameter
+ protected Set<String> includes = new HashSet<String>();
+
+ @Parameter
+ protected Set<String> excludes = new HashSet<String>();
+
+ @Parameter(defaultValue="${project.build.directory}/generated-sources")
+ private File directory;
+
+ public void execute()
+ throws MojoExecutionException
+ {
+ SuffixMapping mapping = new SuffixMapping("jflex", Collections.<String>emptySet());
+ SimpleSourceInclusionScanner scan = new SimpleSourceInclusionScanner(includes, excludes);
+ scan.addSourceMapping(mapping);
+
+ try {
+ Set<File> candidates = scan.getIncludedSources(directory, null);
+ for(File candidate : candidates) {
+ try {
+ OrderSwitches.processFile(candidate);
+ } catch(AnnotateClass.AnnotateClassDeleteException e) {
+ throw new MojoExecutionException(e.getMessage());
+ } catch(AnnotateClass.AnnotateClassRenameException e) {
+ throw new MojoExecutionException(e.getMessage());
+ }
+ }
+ } catch (InclusionScanException e) {
+ throw new MojoExecutionException("Error scanning files to be processed.", e);
+ }
+ }
+}
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 6b6ca6d..86989f2 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
@@ -45,6 +45,7 @@
public ITypeDefinition type;
public boolean resolvedExport;
public String name;
+ public String originalName;
public String uri;
public boolean suppressExport;
}
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 e5a5998..f67b012 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
@@ -277,7 +277,7 @@
write(ASEmitterTokens.PAREN_CLOSE);
writeNewline(ASEmitterTokens.SEMICOLON);
writeNewline(" this.dispatchEvent("+fjs.formatQualifiedName(BindableEmitter.VALUECHANGE_EVENT_QNAME)+".createUpdateEvent(");
- writeNewline(" this, \"" + baseName + "\", oldValue, value));");
+ writeNewline(" this, \"" + p.originalName + "\", oldValue, value));");
writeNewline(ASEmitterTokens.BLOCK_CLOSE);
write(ASEmitterTokens.BLOCK_CLOSE);
write(ASEmitterTokens.SEMICOLON);
@@ -719,6 +719,7 @@
p = new PropertyNodes();
//track name and uri separately:
p.name = name;
+ p.originalName = node.getName();
p.uri = uri;
//resolvedExport is true if it is a custom namespace or one of a paired of accessor definitions is public
p.resolvedExport = uri != null || def.isPublic();
@@ -769,6 +770,7 @@
p = new PropertyNodes();
//track name and uri separately:
p.name = name;
+ p.originalName = node.getName();
p.uri = uri;
//resolvedExport is true if it is a custom namespace or one of a paired of accessor definitions is public
p.resolvedExport = uri != null || def.isPublic();
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 1e54271..64edb13 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
@@ -79,7 +79,7 @@
JSRoyaleDocEmitter doc = (JSRoyaleDocEmitter) getEmitter()
.getDocEmitter();
- if (!getEmitter().getModel().isExterns && doc.getEmitExports())
+ if (!getEmitter().getModel().isExterns && !getEmitter().getModel().suppressExports)
{
boolean isInterface = tnode instanceof IInterfaceNode;
boolean isDynamic = tnode instanceof IClassNode && tnode.hasModifier(ASModifier.DYNAMIC);
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 305a950..37d38f8 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
@@ -31,7 +31,9 @@
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.ITypeDefinition;
+import org.apache.royale.compiler.definitions.IVariableDefinition.VariableClassification;
import org.apache.royale.compiler.definitions.references.IReference;
import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens;
import org.apache.royale.compiler.internal.codegen.js.JSEmitterTokens;
@@ -140,6 +142,12 @@
emitExports = !suppressExports && fjp.config.getExportPublicSymbols();
exportProtected = !suppressExports && fjp.config.getExportProtectedSymbols();
}
+ else
+ {
+ emitExports = !suppressExports;
+ exportProtected = false;
+ }
+ emitExports = emitExports && !node.getFunctionClassification().equals(FunctionClassification.PACKAGE_MEMBER);
coercionList = null;
ignoreList = null;
@@ -544,9 +552,25 @@
@Override
public void emitFieldDoc(IVariableNode node, IDefinition def, ICompilerProject project)
{
+ RoyaleJSProject fjp = (RoyaleJSProject)project;
+ boolean suppressExports = false;
+ if (emitter instanceof JSRoyaleEmitter) {
+ suppressExports = ((JSRoyaleEmitter) emitter).getModel().suppressExports;
+ }
+ if (fjp.config != null)
+ {
+ emitExports = !suppressExports && fjp.config.getExportPublicSymbols();
+ exportProtected = !suppressExports && fjp.config.getExportProtectedSymbols();
+ }
+ else
+ {
+ emitExports = !suppressExports;
+ exportProtected = false;
+ }
+ emitExports = emitExports && !node.getVariableClassification().equals(VariableClassification.PACKAGE_MEMBER);
+
begin();
- RoyaleJSProject fjp = (RoyaleJSProject)project;
String ns = node.getNamespace();
if (ns == IASKeywordConstants.PRIVATE)
{
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 0be6c74..c260963 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
@@ -52,6 +52,7 @@
import org.apache.royale.compiler.projects.ICompilerProject;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.*;
+import org.apache.royale.compiler.utils.DefinitionUtils;
import org.apache.royale.compiler.utils.NativeUtils;
/**
@@ -940,4 +941,8 @@
return false;
}
+ public static final String getClassDepthNameBase(String base, IClassDefinition definition, ICompilerProject project) {
+ return base + "_" + DefinitionUtils.deltaFromObject(definition, project) +"_";
+ }
+
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleASDocEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleASDocEmitter.java
index 3aae3b8..14d6008 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleASDocEmitter.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/mxml/royale/MXMLRoyaleASDocEmitter.java
@@ -38,6 +38,7 @@
import org.apache.royale.compiler.internal.codegen.databinding.BindingDatabase;
import org.apache.royale.compiler.internal.codegen.databinding.BindingInfo;
import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleASDocEmitter;
+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.codegen.mxml.MXMLEmitter;
@@ -355,16 +356,22 @@
MXMLDescriptorSpecifier currentDescriptor = getCurrentDescriptor("i");
MXMLEventSpecifier eventSpecifier = new MXMLEventSpecifier();
- eventSpecifier.eventHandler = MXMLRoyaleEmitterTokens.EVENT_PREFIX
- .getToken() + eventCounter++;
+ IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker()).getASEmitter();
+ JSRoyaleEmitter fjs = (JSRoyaleEmitter)asEmitter;
+
+ IClassDefinition currentClass = fjs.getModel().getCurrentClass();
+ //naming needs to avoid conflicts with ancestors - using delta from object which is
+ //a) short and b)provides a 'unique' (not zero risk, but very low risk) option
+ String nameBase = EmitterUtils.getClassDepthNameBase(MXMLRoyaleEmitterTokens.EVENT_PREFIX
+ .getToken(), currentClass, getMXMLWalker().getProject());
+ eventSpecifier.eventHandler = nameBase + eventCounter++;
+
eventSpecifier.name = cdef.getBaseName();
eventSpecifier.type = node.getEventParameterDefinition()
.getTypeAsDisplayString();
eventHandlerNameMap.put(node, eventSpecifier.eventHandler);
-
- IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker())
- .getASEmitter();
+
StringBuilder sb = null;
int len = node.getChildCount();
@@ -406,8 +413,14 @@
String id = node.getID();
if (id == null)
id = node.getEffectiveID();
- if (id == null)
- id = MXMLRoyaleEmitterTokens.ID_PREFIX.getToken() + idCounter++;
+ if (id == null) {
+ IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker()).getASEmitter();
+ JSRoyaleEmitter fjs = (JSRoyaleEmitter)asEmitter;
+ IClassDefinition currentClass = fjs.getModel().getCurrentClass();
+ //naming needs to avoid conflicts with ancestors - using delta from object which is
+ //a) short and b)provides a 'unique' (not zero risk, but very low risk) option
+ id = EmitterUtils.getClassDepthNameBase(MXMLRoyaleEmitterTokens.ID_PREFIX.getToken(), currentClass, getMXMLWalker().getProject()) + idCounter++;
+ }
MXMLDescriptorSpecifier currentInstance = new MXMLDescriptorSpecifier();
currentInstance.isProperty = false;
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 e8c8e2a..02b2f40 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
@@ -77,6 +77,7 @@
import org.apache.royale.compiler.internal.codegen.js.jx.PackageFooterEmitter;
import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils;
import org.apache.royale.compiler.internal.codegen.mxml.MXMLEmitter;
+import org.apache.royale.compiler.internal.codegen.mxml.MXMLEmitterTokens;
import org.apache.royale.compiler.internal.driver.js.royale.JSCSSCompilationSession;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
@@ -101,6 +102,7 @@
import org.apache.royale.compiler.tree.metadata.IMetaTagsNode;
import org.apache.royale.compiler.tree.mxml.*;
import org.apache.royale.compiler.units.ICompilationUnit;
+import org.apache.royale.compiler.utils.DefinitionUtils;
import org.apache.royale.compiler.utils.NativeUtils;
import org.apache.royale.compiler.visitor.mxml.IMXMLBlockWalker;
import org.apache.royale.swc.ISWC;
@@ -1462,15 +1464,20 @@
{
for (MXMLDescriptorSpecifier instance : instances)
{
- writeNewline();
- writeNewline("/**");
- writeNewline(" * @private");
- writeNewline(" * @type {" + instance.name + "}");
- writeNewline(" */");
- write(ASEmitterTokens.THIS);
- write(ASEmitterTokens.MEMBER_ACCESS);
- write((instance.id != null ? instance.id : instance.effectiveId) + "_");
- writeNewline(ASEmitterTokens.SEMICOLON);
+ String id = instance.id != null ? instance.id : instance.effectiveId;
+ if (id != null) { //it seems id can be null, for example with a generated Object for Operations via RemoteObject
+ writeNewline();
+ writeNewline("/**");
+ writeNewline(" * @private");
+ writeNewline(" * @type {" + instance.name + "}");
+ writeNewline(" */");
+ write(ASEmitterTokens.THIS);
+ write(ASEmitterTokens.MEMBER_ACCESS);
+
+ if (!id.startsWith(MXMLRoyaleEmitterTokens.ID_PREFIX.getToken())) id += "_";
+ write(id);
+ writeNewline(ASEmitterTokens.SEMICOLON);
+ }
}
}
@@ -1501,6 +1508,12 @@
writeNewline(formatQualifiedName(cname)
+ ".prototype._bindings = [");
+ if (bindingDataBase.getHasAncestorBindings()) {
+ //reference the ancestor binding data (which may in turn reference its owner's ancestor's bindings etc)
+ writeNewline(formatQualifiedName(bindingDataBase.getNearestAncestorWithBindings()) +
+ ".prototype._bindings,");
+ }
+
Set<BindingInfo> bindingInfo = bindingDataBase.getBindingInfo();
writeNewline(bindingInfo.size() + ","); // number of bindings
boolean hadOutput = false;
@@ -2252,8 +2265,16 @@
MXMLDescriptorSpecifier currentDescriptor = getCurrentDescriptor("i");
MXMLEventSpecifier eventSpecifier = new MXMLEventSpecifier();
- eventSpecifier.eventHandler = MXMLRoyaleEmitterTokens.EVENT_PREFIX
- .getToken() + eventCounter++;
+
+ IASEmitter asEmitter = ((IMXMLBlockWalker) getMXMLWalker()).getASEmitter();
+ JSRoyaleEmitter fjs = (JSRoyaleEmitter)asEmitter;
+
+ IClassDefinition currentClass = fjs.getModel().getCurrentClass();
+ //naming needs to avoid conflicts with ancestors - using delta from object which is
+ //a) short and b)provides a 'unique' (not zero risk, but very low risk) option
+ String nameBase = EmitterUtils.getClassDepthNameBase(MXMLRoyaleEmitterTokens.EVENT_PREFIX
+ .getToken(), currentClass, getMXMLWalker().getProject());
+ eventSpecifier.eventHandler = nameBase + eventCounter++;
eventSpecifier.name = cdef.getBaseName();
eventSpecifier.type = node.getEventParameterDefinition()
.getTypeAsDisplayString();
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 acb4a2e..beedbe9 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
@@ -39,6 +39,7 @@
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.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
@@ -48,6 +49,7 @@
import org.apache.royale.compiler.definitions.references.ReferenceFactory;
import org.apache.royale.compiler.driver.IBackend;
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.codegen.mxml.royale.MXMLRoyaleEmitterTokens;
import org.apache.royale.compiler.internal.common.JSModuleRequireDescription;
import org.apache.royale.compiler.internal.css.codegen.CSSCompilationSession;
@@ -68,6 +70,7 @@
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.tree.mxml.IMXMLClassDefinitionNode;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.compiler.units.ICompilationUnit.UnitType;
import org.apache.royale.swc.ISWC;
@@ -522,9 +525,10 @@
}
@Override
- public String getGeneratedIDBase()
+ public String getGeneratedIDBase(IMXMLClassDefinitionNode definitionNode)
{
- return MXMLRoyaleEmitterTokens.ID_PREFIX.getToken();
+ IClassDefinition classDefinition = definitionNode.getDefinition();
+ return EmitterUtils.getClassDepthNameBase(MXMLRoyaleEmitterTokens.ID_PREFIX.getToken(), classDefinition, this);
}
public ITargetAttributes computeTargetAttributes()
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/ClosureUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/ClosureUtils.java
index 78c2ea7..0a28046 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/ClosureUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/ClosureUtils.java
@@ -30,6 +30,7 @@
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.IVariableDefinition.VariableClassification;
import org.apache.royale.compiler.definitions.references.INamespaceReference;
import org.apache.royale.compiler.internal.codegen.js.utils.DocEmitterUtils;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
@@ -68,6 +69,14 @@
//file-private symbols are emitted like static variables
result.add(def.getBaseName());
}
+ if (def instanceof IVariableDefinition
+ && !(def instanceof IAccessorDefinition))
+ {
+ IVariableDefinition varDef = (IVariableDefinition) def;
+ if (varDef.getVariableClassification().equals(VariableClassification.PACKAGE_MEMBER)) {
+ result.add(def.getBaseName());
+ }
+ }
if (def instanceof ITypeDefinition)
{
if (def.isImplicit() || def.isNative())
@@ -148,6 +157,10 @@
}
else
{
+ if (project.isExterns(qualifiedName))
+ {
+ return;
+ }
symbolsResult.add(qualifiedName);
if(parentQName == null)
{
@@ -173,18 +186,22 @@
boolean isPublic = nsRef instanceof INamespaceDefinition.IPublicNamespaceDefinition;
boolean isProtected = nsRef instanceof INamespaceDefinition.IProtectedNamespaceDefinition
|| nsRef instanceof INamespaceDefinition.IStaticProtectedNamespaceDefinition;
- if (localDef instanceof IFunctionDefinition && !(localDef instanceof IVariableDefinition)
- && localDef.isStatic() && isPublic)
+ if (localDef instanceof IFunctionDefinition
+ && !(localDef instanceof IAccessorDefinition)
+ // the next two conditions are temporary
+ // and more symbols will be exported in the future
+ && localDef.isStatic()
+ && isPublic)
{
if ((isPublic && exportPublic) || (isProtected && exportProtected))
{
if (isFilePrivate)
{
- filePrivateNames.add(qualifiedName + "." + localDef.getBaseName());
+ filePrivateNames.add(qualifiedName + (localDef.isStatic() ? "." : ".prototype.") + localDef.getBaseName());
}
else
{
- symbolsResult.add(qualifiedName + "." + localDef.getBaseName());
+ symbolsResult.add(qualifiedName + (localDef.isStatic() ? "." : ".prototype.") + localDef.getBaseName());
}
}
}
diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java
index 80b0ae4..40ec8e5 100644
--- a/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java
+++ b/compiler-jx/src/main/java/org/apache/royale/compiler/utils/DefinitionUtils.java
@@ -22,6 +22,7 @@
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.IInterfaceDefinition;
+import org.apache.royale.compiler.projects.ICompilerProject;
/**
* @author Michael Schmalle
@@ -34,4 +35,15 @@
&& (definition.getParent() instanceof IClassDefinition || definition
.getParent() instanceof IInterfaceDefinition);
}
+
+
+ public static final int deltaFromObject(IClassDefinition definition, ICompilerProject project) {
+ int ret = -1;
+ if (definition != null) {
+ return definition.resolveAncestry(project).length - 1;
+ }
+ return ret;
+ }
+
+
}
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 08c748d..dfb6c30 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
@@ -1133,7 +1133,6 @@
"\n" +
"\n" +
"/**\n" +
- " * @export\n" +
" * @return {number}\n" +
" */\n" +
"foo.bar.A = function() {\n" +
@@ -1193,7 +1192,7 @@
{
IFileNode node = compileAS("package {public function A(){}}");
asBlockWalker.visitFile(node);
- assertOutWithMetadata("/**\n * A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('A');\n\n\n\n/**\n * @export\n */\nA = function() {\n}");
+ assertOutWithMetadata("/**\n * A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('A');\n\n\n\n/**\n */\nA = function() {\n}");
}
@Test
@@ -1201,7 +1200,7 @@
{
IFileNode node = compileAS("package foo.bar.baz {public function A(){}}");
asBlockWalker.visitFile(node);
- assertOutWithMetadata("/**\n * foo.bar.baz.A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('foo.bar.baz.A');\n\n\n\n/**\n * @export\n */\nfoo.bar.baz.A = function() {\n}");
+ assertOutWithMetadata("/**\n * foo.bar.baz.A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('foo.bar.baz.A');\n\n\n\n/**\n */\nfoo.bar.baz.A = function() {\n}");
}
@Test
@@ -1209,7 +1208,7 @@
{
IFileNode node = compileAS("package {public var A:String = \"Hello\";}");
asBlockWalker.visitFile(node);
- assertOutWithMetadata("/**\n * A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('A');\n\n\n\n/**\n * @export\n * @type {string}\n */\nA = \"Hello\"");
+ assertOutWithMetadata("/**\n * A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('A');\n\n\n\n/**\n * @type {string}\n */\nA = \"Hello\"");
}
@Test
@@ -1217,7 +1216,7 @@
{
IFileNode node = compileAS("package foo.bar.baz {public var A:String = \"Hello\";}");
asBlockWalker.visitFile(node);
- assertOutWithMetadata("/**\n * foo.bar.baz.A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('foo.bar.baz.A');\n\n\n\n/**\n * @export\n * @type {string}\n */\nfoo.bar.baz.A = \"Hello\"");
+ assertOutWithMetadata("/**\n * foo.bar.baz.A\n *\n * @fileoverview\n *\n * @suppress {checkTypes|accessControls}\n */\n\ngoog.provide('foo.bar.baz.A');\n\n\n\n/**\n * @type {string}\n */\nfoo.bar.baz.A = \"Hello\"");
}
@Override
diff --git a/compiler/build.xml b/compiler/build.xml
index bca3b89..3348d3e 100644
--- a/compiler/build.xml
+++ b/compiler/build.xml
@@ -202,6 +202,25 @@
</macrodef>
<!--
+ Defines an <order.switches file="..."> macro
+ used for ordering the switch statement generated by
+ JFlex in order to get reproducible builds.
+ -->
+ <macrodef name="order.switches">
+ <attribute name="file"/>
+ <sequential>
+ <java classname="org.apache.royale.compiler.tools.annotate.OrderSwitches" fork="false">
+ <classpath>
+ <path refid="classpath"/>
+ <pathelement location="${compiler}/../compiler-build-tools/target/classes"/>
+ <pathelement location="${compiler}/target/classes"/>
+ </classpath>
+ <arg value="@{file}"/>
+ </java>
+ </sequential>
+ </macrodef>
+
+ <!--
SETUP
@@ -237,6 +256,7 @@
<jflex input="${compiler}/src/main/jflex/org/apache/royale/compiler/internal/parsing/as/RawASTokenizer.lex"
skeleton="${compiler}/src/main/jflex/org/apache/royale/compiler/internal/parsing/as/skeleton.royale"
output="${compiler}/target/generated-sources/jflex/org/apache/royale/compiler/internal/parsing/as"/>
+ <order.switches file="${compiler}/target/generated-sources/jflex/org/apache/royale/compiler/internal/parsing/as/RawASTokenizer.java" />
</target>
<target name="set.raw.asdoc.tokenizer.uptodate">
@@ -254,6 +274,7 @@
<echo message="Generating RawASDocTokenizer"/>
<jflex input="${compiler}/src/main/jflex/org/apache/royale/compiler/internal/parsing/as/RawASDocTokenizer.lex"
output="${compiler}/target/generated-sources/jflex/org/apache/royale/compiler/internal/parsing/as"/>
+ <order.switches file="${compiler}/target/generated-sources/jflex/org/apache/royale/compiler/internal/parsing/as/RawASDocTokenizer.java" />
</target>
<target name="set.raw.mxml.tokenizer.uptodate">
@@ -271,6 +292,7 @@
<echo message="Generating RawMXMLTokenizer"/>
<jflex input="${compiler}/src/main/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.lex"
output="${compiler}/target/generated-sources/jflex/org/apache/royale/compiler/internal/parsing/mxml"/>
+ <order.switches file="${compiler}/target/generated-sources/jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.java" />
</target>
<target name="jflex" depends="raw.as.tokenizer, raw.asdoc.tokenizer, raw.mxml.tokenizer"
diff --git a/compiler/pom.xml b/compiler/pom.xml
index cf1c584..76df53a 100644
--- a/compiler/pom.xml
+++ b/compiler/pom.xml
@@ -1,21 +1,21 @@
<?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.
-
+<!--
+
+ 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>
@@ -82,8 +82,8 @@
</execution>
</executions>
</plugin>
- <!--
- Do all the JFlex code generation
+ <!--
+ Do all the JFlex code generation
-->
<plugin>
<groupId>de.jflex</groupId>
@@ -129,8 +129,8 @@
</execution>
</executions>
</plugin>
- <!--
- Do all the Antlr2 code generation
+ <!--
+ Do all the Antlr2 code generation
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@@ -155,12 +155,12 @@
</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.
+ <!--
+ 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>
@@ -239,8 +239,8 @@
</executions>
</plugin>
- <!--
- Do all the JBurg code generation.
+ <!--
+ Do all the JBurg code generation.
-->
<plugin>
<groupId>net.sourceforge.jburg</groupId>
@@ -293,8 +293,8 @@
</dependencies>
</plugin>
- <!--
- Do all the Antlr3 code generation.
+ <!--
+ Do all the Antlr3 code generation.
-->
<plugin>
<groupId>org.antlr</groupId>
@@ -329,8 +329,8 @@
</executions>
</plugin>
- <!--
- Do all the custom processing with the royale build tools.
+ <!--
+ Do all the custom processing with the royale build tools.
-->
<plugin>
<groupId>org.apache.royale.compiler</groupId>
@@ -426,6 +426,19 @@
<goal>generate-problems-resource-bundle</goal>
</goals>
</execution>
+ <execution>
+ <id>order-jflex-switch-statements</id>
+ <goals>
+ <goal>order-jflex-switches</goal>
+ </goals>
+ <configuration>
+ <includes>
+ <include>jflex/org/apache/royale/compiler/internal/parsing/as/RawASDocTokenizer.java</include>
+ <include>jflex/org/apache/royale/compiler/internal/parsing/as/RawASTokenizer.java</include>
+ <include>jflex/org/apache/royale/compiler/internal/parsing/mxml/RawMXMLTokenizer.java</include>
+ </includes>
+ </configuration>
+ </execution>
</executions>
</plugin>
@@ -490,10 +503,10 @@
</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.
+ <!--
+ 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>option-with-flex-sdk-tests</id>
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 ecf8158..9412bcb 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
@@ -219,6 +219,9 @@
// [RoyaleArrayLike(...args)]
static final String ATTRIBUTE_ARRAYLIKE = "RoyaleArrayLike";
+
+ // [RoyaleBindings] (added by compiler)
+ static final String ATTRIBUTE_BINDINGS= "RoyaleBindings";
/**
* List of metadata tags that do not inherit
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 d1df60c..d7a087a 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
@@ -27,9 +27,7 @@
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
-import java.util.WeakHashMap;
-import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.internal.as.codegen.MXMLClassDirectiveProcessor;
import org.apache.royale.compiler.internal.codegen.databinding.WatcherInfoBase.WatcherType;
import org.apache.royale.compiler.internal.scopes.ASScope;
@@ -65,6 +63,20 @@
_diagnosticLogger.add(this);
}
}
+
+ private String nearestAncestorBindings = null;
+
+ public Boolean getHasAncestorBindings(){
+ return nearestAncestorBindings != null;
+ }
+
+ public void setNearestAncestorWithBindings(String value){
+ nearestAncestorBindings = value;
+ }
+
+ public String getNearestAncestorWithBindings(){
+ return nearestAncestorBindings;
+ }
/************** private data ****************/
@@ -337,6 +349,10 @@
public String toString()
{
StringBuilder sb = new StringBuilder();
+
+ if (nearestAncestorBindings != null) {
+ sb.append("<ancestor bindings also exist at "+ nearestAncestorBindings+ " >");
+ }
if (bindingInfoSet.isEmpty())
{
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
index a5a2fe6..ea82e09 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/MXMLBindingDirectiveHelper.java
@@ -33,6 +33,8 @@
import org.apache.royale.abc.visitors.IABCVisitor;
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+import org.apache.royale.compiler.constants.IMetaAttributeConstants;
+import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
import org.apache.royale.compiler.definitions.references.IResolvedQualifiersReference;
import org.apache.royale.compiler.definitions.references.ReferenceFactory;
@@ -63,9 +65,10 @@
* TODO:
* Document the runtime dependencies on SDK
* add problem reporting.
- *
+ *
+ * bind to function, This should be fixed now
* Cases not yet working:
- * bind to function, xml, xml list, array
+ * xml, xml list, array
*
* Improve code gen
* don't make getter functions when not needed
@@ -145,6 +148,15 @@
return null;
bindingDataBase.finishAnalysis();
+
+ for (IClassDefinition ancestor: host.getClassDefinition().resolveAncestry(host.getProject())) {
+ if (ancestor.equals(host.getClassDefinition())) continue;
+ if (ancestor.getMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_BINDINGS) != null) {
+ //System.out.println("Ancestor bindings for "+host.getClassDefinition().getQualifiedName()+" at "+ancestor.getQualifiedName());
+ bindingDataBase.setNearestAncestorWithBindings(ancestor.getQualifiedName());
+ break;
+ }
+ }
// Please leave this in here - it is a very commonly used diagnostic
// Just comment it out before checking
@@ -159,8 +171,15 @@
makeSpecialMemberVariablesForBinding();
isFlexSDK = true;
}
- else
- host.addVariableTrait(IMXMLTypeConstants.NAME_BINDINGS, NAME_ARRAYTYPE);
+ else {
+ //if the variable is already declared on an ancestor, we should not redeclare it (as it is currently public)
+ //redeclaring it will essentially prevent the inherited value from being accessed at the current level (in swf)
+ //accessing the super class value allows 'nesting' which permits inheritance
+ if (!bindingDataBase.getHasAncestorBindings())
+ host.addVariableTrait(IMXMLTypeConstants.NAME_BINDINGS, NAME_ARRAYTYPE);
+ //this should already be set, the following may be able to be removed (tbc):
+ host.getClassDefinition().setRoyaleBindings();
+ }
}
else
{
@@ -169,8 +188,14 @@
makeSpecialMemberVariablesForBinding();
isFlexSDK = true;
}
- else
- host.addVariableTrait(IMXMLTypeConstants.NAME_BINDINGS, NAME_ARRAYTYPE);
+ else{
+ //redeclaring it will essentially prevent the inherited value from being accessed at the current level (in swf)
+ if (!bindingDataBase.getHasAncestorBindings())
+ host.addVariableTrait(IMXMLTypeConstants.NAME_BINDINGS, NAME_ARRAYTYPE);
+ //this should already be set, the following may be able to be removed (tbc):
+ host.getClassDefinition().setRoyaleBindings();
+
+ }
}
if (host.getProject().getTargetSettings().getMxmlChildrenAsData())
@@ -191,11 +216,20 @@
private InstructionList outputBindingInfoAsData(boolean isFlexSDK)
{
- //System.out.println("outputBindingInfoAsData");
InstructionList ret = new InstructionList();
int propertyCount = 0;
-
+ if (!isFlexSDK && bindingDataBase.getHasAncestorBindings()) {
+ //add the ancestor bindings reference as the first item in this current _bindings array
+ //this approach permits binding evaluation to work recursively by checking the first element only
+
+ ret.addInstruction(OP_getlocal0);
+ // stack: ..., this
+ ret.addInstruction(OP_getproperty, IMXMLTypeConstants.NAME_BINDINGS);
+ //propertyCount needs to be incremented for the current array:
+ propertyCount++;
+ }
+
Set<BindingInfo> bindingInfo = bindingDataBase.getBindingInfo();
ret.pushNumericConstant(bindingInfo.size()); // number of bindings
propertyCount++;
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/WatcherAnalyzer.java b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/WatcherAnalyzer.java
index 7f9289e..50ade92 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/WatcherAnalyzer.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/WatcherAnalyzer.java
@@ -24,6 +24,7 @@
import java.util.List;
import org.apache.royale.compiler.constants.IASKeywordConstants;
+import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.IClassDefinition;
import org.apache.royale.compiler.definitions.IConstantDefinition;
import org.apache.royale.compiler.definitions.IDefinition;
@@ -34,6 +35,8 @@
import org.apache.royale.compiler.internal.codegen.databinding.WatcherInfoBase.WatcherType;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
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.problems.ICompilerProblem;
import org.apache.royale.compiler.problems.MXMLDatabindingSourceNotBindableProblem;
import org.apache.royale.compiler.projects.ICompilerProject;
@@ -271,6 +274,52 @@
}
}
+ private boolean isLeftXML(MemberAccessExpressionNode maen)
+ {
+ IDefinition xmlDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.XML);
+ if (maen.getLeftOperandNode().getNodeID() == ASTNodeID.Op_AsID)
+ {
+ if (maen.getLeftOperandNode().getChild(1).getNodeID() == ASTNodeID.IdentifierID)
+ {
+ IdentifierNode child = (IdentifierNode)maen.getLeftOperandNode().getChild(1);
+ IDefinition def = child.resolve(project);
+ if (def == xmlDef)
+ return true;
+ ITypeDefinition type = child.resolveType(project);
+ if (type != null && type.isInstanceOf("XML", project))
+ return true;
+ }
+ }
+ else if (maen.getLeftOperandNode().getNodeID() == ASTNodeID.MemberAccessExpressionID)
+ {
+ maen = (MemberAccessExpressionNode)maen.getLeftOperandNode();
+ if (isLeftXML(maen))
+ return true;
+ }
+ return false;
+ }
+
+ private boolean nodeIsXML(IASNode node)
+ {
+ IDefinition xmlDef = project.getBuiltinType(IASLanguageConstants.BuiltinType.XML);
+ IASNode parent = node.getParent();
+ while (parent != null && (parent.getNodeID() == ASTNodeID.MemberAccessExpressionID))
+ {
+ MemberAccessExpressionNode maen = ((MemberAccessExpressionNode)parent);
+ IDefinition def = maen.resolve(project);
+ if (def == xmlDef)
+ return true;
+ ITypeDefinition type = maen.resolveType(project);
+ if (type != null && type.isInstanceOf("XML", project))
+ return true;
+ if (def != null)
+ break;
+ if (isLeftXML(maen))
+ return true;
+ parent = parent.getParent();
+ }
+ return false;
+ }
private void analyzeIdentifierNode(IIdentifierNode node, AnalysisState state)
{
@@ -288,6 +337,8 @@
// may very well be a dynamic property with no definition,
// so will will continue on (with the knowledge that we have no
// IDefinition
+ if (nodeIsXML(node))
+ return;
this.problems.add(new MXMLDatabindingSourceNotBindableProblem(node, node.getName()));
return;
}
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 85a6900..0454ef2 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
@@ -1383,6 +1383,18 @@
addMetaTag(excludeClassMetaTag);
}
+
+ /**
+ * Mark this class as being generated with mxml bindings [RoyaleBindings] meta data.
+ */
+ public void setRoyaleBindings()
+ {
+ if (!hasMetaTagByName(IMetaAttributeConstants.ATTRIBUTE_BINDINGS)) {
+ MetaTag bindingsMarker = new MetaTag(this, IMetaAttributeConstants.ATTRIBUTE_BINDINGS, new IMetaTagAttribute[0]);
+ addMetaTag(bindingsMarker);
+ }
+ }
+
/**
* For debugging only. Produces a string such as
* <code>public class B extends A implements I1, I2</code>.
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 b85c412..0613ffe 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
@@ -92,6 +92,7 @@
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IImportNode;
+import org.apache.royale.compiler.tree.mxml.IMXMLClassDefinitionNode;
import org.apache.royale.compiler.units.ICompilationUnit;
import org.apache.royale.compiler.units.requests.IOutgoingDependenciesRequestResult;
import org.apache.royale.compiler.units.requests.IRequest;
@@ -2249,9 +2250,10 @@
* it isn't allowed in an ActionScript identifier or MXML id. It also can't
* conflict with any dynamic properties, because MXML classes are sealed.
*/
- public String getGeneratedIDBase()
+ public String getGeneratedIDBase(IMXMLClassDefinitionNode definitionNode)
{
- return "#";
+ IClassDefinition classDefinition = definitionNode.getDefinition();
+ return "#_"+classDefinition.resolveAncestry(this).length+"_";
}
@Override
@@ -2620,12 +2622,12 @@
}
- private WeakHashMap<IClassDefinition, BindingDatabase> bindingMap = new WeakHashMap<IClassDefinition, BindingDatabase>();
+ private HashMap<IClassDefinition, BindingDatabase> bindingMap = new HashMap<IClassDefinition, BindingDatabase>();
/**
* Support for access to BindingData from the class definition as key.
* @return
*/
- public WeakHashMap<IClassDefinition, BindingDatabase> getBindingMap(){
+ public HashMap<IClassDefinition, BindingDatabase> getBindingMap(){
return bindingMap;
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassDefinitionNode.java b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassDefinitionNode.java
index 5cfd2d2..e4d16f9 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassDefinitionNode.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/mxml/MXMLClassDefinitionNode.java
@@ -754,7 +754,7 @@
{
if (generatedIDMap.containsKey(instanceNode))
return;
- String id = project.getGeneratedIDBase() + generatedIDCounter++;
+ String id = project.getGeneratedIDBase(this) + generatedIDCounter++;
generatedIDMap.put(instanceNode, id);
}
}
diff --git a/compiler/src/main/java/org/apache/royale/compiler/internal/units/MXMLCompilationUnit.java b/compiler/src/main/java/org/apache/royale/compiler/internal/units/MXMLCompilationUnit.java
index 13c587b..e8f000d 100644
--- a/compiler/src/main/java/org/apache/royale/compiler/internal/units/MXMLCompilationUnit.java
+++ b/compiler/src/main/java/org/apache/royale/compiler/internal/units/MXMLCompilationUnit.java
@@ -114,6 +114,9 @@
{
TypeScope mainClassScope = (TypeScope)mainClassDefinition.getContainedScope();
documentNode.setScope(mainClassScope);
+ if (documentNode.getHasDataBindings()) {
+ mainClassDefinition.setRoyaleBindings();
+ }
}
}
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 b003466..0836a82 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
@@ -250,6 +250,6 @@
* Support for access to BindingData from the class definition as key.
* @return
*/
- WeakHashMap<IClassDefinition, BindingDatabase> getBindingMap();
+ HashMap<IClassDefinition, BindingDatabase> getBindingMap();
}
diff --git a/pom.xml b/pom.xml
index e9e37e2..cd37577 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,21 +1,21 @@
<?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.
-
+<!--
+
+ 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>
@@ -46,7 +46,7 @@
<project.reporting.outputencoding>UTF-8</project.reporting.outputencoding>
<maven.version>3.3.1</maven.version>
- <compiler-build-tools.version>1.2.0</compiler-build-tools.version>
+ <compiler-build-tools.version>1.2.1-SNAPSHOT</compiler-build-tools.version>
<compiler-jburg-types.version>1.1.0</compiler-jburg-types.version>
<flex.version>4.15.0</flex.version>
@@ -174,24 +174,24 @@
<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 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
+ <!--
+ 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.
+ <!-- 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>
@@ -231,9 +231,9 @@
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
- <!--
- Prepares the property pointing to the JaCoCo runtime agent which
- is passed as VM argument when Maven the Surefire plugin is executed.
+ <!--
+ 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>
@@ -243,16 +243,16 @@
<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.
+ <!--
+ Sets the name of the property containing the settings
+ for JaCoCo runtime agent.
-->
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
- <!--
- Prepares the property pointing to the JaCoCo runtime agent which
- is passed as VM argument when Maven the Failsafe plugin is executed.
+ <!--
+ 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>
@@ -263,9 +263,9 @@
<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.
+ <!--
+ Sets the name of the property containing the settings
+ for JaCoCo runtime agent.
-->
<propertyName>failsafeArgLine</propertyName>
</configuration>
@@ -288,12 +288,12 @@
<mavenLocalRepoDir>${settings.localRepository}</mavenLocalRepoDir>
<optionWithSwfEnabled>${option.withSwf.enabled}</optionWithSwfEnabled>
</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 definitely fix
- the tests so assertions can be enabled.
+ <!--
+ 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 definitely fix
+ the tests so assertions can be enabled.
-->
<enableAssertions>false</enableAssertions>
</configuration>
@@ -616,8 +616,8 @@
</profile>
<profile>
- <!-- This profile is used to test against staged release artifacts.
- Be sure to clear out artifacts in the local repository before
+ <!-- This profile is used to test against staged release artifacts.
+ Be sure to clear out artifacts in the local repository before
and after using -->
<id>staged-releases</id>
<pluginRepositories>
@@ -628,9 +628,9 @@
</pluginRepositories>
</profile>
- <!--
- This profile enables the changes required to do releases on the Royale CI server.
- It should not be used otherwise.
+ <!--
+ This profile enables the changes required to do releases on the Royale CI server.
+ It should not be used otherwise.
-->
<profile>
<id>royale-release</id>
@@ -645,11 +645,11 @@
<repository>
<id>apache.releases.https</id>
<name>Apache Release Distribution Repository</name>
- <!--
- 'maven.multiModuleProjectDirectory' is a property introduced with maven 3.3.1 ...
- don't worry if your IDE is complaining.
- Also this will be set to the 'target/checkout' directory the output will be in
- 'target/local-release-dir'.
+ <!--
+ 'maven.multiModuleProjectDirectory' is a property introduced with maven 3.3.1 ...
+ don't worry if your IDE is complaining.
+ Also this will be set to the 'target/checkout' directory the output will be in
+ 'target/local-release-dir'.
-->
<url>file://${maven.multiModuleProjectDirectory}/../local-release-dir</url>
</repository>
@@ -713,8 +713,6 @@
<id>apache-release</id>
<build>
<plugins>
- <!--
- Create MD5 and SHA512 checksum files for the release artifacts.
-->
<plugin>
<groupId>net.nicoulaj.maven.plugins</groupId>
@@ -745,11 +743,11 @@
</build>
</profile>
- <!--
- This profile is intended to help when having problems with Maven.
- When enabled, it automatically generates an "effective.pom" in the target directory.
- This version is the fully expanded version where all inherited configuration is in
- place and all variables are resolved and profile configuration is included.
+ <!--
+ This profile is intended to help when having problems with Maven.
+ When enabled, it automatically generates an "effective.pom" in the target directory.
+ This version is the fully expanded version where all inherited configuration is in
+ place and all variables are resolved and profile configuration is included.
-->
<profile>
<id>debug-pom</id>