This is an automated email from the ASF dual-hosted git repository.
gregdove pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
The following commit(s) were added to refs/heads/develop by this push:
new 65b2f1b Fixes for multiple issues with Bindings and Bindables. Closes
#114
65b2f1b is described below
commit 65b2f1b9c3476ccb3b7b509b052025bd153504b4
Author: greg-dove <[email protected]>
AuthorDate: Tue Mar 3 10:44:02 2020 +1300
Fixes for multiple issues with Bindings and Bindables. Closes #114
---
.../internal/codegen/js/jx/AccessorEmitter.java | 41 ++++----
.../codegen/js/jx/MemberAccessEmitter.java | 46 +++++++++
.../codegen/mxml/royale/MXMLRoyaleEmitter.java | 2 +-
.../internal/as/codegen/BindableHelper.java | 103 ++++++++++++++++++++-
.../as/codegen/ClassDirectiveProcessor.java | 80 ++++++++--------
.../codegen/databinding/BindingCodeGenUtils.java | 80 +++++++++++-----
.../databinding/MXMLBindingDirectiveHelper.java | 5 +-
.../internal/definitions/DefinitionBase.java | 20 ++--
.../internal/definitions/VariableDefinition.java | 9 ++
.../internal/parsing/mxml/MXMLScopeBuilder.java | 1 +
.../compiler/internal/tree/as/VariableNode.java | 16 +++-
11 files changed, 302 insertions(+), 101 deletions(-)
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 2b0ab7c..e5a5998 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
@@ -35,7 +35,7 @@ import
org.apache.royale.compiler.definitions.IFunctionDefinition;
import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.definitions.IParameterDefinition;
import org.apache.royale.compiler.definitions.ITypeDefinition;
-import org.apache.royale.compiler.definitions.metadata.IMetaTag;
+import org.apache.royale.compiler.internal.as.codegen.BindableHelper;
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.JSSessionModel.PropertyNodes;
@@ -163,6 +163,8 @@ public class AccessorEmitter extends JSSubEmitter implements
}
if (setterNode != null)
{
+ boolean isClassBindable =
BindableHelper.isClassCodeGenBindable(definition);
+
boolean isBindable = false;
IAccessorDefinition setterDef =
(IAccessorDefinition)setterNode.getDefinition();
IAccessorDefinition getterDef = null;
@@ -170,34 +172,25 @@ public class AccessorEmitter extends JSSubEmitter
implements
getterDef =
(IAccessorDefinition)getterNode.getDefinition();
if ((getterDef != null &&
(setterDef.isBindable() || getterDef.isBindable())))
{
+ boolean
foundExplicitBindableTag = false;
if (setterDef.isBindable())
{
- IMetaTag[] tags =
setterDef.getMetaTagsByName("Bindable");
- if (tags.length > 1)
- isBindable = true;
- else if (tags.length == 1)
- {
- if
(tags[0].getAllAttributes().length == 0)
- isBindable =
true;
- }
- if (tags.length == 0 ) {
- isBindable =
definition.isBindable();// if the class itself is marked as Bindable
- }
+
+ isBindable =
BindableHelper.isCodeGenBindableMember(setterDef, isClassBindable);
+
foundExplicitBindableTag = BindableHelper.hasExplicitBindable(setterDef);
}
- else if (getterDef.isBindable())
+ if (getterDef.isBindable())
{
- IMetaTag[] tags =
getterDef.getMetaTagsByName("Bindable");
- if (tags.length > 1)
- isBindable = true;
- else if (tags.length == 1)
- {
- if
(tags[0].getAllAttributes().length == 0)
- isBindable =
true;
- }
- if (tags.length
== 0 ) {
-
isBindable = definition.isBindable();// if the class itself is marked as
Bindable
- }
+
+ isBindable =
isBindable || BindableHelper.isCodeGenBindableMember(getterDef,
isClassBindable);
+
foundExplicitBindableTag = foundExplicitBindableTag ||
BindableHelper.hasExplicitBindable(getterDef);
+
}
+
+ if (isClassBindable) {
+ //if we
'foundExplicitBindableTag' such as [Bindable(event='someEvent')], then nothing
else matters, even another [Bindable] tag is ignored (Flex)
+ isBindable =
!foundExplicitBindableTag;
+ }
}
writeNewline();
writeNewline();
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 b4a8271..51d45b5 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
@@ -29,6 +29,7 @@ import org.apache.royale.compiler.definitions.*;
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.definitions.references.IResolvedQualifiersReference;
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;
@@ -40,6 +41,7 @@ import
org.apache.royale.compiler.internal.codegen.js.jx.BinaryOperatorEmitter.D
import org.apache.royale.compiler.internal.definitions.AccessorDefinition;
import org.apache.royale.compiler.internal.definitions.FunctionDefinition;
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.royale.compiler.internal.definitions.VariableDefinition;
import org.apache.royale.compiler.internal.projects.RoyaleJSProject;
import org.apache.royale.compiler.internal.scopes.FunctionScope;
import org.apache.royale.compiler.internal.semantics.SemanticUtils;
@@ -48,6 +50,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.tree.as.IOperatorNode.OperatorType;
+import org.apache.royale.compiler.tree.mxml.IMXMLSingleDataBindingNode;
import org.apache.royale.compiler.utils.ASNodeUtils;
import java.util.ArrayList;
@@ -428,6 +431,13 @@ public class MemberAccessEmitter extends JSSubEmitter
implements
needClosure = !isStatic && parentNodeId !=
ASTNodeID.FunctionCallID &&
parentNodeId !=
ASTNodeID.MemberAccessExpressionID &&
parentNodeId !=
ASTNodeID.ArrayIndexExpressionID;
+
+ //If binding getterFunctions ever need
closures, this seems to be where it would be done (so far not needed, @todo
review and remove this when certain)
+ /*if (!needClosure && !isStatic && parentNodeId
== ASTNodeID.FunctionCallID) {
+ if (node.getParent().getParent()
instanceof IMXMLSingleDataBindingNode) {
+ needClosure = true;
+ }
+ }*/
if (needClosure
&& getEmitter().getDocEmitter()
instanceof JSRoyaleDocEmitter
@@ -458,6 +468,42 @@ public class MemberAccessEmitter extends JSSubEmitter
implements
{
dynamicAccessUnknownMembers =
fjsProject.config.getJsDynamicAccessUnknownMembers();
}
+ if (!dynamicAccessUnknownMembers) {
+ //for <fx:Object declarations in mxml, we need to do
this by default, because initialization values are set this way already, as are
destination bindings, for example.
+ IIdentifierNode checkNode = null;
+ if (leftNode instanceof
IIdentifierNode) {
+ //we might be dealing with the
direct child member access of an fx:Object
+ checkNode = (IIdentifierNode)
leftNode;
+ } else {
+ if (leftNode instanceof
MemberAccessExpressionNode) {
+ //if we are nested,
check upwards for topmost Identifier node and verify that it is mxml variable
of type Object, verifying that we are considered 'untyped' along the way
+
MemberAccessExpressionNode mae = (MemberAccessExpressionNode) leftNode;
+ while (mae != null) {
+ if
(mae.getRightOperandNode().resolve(getProject()) == null) {
+ if
(mae.getLeftOperandNode() instanceof IIdentifierNode) {
+
checkNode = (IIdentifierNode) mae.getLeftOperandNode();
+
break;
+ } else
if (mae.getLeftOperandNode() instanceof MemberAccessExpressionNode) {
+
mae = (MemberAccessExpressionNode) mae.getLeftOperandNode();
+ } else {
+
mae = null;
+ }
+ } else mae =
null;
+ }
+ }
+ }
+
+ if (checkNode != null &&
+
checkNode.resolve(getProject()) instanceof VariableDefinition) {
+ VariableDefinition varDef =
((VariableDefinition) (checkNode.resolve(getProject())));
+ if (varDef.isMXMLDeclared()) {
+ IDefinition type =
varDef.resolveType(getProject());
+ if (type instanceof
IClassDefinition &&
type.equals(getProject().getBuiltinType(IASLanguageConstants.BuiltinType.OBJECT)))
{
+
dynamicAccessUnknownMembers = true;
+ }
+ }
+ }
+ }
}
if (dynamicAccessUnknownMembers && rightNode instanceof
IIdentifierNode)
{
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 7cd6d24..47162b7 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
@@ -2956,7 +2956,7 @@ public class MXMLRoyaleEmitter extends MXMLEmitter
implements
if (!makingSimpleArray)
{
MXMLDescriptorSpecifier ps = getCurrentDescriptor("ps");
- if (ps.hasObject)
+ if (ps.hasObject || ps.parent == null) //('ps.parent == null' was
added to allow a top level fx:Object definition, they were not being output
without that)
{
emitInstance(node);
return;
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
index 4bb45a7..299bb41 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/as/codegen/BindableHelper.java
@@ -31,6 +31,8 @@ import org.apache.royale.abc.visitors.ITraitVisitor;
import org.apache.royale.abc.visitors.ITraitsVisitor;
import org.apache.royale.compiler.common.DependencyType;
import org.apache.royale.compiler.constants.IASLanguageConstants;
+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.metadata.IMetaTag;
import org.apache.royale.compiler.internal.abc.FunctionGeneratorHelper;
@@ -73,16 +75,115 @@ import static org.apache.royale.abc.ABCConstants.TRAIT_Var;
*/
public class BindableHelper
{
+
+ /**
+ * Check to see if a class definition is Bindable (for bindable code-gen)
+ * @param classDefinition the Class definition to check
+ * @return true if the definition has [Bindable]
+ */
+ public static boolean isClassCodeGenBindable(IClassDefinition
classDefinition) {
+ IMetaTag[] metaTags = classDefinition.getAllMetaTags();
+ boolean isBindable = false;
+ for (IMetaTag metaTag : metaTags)
+ {
+ if (isCodeGenBindable(metaTag)) {
+ //if there is a single [Bindable] tag, then others are
ignored, and the class is considered Bindable
+ isBindable = true;
+ break;
+ }
+ }
+ return isBindable;
+ }
+
/**
* Check to see if the metaTag is a codegen style [Bindable] tag (without
any event names specified)
- * @param metaTag
+ * @param memberDef the definition to check
+ * @param isClassBindable whether the containing class is [Bindable]
* @return true if the tag is [Bindable]
*/
+ public static boolean isCodeGenBindableMember(IDefinition memberDef,
boolean isClassBindable) {
+ boolean memberHasCodeGenBindable = false;
+ boolean memberHasExplicitBindable = false;
+ boolean resolved = false;
+ IMetaTag[] metaTags = memberDef.getAllMetaTags();
+ for (IMetaTag metaTag : metaTags)
+ {
+ if (!memberHasCodeGenBindable) {
+ memberHasCodeGenBindable = isCodeGenBindable(metaTag);
+ if (memberHasCodeGenBindable) continue;
+ }
+ if (!memberHasExplicitBindable) {
+ memberHasExplicitBindable = isExplicitBindable(metaTag);
+ }
+ }
+
+ if (isClassBindable) {
+ //if a getter/setter member has at least one explicit Bindable tag
, then no code-gen is applied, even if it is also has a 'codegen' [Bindable] tag
+ if (memberDef instanceof IAccessorDefinition) {
+ resolved = !memberHasExplicitBindable;
+ } else {
+ //if it is a variable member, extra [Bindable] tags, including
explicit Bindable(event='something') tags are ignored (at least for code-gen)
+ resolved = true; // @todo avoid checking at all in the above
loop for this case
+ }
+ } else {
+ //in this case other explicit Bindable tags are ignored, a
[Bindable] is sufficient @todo avoid checking for 'memberHasExplicitBindable'
in the above loop for this case
+ resolved = memberHasCodeGenBindable;
+ }
+ return resolved;
+ }
+
+ public static boolean hasExplicitBindable(IDefinition definition) {
+ boolean hasExplicitBindableTag = false;
+ if (definition != null) {
+ IMetaTag[] metaTags = definition.getAllMetaTags();
+ for (IMetaTag metaTag : metaTags)
+ {
+ if (isExplicitBindable(metaTag)) {
+ hasExplicitBindableTag = true;
+ break;
+ }
+ }
+ }
+ return hasExplicitBindableTag;
+ }
+
+
+ public static boolean hasCodegenBindable(IDefinition definition) {
+ boolean hasCodegenBindableTag = false;
+ if (definition != null) {
+ IMetaTag[] metaTags = definition.getAllMetaTags();
+ for (IMetaTag metaTag : metaTags)
+ {
+ if (isCodeGenBindable(metaTag)) {
+ hasCodegenBindableTag = true;
+ break;
+ }
+ }
+ }
+ return hasCodegenBindableTag;
+ }
+
+ /**
+ * Check to see if the metaTag is a codegen style [Bindable] tag (without
any event names specified)
+ * @param metaTag the MetaTag to check
+ * @return true if the MetaTag is [Bindable]
+ */
public static boolean isCodeGenBindable(IMetaTag metaTag) {
return metaTag != null
&& metaTag.getTagName().equals(BINDABLE)
&& metaTag.getAllAttributes().length == 0;
}
+ /**
+ * Check to see if the metaTag is an explicit [Bindable] tag (with some
attributes, such as event='someEvent' specified)
+ * @param metaTag the MetaTag to check
+ * @return true if the MetaTag is [Bindable('something')]
+ */
+ public static boolean isExplicitBindable(IMetaTag metaTag) {
+ return metaTag != null
+ && metaTag.getTagName().equals(BINDABLE)
+ && metaTag.getAllAttributes().length > 0;
+ }
+
/**
* A convenience method to get the next full node after all the Metadata
tags, for when
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 82cfa05..2f45c11 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
@@ -744,7 +744,7 @@ class ClassDirectiveProcessor extends DirectiveProcessor
if (!definition.isContingentNeeded(classScope.getProject()))
continue;
- assert (definition instanceof VariableDefinition) : "The code
generator only supports contigent variable definitions";
+ assert (definition instanceof VariableDefinition) : "The code
generator only supports contingent variable definitions";
final IDefinitionNode node = definition.getNode();
declareVariable((VariableNode) node,
(VariableDefinition)definition, definition.isStatic(),
@@ -779,46 +779,42 @@ class ClassDirectiveProcessor extends DirectiveProcessor
ICompilerProject project = classScope.getProject();
ASTUtil.processFunctionNode(func, project);
boolean isBindable = false;
-
if (funcDef instanceof AccessorDefinition)
{
- boolean isClassBindable = false;
- IMetaTag[] metaTags = getClassDefinition().getAllMetaTags();
- for (IMetaTag metaTag : metaTags)
- {
- if (BindableHelper.isCodeGenBindable(metaTag)) {
- isClassBindable = true;
- break;
- }
- }
+ boolean isClassBindable =
BindableHelper.isClassCodeGenBindable(getClassDefinition());
+
AccessorDefinition definitionWithBindable = null;
+ boolean foundExplicitBindableTag = false;
- metaTags = funcDef.getAllMetaTags();
- for (IMetaTag metaTag : metaTags)
- {
- if (BindableHelper.isCodeGenBindable(metaTag)) {
- isBindable = true;
- definitionWithBindable = (AccessorDefinition)funcDef;
- break;
- }
+ isBindable = BindableHelper.isCodeGenBindableMember(funcDef,
isClassBindable);
+ if (isBindable) {
+ definitionWithBindable = (AccessorDefinition) funcDef;
}
+ foundExplicitBindableTag =
BindableHelper.hasExplicitBindable(funcDef);
+
AccessorDefinition otherDef =
((AccessorDefinition)funcDef).resolveCorrespondingAccessor(classScope.getProject());
- if (!isBindable)
+ if (!isBindable && !foundExplicitBindableTag)
{
if (otherDef != null &&
otherDef.getContainingScope().equals(funcDef.getContainingScope()))
{
- metaTags = otherDef.getAllMetaTags();
- for (IMetaTag metaTag : metaTags)
- {
- if (BindableHelper.isCodeGenBindable(metaTag)) {
- isBindable = true;
- definitionWithBindable = otherDef;
- break;
- }
+ isBindable =
BindableHelper.isCodeGenBindableMember(otherDef, isClassBindable);
+ if (isBindable) {
+ definitionWithBindable = otherDef;
+ }
+ foundExplicitBindableTag =
BindableHelper.hasExplicitBindable(otherDef);
+ //if a) class is Bindable, and b)there is a [Bindable]
tag, and c) there is also a [Bindable(eventName)] tag
+ //then we can retain the [Bindable] codegen and reset
foundExplicitBinding to false (assumption, check in flex)
+ if (isClassBindable && isBindable &&
foundExplicitBindableTag) {
+ foundExplicitBindableTag = false; //we will ignore it
and keep codegen as well
}
}
}
+ if (isBindable && otherDef == null) {
+ //no other definition
+ isBindable = false;
+ //warning if explicit [Bindable] ?
+ }
if (isBindable
&& otherDef instanceof ISetterDefinition
@@ -828,24 +824,32 @@ class ClassDirectiveProcessor extends DirectiveProcessor
classScope.addProblem(new
BindableGetterCodeGenProblem((IGetterDefinition) funcDef));
}
if (isClassBindable) {
+ //add a warning if redundant local 'codegen' [Bindable] tag
+ if (BindableHelper.hasCodegenBindable(definitionWithBindable))
{
+ classScope.addProblem(new RedundantBindableTagProblem(
+
BindableHelper.getProblemReportingNode(definitionWithBindable)
+ ));
+ }
if (isBindable) {
- if (definitionWithBindable == funcDef) { //if we don't do
this, we will end up with two reports
- classScope.addProblem(new RedundantBindableTagProblem(
-
BindableHelper.getProblemReportingNode(definitionWithBindable)
- ));
- }
- } else {
- isBindable = true;
+ if (!foundExplicitBindableTag &&
BindableHelper.hasExplicitBindable(otherDef)) foundExplicitBindableTag = true;
+ }
+ if (foundExplicitBindableTag) {
+ //logic:
+ //when class is [Bindable],
+ //if either getter/setter member has at least one explicit
Bindable tag (Bindable(event='something'))
+ //then no code-gen is applied,
+ //even if one of them also has a local 'codegen'
[Bindable] tag
+ isBindable = false;
}
}
}
-
+
functionSemanticChecks(func);
Name funcName = funcDef.getMName(classScope.getProject());
Name bindableName = null;
boolean wasOverride = false;
- //we only mutate the setter definitions, leave getters as-is
+ //from here on we are only interested in the setter definitions, leave
getters as-is
isBindable = isBindable && funcDef instanceof ISetterDefinition;
if (isBindable)
{
@@ -1471,7 +1475,7 @@ class ClassDirectiveProcessor extends DirectiveProcessor
this.cinitInsns.addAll(cgResult);
else
this.iinitInsns.addAll(cgResult);
- }
+ }
}
/**
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
index 250e351..b4c6614 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/codegen/databinding/BindingCodeGenUtils.java
@@ -37,14 +37,16 @@ import org.apache.royale.abc.visitors.IABCVisitor;
import org.apache.royale.compiler.constants.IASLanguageConstants;
import org.apache.royale.compiler.definitions.INamespaceDefinition;
import org.apache.royale.compiler.internal.abc.FunctionGeneratorHelper;
+import org.apache.royale.compiler.internal.as.codegen.CmcEmitter;
import org.apache.royale.compiler.internal.as.codegen.CodeGeneratorManager;
import org.apache.royale.compiler.internal.as.codegen.LexicalScope;
import org.apache.royale.compiler.internal.definitions.NamespaceDefinition;
import org.apache.royale.compiler.internal.projects.RoyaleProject;
import org.apache.royale.compiler.internal.scopes.ASScope;
-import org.apache.royale.compiler.internal.tree.as.LiteralNode;
+import org.apache.royale.compiler.internal.tree.as.*;
import org.apache.royale.compiler.mxml.IMXMLTypeConstants;
import org.apache.royale.compiler.projects.ICompilerProject;
+import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.IExpressionNode;
/**
@@ -376,11 +378,12 @@ public class BindingCodeGenUtils
String functionName,
List<String> eventNames,
List<BindingInfo> bindingInfo,
- IExpressionNode[] params)
+ IExpressionNode[] params,
+ LexicalScope lexicalScope)
{
log(insns, "enter makeFunctionWatchercg");
-
+
Name watcherClassName = project.getFunctionReturnWatcherClassName();
insns.addInstruction(OP_findpropstrict, watcherClassName);
// stack: mx.binding.FunctionReturnWatcher
@@ -404,7 +407,7 @@ public class BindingCodeGenUtils
// stack: this, functionName, watcher class
// arg3: parameterFunction
- makeParameterFunction(emitter, insns, params);
+ makeParameterFunction(emitter, insns, params, lexicalScope);
// arg4: events
boolean isStyle = makeEventNameArray(insns, eventNames);
@@ -450,7 +453,7 @@ public class BindingCodeGenUtils
// version 2: just throw
- public static void makeParameterFunction(IABCVisitor emitter,
InstructionList ret, IExpressionNode[] params)
+ public static void makeParameterFunction(IABCVisitor emitter,
InstructionList ret, IExpressionNode[] params, LexicalScope lexicalScope)
{
//----------- step 1: build up a method info for the function
@@ -471,26 +474,53 @@ public class BindingCodeGenUtils
parameterFunctionBody.addInstruction(OP_getlocal0);
parameterFunctionBody.addInstruction(OP_pushscope);
-
- if (params.length == 1 && params[0] instanceof LiteralNode)
- {
- parameterFunctionBody.addInstruction(OP_pushstring,
((LiteralNode)params[0]).getValue());
-
- parameterFunctionBody.addInstruction(OP_newarray, 1);
- parameterFunctionBody.addInstruction(OP_returnvalue);
- }
- else
- {
- parameterFunctionBody.addInstruction(OP_findpropstrict,
IMXMLTypeConstants.NAME_ARGUMENTERROR);
-
- // Make a new ArugmentError with correct ID
- parameterFunctionBody.addInstruction(OP_pushstring, "unimp param
func");
- parameterFunctionBody.pushNumericConstant(1069);
- parameterFunctionBody.addInstruction(OP_constructprop,
- new Object[] { IMXMLTypeConstants.NAME_ARGUMENTERROR, 2
});
- // stack : ArgumentError
-
- parameterFunctionBody.addInstruction(OP_throw);
+
+ if (params.length == 0) {
+ //it is a function call with no params
+ parameterFunctionBody.addInstruction(OP_newarray, 0);
+ parameterFunctionBody.addInstruction(OP_returnvalue);
+ } else {
+
+ //create a temporary ArrayLiteralNode
+ ArrayLiteralNode arrayLit = new ArrayLiteralNode();
+
+ for (IASNode param: params) {
+ ContainerNode parent = (ContainerNode)param.getParent();
+ //make the array literal think it has the param as a child
+ arrayLit.getContentsNode().addItem((NodeBase)param);
+ //(tricky) now reset the parent of the param, avoid errors
with ASScope access during traversal,
+ //we only really want the downward traversal from the
ArrayLiteralNode as the root, we don't want any sense
+ //that it is *actually* a parent, because it is not ASScope
aware.
+ ((NodeBase) param).setParent(parent);
+ if (arrayLit.getSourcePath()==null) {
+ //give the synthetic node a location to avoid an error
elsewhere
+ //setting the source path here will prevent an assertion
failure in a future call to SemanticUtils.getFileName(iNode) if
+ //asserts are enabled for the compiler runtime (at the
time of writing, ant was and maven was not)
+ arrayLit.setSourceLocation(param);
+ } else {
+ arrayLit.endAfter(param);
+ }
+ }
+
+ //generate the instruction list for the Arrayliteral
+ InstructionList list =
lexicalScope.getGenerator().generateInstructions(arrayLit,
CmcEmitter.__array_literal_NT, lexicalScope);
+ if (list != null && !list.isEmpty()) {
+ //output the array literal and return it
+ parameterFunctionBody.addAll(list);
+ parameterFunctionBody.addInstruction(OP_returnvalue);
+ } else {
+ //sanity check, this is the original legacy fail approach
@todo review this, hopefully it can be removed if it never happens in practice
+ parameterFunctionBody.addInstruction(OP_findpropstrict,
IMXMLTypeConstants.NAME_ARGUMENTERROR);
+
+ // Make a new ArugmentError with correct ID
+ parameterFunctionBody.addInstruction(OP_pushstring, "unimp
param func");
+ parameterFunctionBody.pushNumericConstant(1069);
+ parameterFunctionBody.addInstruction(OP_constructprop,
+ new Object[] { IMXMLTypeConstants.NAME_ARGUMENTERROR,
2 });
+ // stack : ArgumentError
+
+ parameterFunctionBody.addInstruction(OP_throw);
+ }
}
// now generate the function
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 7ea4cc4..a5a2fe6 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
@@ -288,7 +288,7 @@ public class MXMLBindingDirectiveHelper
ret.addInstruction(OP_pushstring,
functionWatcherInfo.getFunctionName());
InstructionList paramFunction = new InstructionList();
- BindingCodeGenUtils.makeParameterFunction(emitter, paramFunction,
functionWatcherInfo.params);
+ BindingCodeGenUtils.makeParameterFunction(emitter, paramFunction,
functionWatcherInfo.params, host.getInstanceScope());
ret.addAll(paramFunction);
outputEventNames(ret, functionWatcherInfo.getEventNames());
outputBindings(ret, functionWatcherInfo.getBindings());
@@ -916,7 +916,8 @@ public class MXMLBindingDirectiveHelper
functionWatcherInfo.getFunctionName(),
functionWatcherInfo.getEventNames(),
functionWatcherInfo.getBindings(),
- functionWatcherInfo.params);
+ functionWatcherInfo.params,
+ host.getInstanceScope());
}
else if ((type == WatcherType.STATIC_PROPERTY) || (type ==
WatcherType.PROPERTY))
{
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 41da6b2..c822686 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
@@ -1348,17 +1348,23 @@ public abstract class DefinitionBase implements
IDocumentableDefinition, IDefini
boolean bindable = isBindableLocally();
if (!bindable)
{
- IDefinition containing = getParent();
- if (containing instanceof IClassDefinition
- && this.getNamespaceReference() ==
NamespaceDefinition.getPublicNamespaceDefinition())
- {
- DefinitionBase containingBase = (DefinitionBase)containing;
- bindable = containingBase.isBindableLocally();
- }
+ bindable = isClassBindable();
}
return bindable;
}
+ public boolean isClassBindable() {
+ boolean classBindable = false;
+ IDefinition containing = getParent();
+ if (containing instanceof IClassDefinition
+ && this.getNamespaceReference() ==
NamespaceDefinition.getPublicNamespaceDefinition())
+ {
+ DefinitionBase containingBase = (DefinitionBase)containing;
+ classBindable = containingBase.isBindableLocally();
+ }
+ return classBindable;
+ }
+
/**
* @return a collection of Bindable event names, if any were specified in
* the metadata, as well as any inherited from the class
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 a465894..2f8a1e9 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
@@ -136,6 +136,15 @@ public class VariableDefinition extends DefinitionBase
implements IVariableDefin
return dt;
}
+ private boolean mxmlDeclared = false;
+ public void setMxmlDeclared(){
+ mxmlDeclared = true;
+ }
+
+ public boolean isMXMLDeclared() {
+ return mxmlDeclared;
+ }
+
@Override
public IVariableNode getNode()
{
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
index a2af339..74b308d 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/parsing/mxml/MXMLScopeBuilder.java
@@ -772,6 +772,7 @@ public class MXMLScopeBuilder
variableDefinition.setTypeReference(typeRef);
variableDefinition.setNameLocation(idAttribute.getValueStart(),
idAttribute.getValueEnd());
variableDefinition.setBindable();
+ variableDefinition.setMxmlDeclared();
currentClassScope.addDefinition(variableDefinition);
}
diff --git
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
index 8deb160..23c8ed4 100644
---
a/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
+++
b/compiler/src/main/java/org/apache/royale/compiler/internal/tree/as/VariableNode.java
@@ -27,6 +27,7 @@ import org.apache.royale.compiler.common.ASImportTarget;
import org.apache.royale.compiler.common.IImportTarget;
import org.apache.royale.compiler.definitions.IDefinition;
import
org.apache.royale.compiler.definitions.IVariableDefinition.VariableClassification;
+import org.apache.royale.compiler.internal.definitions.DefinitionBase;
import org.apache.royale.compiler.tree.ASTNodeID;
import org.apache.royale.compiler.tree.as.IASNode;
import org.apache.royale.compiler.tree.as.ICommonClassNode;
@@ -76,14 +77,23 @@ public class VariableNode extends BaseVariableNode
{
ASTNodeID nodeID = ASTNodeID.VariableID;
- IDefinition varDef = this.getDefinition();
+ DefinitionBase varDef = this.getDefinition();
if (varDef != null && varDef.isBindable())
{
// Bindable vars with a user-specified event class work the same
as normal variables
// the user is responsible for dispatching the event.
- List<String> eventNames = varDef.getBindableEventNames();
- if (eventNames.size() == 0)
+
+ //note: the above statement was inconsistent with Flex if the
class itself is also marked [Bindable]
+ //in that case, binding is related to both codegen events and the
specified event.
+ if (varDef.isClassBindable()) {
+ //we know that isBindable() must be because of the class
[Bindable], regardless of any specific eventNames
nodeID = ASTNodeID.BindableVariableID;
+ } else {
+ //as original, only consider to be [Bindable] if eventNames is
empty:
+ List<String> eventNames = varDef.getBindableEventNames();
+ if (eventNames.size() == 0)
+ nodeID = ASTNodeID.BindableVariableID;
+ }
}
return nodeID;