This is an automated email from the ASF dual-hosted git repository. joshtynjala pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
commit 6228202d9ab2d8d1b216c0372fdc272661d6ee2c Author: Josh Tynjala <joshtynj...@apache.org> AuthorDate: Mon Nov 20 13:23:28 2023 -0800 MemberAccessEmitter: extract some of the branches into separate methods --- .../codegen/js/jx/MemberAccessEmitter.java | 606 +++++++++++---------- 1 file changed, 330 insertions(+), 276 deletions(-) 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 60bbe8ce6..80d5ab4b2 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 @@ -67,23 +67,15 @@ public class MemberAccessEmitter extends JSSubEmitter implements if (ASNodeUtils.hasParenOpen(node)) write(ASEmitterTokens.PAREN_OPEN); - IExpressionNode leftNode = node.getLeftOperandNode(); - IASNode rightNode = node.getRightOperandNode(); - JSRoyaleEmitter fjs = (JSRoyaleEmitter)getEmitter(); if (fjs.isDateProperty(node, false)) { - writeLeftSide(node, leftNode, rightNode); - String rightName = ((IIdentifierNode)rightNode).getName(); - DatePropertiesGetters propGetter = DatePropertiesGetters.valueOf(rightName.toUpperCase()); - write(ASEmitterTokens.MEMBER_ACCESS); - write(propGetter.getFunctionName()); - write(ASEmitterTokens.PAREN_OPEN); - write(ASEmitterTokens.PAREN_CLOSE); - if (ASNodeUtils.hasParenClose(node)) - write(ASEmitterTokens.PAREN_CLOSE); + writeDateGetterMemberAccess(node); return; } + + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); IDefinition def = node.resolve(getProject()); //extra check to cope with e4x member access identifier nodes that resolve //to instance member function definitions @@ -125,135 +117,7 @@ public class MemberAccessEmitter extends JSSubEmitter implements !((rightNode.getNodeID() == ASTNodeID.ArrayIndexExpressionID) && (((DynamicAccessNode)rightNode).getLeftOperandNode().getNodeID() == ASTNodeID.Op_AtID)); if (descendant || child) { - writeLeftSide(node, leftNode, rightNode); - if (descendant) - write(".descendants("); - if (child) - write(".child("); - String closeMethodCall = "')"; - String s = ""; - boolean isNamespaceAccessNode = rightNode instanceof INamespaceAccessExpressionNode; - ArrayList<IDefinition> usedNamespaceDefs = null; - if (!isNamespaceAccessNode) { - //check for open namespaces - NamespaceDefinition.INamespaceDirective item = ((NodeBase) node).getASScope().getFirstNamespaceDirective(); - while(item != null) { - if (item instanceof NamespaceDefinition.IUseNamespaceDirective) { - - INamespaceDefinition itemDef = ((NamespaceDefinition.IUseNamespaceDirective) item).resolveNamespaceReference(getProject()); - if (itemDef == null) { - //@todo - either resolve this or make it an actual Warning. - // System.out.println("Ambiguous 'use namespace "+((NamespaceDefinition.IUseNamespaceDirective) item).getBaseName()+ "', probably conflicts with local var name:"+node.getSourcePath()+":"+node.getLine()+":"+node.getColumn()); - IDefinition lookupDef = ((NodeBase) node).getASScope().findProperty(getProject(), ((NamespaceDefinition.IUseNamespaceDirective) item).getBaseName(), DependencyType.NAMESPACE); - if (lookupDef instanceof IVariableDefinition) { - //it seems that swf ignores this too...adding it in creates a different result - /*if (usedNamespaceDefs == null) { - usedNamespaceDefs = new ArrayList<IDefinition>(); - } - - if (!usedNamespaceDefs.contains(lookupDef)) { - usedNamespaceDefs.add(lookupDef); - }*/ - } - - } else { - if (usedNamespaceDefs == null) { - usedNamespaceDefs = new ArrayList<IDefinition>(); - } - if (!usedNamespaceDefs.contains(itemDef)) usedNamespaceDefs.add(itemDef); - } - } - item = item.getNext(); - } - } - - if (isNamespaceAccessNode || usedNamespaceDefs != null) { - if (isNamespaceAccessNode) { - NamespaceIdentifierNode namespaceIdentifierNode = (NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode(); - IDefinition nsDef = namespaceIdentifierNode.resolve(getProject()); - if (nsDef instanceof INamespaceDefinition - && ((INamespaceDefinition)nsDef).getNamespaceClassification().equals(INamespaceDefinition.NamespaceClassification.LANGUAGE)) { - //deal with built-ins - String name = ((NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode()).getName(); - if (name.equals(INamespaceConstants.ANY)) { - //let the internal support within 'QName' class deal with it - write("new QName(null,'"); - //only stringify the right node at the next step (it is the localName part) - rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); - closeMethodCall = "'))"; - } else if (name.equals(IASKeywordConstants.PUBLIC) - || name.equals(IASKeywordConstants.PROTECTED)) { - //@todo check this, but both public and protected appear to have the effect of skipping the namespace part in swf, so just use default namespace - write("/* as3 " + name + " */ '"); - //skip the namespace to just output the name - rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); - } else { - //this is an unlikely condition, but do something that should give same results as swf... - //private, internal namespaces used in an XML context (I don't think this makes sense, but is possible to do in code) - //@todo check this, but it seems like it should never match anything in a valid XML query - write("new QName('"); - //provide an 'unlikely' 'uri': - write("_as3Lang_" + fjs.stringifyNode(namespaceIdentifierNode)); - write(s + "','"); - //only stringify the right node at the next step (it is the localName part) - rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); - closeMethodCall = "'))"; - } - } else { - write("new QName("); - s = fjs.stringifyNode(namespaceIdentifierNode); - write(s + ",'"); - //only stringify the right node at the next step (it is the localName part) - rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); - closeMethodCall = "'))"; - } - } else { - //use a special MultiQName compiler support method - //to simulate a MultiName for the used namespaces (which includes 'no namespace') - write("XML.multiQName(["); - int count = 0; - for (IDefinition nsDef:usedNamespaceDefs) { - if (count > 0) write(","); - if (nsDef instanceof INamespaceDefinition) { - write("'"+((INamespaceDefinition)nsDef).getURI()+"'"); - } else { - String varName = getEmitter().stringifyNode(((IVariableDefinition) nsDef).getVariableNode().getNameExpressionNode()); - write(varName); - } - count++; - } - write("]"); - write(", '"); - closeMethodCall = "'))"; - } - } else if (getModel().defaultXMLNamespaceActive - && ((MemberAccessExpressionNode) node).getASScope() instanceof FunctionScope - && getModel().getDefaultXMLNamespace((FunctionScope)((MemberAccessExpressionNode) node).getASScope()) != null) { - //new QName('contextualDefaultNameSpace','originalValueHere') - write("new QName("); - getEmitter().getWalker().walk(getModel().getDefaultXMLNamespace((FunctionScope)((MemberAccessExpressionNode) node).getASScope())); - write(",'"); - closeMethodCall = "'))"; - } else { - //regular string value - write("'"); //normal string name for child - } - - - s = fjs.stringifyNode(rightNode); - int dot = s.indexOf('.'); - if (dot != -1) { - String name = s.substring(0, dot); - String afterDot = s.substring(dot); - write(name); - write(closeMethodCall); - write(afterDot); - } else { - write(s); - write(closeMethodCall); - } - if (ASNodeUtils.hasParenClose(node)) - write(ASEmitterTokens.PAREN_CLOSE); + writeXmlDescendantOrChild(node, descendant, child); return; } } @@ -264,36 +128,7 @@ public class MemberAccessEmitter extends JSSubEmitter implements rightNode.getNodeID() != ASTNodeID.Op_AtID; if (child) { - writeLeftSide(node, leftNode, rightNode); - if (child) - write(".getProperty("); - String s = fjs.stringifyNode(rightNode); - int dot = s.indexOf('.'); - if (dot != -1) - { - String name = s.substring(0, dot); - String afterDot = s.substring(dot); - write("'"); - write(name); - write("'"); - write(")"); - write(afterDot); - } - else - { - if ((s.startsWith("'") && s.endsWith("'")) || (s.startsWith("\"") && s.endsWith("\""))) - { - // already quoted - write(s); - } - else - { - write("'"); - write(s); - write("'"); - } - write(")"); - } + writeProxyGetProperty(node); return; } } @@ -302,30 +137,7 @@ public class MemberAccessEmitter extends JSSubEmitter implements // if you define a local variable with the same URI as a // namespace that defines a namespaced property // it doesn't resolve above so we handle it here - NamespaceAccessExpressionNode naen = (NamespaceAccessExpressionNode)rightNode; - IDefinition d = naen.getLeftOperandNode().resolve(getProject()); - IdentifierNode r = (IdentifierNode)(naen.getRightOperandNode()); - // output bracket access with QName - writeLeftSide(node, leftNode, rightNode); - //exception: variable member access needs to have literal output, because there is no guarantee that string access will work in release mode after renaming - if (((NamespaceAccessExpressionNode) rightNode).resolve(getProject()) instanceof IVariableDefinition) { - write(JSRoyaleEmitter.formatNamespacedProperty(d.toString(), r.getName(),true)); - } else { - write(ASEmitterTokens.SQUARE_OPEN); - write(ASEmitterTokens.NEW); - write(ASEmitterTokens.SPACE); - write(IASLanguageConstants.QName); - write(ASEmitterTokens.PAREN_OPEN); - write(fjs.formatQualifiedName(d.getQualifiedName())); - write(ASEmitterTokens.COMMA); - write(ASEmitterTokens.SPACE); - write(ASEmitterTokens.SINGLE_QUOTE); - write(r.getName()); - write(ASEmitterTokens.SINGLE_QUOTE); - write(ASEmitterTokens.PAREN_CLOSE); - write(".objectAccessFormat()"); - write(ASEmitterTokens.SQUARE_CLOSE); - } + writeNullDefinitionRightSideNamespaceAccessExpressionNode(node); return; } } @@ -341,88 +153,18 @@ public class MemberAccessEmitter extends JSSubEmitter implements { if (def.getBaseName().equals("removeAt")) { - writeLeftSide(node, leftNode, rightNode); - write(".splice"); + writeArrayRemoveAt(node); return; } else if (def.getBaseName().equals("insertAt")) { - writeLeftSide(node, leftNode, rightNode); - write(".splice"); + writeArrayInsertAt(node); return; } } else if (rightNode instanceof NamespaceAccessExpressionNode) { - boolean isStatic = false; - if (def != null && def.isStatic()) - isStatic = true; - boolean needClosure = false; - if (def instanceof FunctionDefinition && (!(def instanceof AccessorDefinition)) - && !def.getBaseName().equals("constructor")) // don't wrap references to obj.constructor - { - IASNode parentNode = node.getParent(); - if (parentNode != null) - { - ASTNodeID parentNodeId = parentNode.getNodeID(); - // we need a closure if this MAE is the top-level in a chain - // of MAE and not in a function call. - needClosure = !isStatic && parentNodeId != ASTNodeID.FunctionCallID && - parentNodeId != ASTNodeID.MemberAccessExpressionID && - parentNodeId != ASTNodeID.ArrayIndexExpressionID; - } - } - - if (needClosure - && getEmitter().getDocEmitter() instanceof JSRoyaleDocEmitter - && ((JSRoyaleDocEmitter)getEmitter().getDocEmitter()).getSuppressClosure()) - needClosure = false; - if (needClosure) - getEmitter().emitClosureStart(); - - NamespaceAccessExpressionNode naen = (NamespaceAccessExpressionNode)rightNode; - IDefinition d = naen.getLeftOperandNode().resolve(getProject()); - IdentifierNode r = (IdentifierNode)(naen.getRightOperandNode()); - // output bracket access with QName - writeLeftSide(node, leftNode, rightNode); - if (!d.getBaseName().equals(ASEmitterTokens.PRIVATE.getToken())) - { - //exception: variable member access needs to have literal output, because there is no guarantee that string access will work in release mode after renaming - if (naen.resolve(getProject()) instanceof IVariableDefinition) { - write(JSRoyaleEmitter.formatNamespacedProperty(d.toString(), r.getName(),true)); - } else { - write(ASEmitterTokens.SQUARE_OPEN); - write(ASEmitterTokens.NEW); - write(ASEmitterTokens.SPACE); - write(IASLanguageConstants.QName); - write(ASEmitterTokens.PAREN_OPEN); - write(fjs.formatQualifiedName(d.getQualifiedName())); - write(ASEmitterTokens.COMMA); - write(ASEmitterTokens.SPACE); - write(ASEmitterTokens.SINGLE_QUOTE); - write(r.getName()); - write(ASEmitterTokens.SINGLE_QUOTE); - write(ASEmitterTokens.PAREN_CLOSE); - write(".objectAccessFormat()"); - write(ASEmitterTokens.SQUARE_CLOSE); - } - } - else - { - write(node.getOperator().getOperatorText()); - write(r.getName()); - } - - if (needClosure) - { - write(ASEmitterTokens.COMMA); - write(ASEmitterTokens.SPACE); - if (leftNode.getNodeID() == ASTNodeID.SuperID) - write(ASEmitterTokens.THIS); - else - writeLeftSide(node, leftNode, rightNode); - getEmitter().emitClosureEnd(leftNode, def); - } + writeRightSideNamespaceAccessExpressionNode(node, def); return; } boolean isCustomNamespace = false; @@ -552,14 +294,7 @@ public class MemberAccessEmitter extends JSSubEmitter implements } if (emitDynamicAccess) { - IIdentifierNode identifierNode = (IIdentifierNode) node.getRightOperandNode(); - startMapping(node, rightNode); - write(ASEmitterTokens.SQUARE_OPEN); - write(ASEmitterTokens.DOUBLE_QUOTE); - write(identifierNode.getName()); - write(ASEmitterTokens.DOUBLE_QUOTE); - write(ASEmitterTokens.SQUARE_CLOSE); - endMapping(node); + writeDynamicAccessForIdentifier(node); } else { @@ -588,6 +323,325 @@ public class MemberAccessEmitter extends JSSubEmitter implements write(ASEmitterTokens.PAREN_CLOSE); } + private void writeDateGetterMemberAccess(IMemberAccessExpressionNode node) + { + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + writeLeftSide(node, leftNode, rightNode); + String rightName = ((IIdentifierNode)rightNode).getName(); + DatePropertiesGetters propGetter = DatePropertiesGetters.valueOf(rightName.toUpperCase()); + write(ASEmitterTokens.MEMBER_ACCESS); + write(propGetter.getFunctionName()); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.PAREN_CLOSE); + if (ASNodeUtils.hasParenClose(node)) + write(ASEmitterTokens.PAREN_CLOSE); + } + + private void writeArrayRemoveAt(IMemberAccessExpressionNode node) { + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + writeLeftSide(node, leftNode, rightNode); + // removeAt() doesn't exist in JS, but we can replace with splice() + // the parameters are rewritten as part of emitting the function call + write(".splice"); + } + + private void writeArrayInsertAt(IMemberAccessExpressionNode node) { + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + writeLeftSide(node, leftNode, rightNode); + // insertAt() doesn't exist in JS, but we can replace with splice() + // the parameters are rewritten as part of emitting the function call + write(".splice"); + } + + private void writeDynamicAccessForIdentifier(IMemberAccessExpressionNode node) { + IIdentifierNode identifierNode = (IIdentifierNode) node.getRightOperandNode(); + startMapping(node, identifierNode); + write(ASEmitterTokens.SQUARE_OPEN); + write(ASEmitterTokens.DOUBLE_QUOTE); + write(identifierNode.getName()); + write(ASEmitterTokens.DOUBLE_QUOTE); + write(ASEmitterTokens.SQUARE_CLOSE); + endMapping(node); + } + + private void writeProxyGetProperty(IMemberAccessExpressionNode node) { + JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + writeLeftSide(node, leftNode, rightNode); + write(".getProperty("); + String s = fjs.stringifyNode(rightNode); + int dot = s.indexOf('.'); + if (dot != -1) + { + String name = s.substring(0, dot); + String afterDot = s.substring(dot); + write("'"); + write(name); + write("'"); + write(")"); + write(afterDot); + } + else + { + if ((s.startsWith("'") && s.endsWith("'")) || (s.startsWith("\"") && s.endsWith("\""))) + { + // already quoted + write(s); + } + else + { + write("'"); + write(s); + write("'"); + } + write(")"); + } + } + + private void writeNullDefinitionRightSideNamespaceAccessExpressionNode(IMemberAccessExpressionNode node) { + JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + NamespaceAccessExpressionNode naen = (NamespaceAccessExpressionNode)rightNode; + IDefinition d = naen.getLeftOperandNode().resolve(getProject()); + IdentifierNode r = (IdentifierNode)(naen.getRightOperandNode()); + // output bracket access with QName + writeLeftSide(node, leftNode, rightNode); + //exception: variable member access needs to have literal output, because there is no guarantee that string access will work in release mode after renaming + if (((NamespaceAccessExpressionNode) rightNode).resolve(getProject()) instanceof IVariableDefinition) { + write(JSRoyaleEmitter.formatNamespacedProperty(d.toString(), r.getName(),true)); + } else { + write(ASEmitterTokens.SQUARE_OPEN); + write(ASEmitterTokens.NEW); + write(ASEmitterTokens.SPACE); + write(IASLanguageConstants.QName); + write(ASEmitterTokens.PAREN_OPEN); + write(fjs.formatQualifiedName(d.getQualifiedName())); + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.SINGLE_QUOTE); + write(r.getName()); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + write(".objectAccessFormat()"); + write(ASEmitterTokens.SQUARE_CLOSE); + } + } + + private void writeRightSideNamespaceAccessExpressionNode(IMemberAccessExpressionNode node, IDefinition def) { + JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + boolean isStatic = false; + if (def != null && def.isStatic()) + isStatic = true; + boolean needClosure = false; + if (def instanceof FunctionDefinition && (!(def instanceof AccessorDefinition)) + && !def.getBaseName().equals("constructor")) // don't wrap references to obj.constructor + { + IASNode parentNode = node.getParent(); + if (parentNode != null) + { + ASTNodeID parentNodeId = parentNode.getNodeID(); + // we need a closure if this MAE is the top-level in a chain + // of MAE and not in a function call. + needClosure = !isStatic && parentNodeId != ASTNodeID.FunctionCallID && + parentNodeId != ASTNodeID.MemberAccessExpressionID && + parentNodeId != ASTNodeID.ArrayIndexExpressionID; + } + } + + if (needClosure + && getEmitter().getDocEmitter() instanceof JSRoyaleDocEmitter + && ((JSRoyaleDocEmitter)getEmitter().getDocEmitter()).getSuppressClosure()) + needClosure = false; + if (needClosure) + getEmitter().emitClosureStart(); + + NamespaceAccessExpressionNode naen = (NamespaceAccessExpressionNode)rightNode; + IDefinition d = naen.getLeftOperandNode().resolve(getProject()); + IdentifierNode r = (IdentifierNode)(naen.getRightOperandNode()); + // output bracket access with QName + writeLeftSide(node, leftNode, rightNode); + if (!d.getBaseName().equals(ASEmitterTokens.PRIVATE.getToken())) + { + //exception: variable member access needs to have literal output, because there is no guarantee that string access will work in release mode after renaming + if (naen.resolve(getProject()) instanceof IVariableDefinition) { + write(JSRoyaleEmitter.formatNamespacedProperty(d.toString(), r.getName(),true)); + } else { + write(ASEmitterTokens.SQUARE_OPEN); + write(ASEmitterTokens.NEW); + write(ASEmitterTokens.SPACE); + write(IASLanguageConstants.QName); + write(ASEmitterTokens.PAREN_OPEN); + write(fjs.formatQualifiedName(d.getQualifiedName())); + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.SINGLE_QUOTE); + write(r.getName()); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + write(".objectAccessFormat()"); + write(ASEmitterTokens.SQUARE_CLOSE); + } + } + else + { + write(node.getOperator().getOperatorText()); + write(r.getName()); + } + + if (needClosure) + { + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + if (leftNode.getNodeID() == ASTNodeID.SuperID) + write(ASEmitterTokens.THIS); + else + writeLeftSide(node, leftNode, rightNode); + getEmitter().emitClosureEnd(leftNode, def); + } + } + + private void writeXmlDescendantOrChild(IMemberAccessExpressionNode node, boolean descendant, boolean child) { + JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); + IExpressionNode leftNode = node.getLeftOperandNode(); + IExpressionNode rightNode = node.getRightOperandNode(); + writeLeftSide(node, leftNode, rightNode); + if (descendant) + write(".descendants("); + if (child) + write(".child("); + String closeMethodCall = "')"; + String s = ""; + boolean isNamespaceAccessNode = rightNode instanceof INamespaceAccessExpressionNode; + ArrayList<IDefinition> usedNamespaceDefs = null; + if (!isNamespaceAccessNode) { + //check for open namespaces + NamespaceDefinition.INamespaceDirective item = ((NodeBase) node).getASScope().getFirstNamespaceDirective(); + while(item != null) { + if (item instanceof NamespaceDefinition.IUseNamespaceDirective) { + + INamespaceDefinition itemDef = ((NamespaceDefinition.IUseNamespaceDirective) item).resolveNamespaceReference(getProject()); + if (itemDef == null) { + //@todo - either resolve this or make it an actual Warning. + // System.out.println("Ambiguous 'use namespace "+((NamespaceDefinition.IUseNamespaceDirective) item).getBaseName()+ "', probably conflicts with local var name:"+node.getSourcePath()+":"+node.getLine()+":"+node.getColumn()); + IDefinition lookupDef = ((NodeBase) node).getASScope().findProperty(getProject(), ((NamespaceDefinition.IUseNamespaceDirective) item).getBaseName(), DependencyType.NAMESPACE); + if (lookupDef instanceof IVariableDefinition) { + //it seems that swf ignores this too...adding it in creates a different result + /*if (usedNamespaceDefs == null) { + usedNamespaceDefs = new ArrayList<IDefinition>(); + } + + if (!usedNamespaceDefs.contains(lookupDef)) { + usedNamespaceDefs.add(lookupDef); + }*/ + } + + } else { + if (usedNamespaceDefs == null) { + usedNamespaceDefs = new ArrayList<IDefinition>(); + } + if (!usedNamespaceDefs.contains(itemDef)) usedNamespaceDefs.add(itemDef); + } + } + item = item.getNext(); + } + } + + if (isNamespaceAccessNode || usedNamespaceDefs != null) { + if (isNamespaceAccessNode) { + NamespaceIdentifierNode namespaceIdentifierNode = (NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode(); + IDefinition nsDef = namespaceIdentifierNode.resolve(getProject()); + if (nsDef instanceof INamespaceDefinition + && ((INamespaceDefinition)nsDef).getNamespaceClassification().equals(INamespaceDefinition.NamespaceClassification.LANGUAGE)) { + //deal with built-ins + String name = ((NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode()).getName(); + if (name.equals(INamespaceConstants.ANY)) { + //let the internal support within 'QName' class deal with it + write("new QName(null,'"); + //only stringify the right node at the next step (it is the localName part) + rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); + closeMethodCall = "'))"; + } else if (name.equals(IASKeywordConstants.PUBLIC) + || name.equals(IASKeywordConstants.PROTECTED)) { + //@todo check this, but both public and protected appear to have the effect of skipping the namespace part in swf, so just use default namespace + write("/* as3 " + name + " */ '"); + //skip the namespace to just output the name + rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); + } else { + //this is an unlikely condition, but do something that should give same results as swf... + //private, internal namespaces used in an XML context (I don't think this makes sense, but is possible to do in code) + //@todo check this, but it seems like it should never match anything in a valid XML query + write("new QName('"); + //provide an 'unlikely' 'uri': + write("_as3Lang_" + fjs.stringifyNode(namespaceIdentifierNode)); + write(s + "','"); + //only stringify the right node at the next step (it is the localName part) + rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); + closeMethodCall = "'))"; + } + } else { + write("new QName("); + s = fjs.stringifyNode(namespaceIdentifierNode); + write(s + ",'"); + //only stringify the right node at the next step (it is the localName part) + rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); + closeMethodCall = "'))"; + } + } else { + //use a special MultiQName compiler support method + //to simulate a MultiName for the used namespaces (which includes 'no namespace') + write("XML.multiQName(["); + int count = 0; + for (IDefinition nsDef:usedNamespaceDefs) { + if (count > 0) write(","); + if (nsDef instanceof INamespaceDefinition) { + write("'"+((INamespaceDefinition)nsDef).getURI()+"'"); + } else { + String varName = getEmitter().stringifyNode(((IVariableDefinition) nsDef).getVariableNode().getNameExpressionNode()); + write(varName); + } + count++; + } + write("]"); + write(", '"); + closeMethodCall = "'))"; + } + } else if (getModel().defaultXMLNamespaceActive + && ((MemberAccessExpressionNode) node).getASScope() instanceof FunctionScope + && getModel().getDefaultXMLNamespace((FunctionScope)((MemberAccessExpressionNode) node).getASScope()) != null) { + //new QName('contextualDefaultNameSpace','originalValueHere') + write("new QName("); + getEmitter().getWalker().walk(getModel().getDefaultXMLNamespace((FunctionScope)((MemberAccessExpressionNode) node).getASScope())); + write(",'"); + closeMethodCall = "'))"; + } else { + //regular string value + write("'"); //normal string name for child + } + + + s = fjs.stringifyNode(rightNode); + int dot = s.indexOf('.'); + if (dot != -1) { + String name = s.substring(0, dot); + String afterDot = s.substring(dot); + write(name); + write(closeMethodCall); + write(afterDot); + } else { + write(s); + write(closeMethodCall); + } + if (ASNodeUtils.hasParenClose(node)) + write(ASEmitterTokens.PAREN_CLOSE); + } + private boolean writeLeftSide(IMemberAccessExpressionNode node, IASNode leftNode, IASNode rightNode) { JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter();