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
commit f41c99796917f8c70f120c8411acf5a3180ea4b6 Author: greg-dove <[email protected]> AuthorDate: Wed Oct 2 17:51:34 2019 +1300 Baseline XML improvements compiler implementation --- .../royale/compiler/codegen/as/IASEmitter.java | 44 +--- .../internal/codegen/as/ASBlockWalker.java | 3 +- .../compiler/internal/codegen/as/ASEmitter.java | 56 +---- .../internal/codegen/js/JSSessionModel.java | 50 ++++- .../codegen/js/jx/BinaryOperatorEmitter.java | 23 +- .../internal/codegen/js/jx/ClassEmitter.java | 20 +- .../codegen/js/jx/DynamicAccessEmitter.java | 9 + .../js/jx/FunctionCallArgumentsEmitter.java | 31 ++- .../codegen/js/jx/FunctionCallEmitter.java | 64 +++++- .../internal/codegen/js/jx/IdentifierEmitter.java | 16 +- .../internal/codegen/js/jx/LiteralEmitter.java | 17 +- .../codegen/js/jx/MemberAccessEmitter.java | 139 +++++++++--- .../codegen/js/jx/PackageFooterEmitter.java | 1 + .../codegen/js/royale/JSRoyaleDocEmitter.java | 9 +- .../codegen/js/royale/JSRoyaleEmitter.java | 131 ++++++++--- .../internal/codegen/js/utils/EmitterUtils.java | 249 +++++++++++++++++++-- .../codegen/js/royale/TestRoyaleGlobalClasses.java | 8 +- .../codegen/js/royale/TestRoyaleStatements.java | 4 +- 18 files changed, 646 insertions(+), 228 deletions(-) diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/as/IASEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/as/IASEmitter.java index 815a80c..e8be26b 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/as/IASEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/codegen/as/IASEmitter.java @@ -25,47 +25,7 @@ import org.apache.royale.compiler.codegen.IDocEmitter; import org.apache.royale.compiler.codegen.INestingEmitter; import org.apache.royale.compiler.definitions.IPackageDefinition; import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode; -import org.apache.royale.compiler.tree.as.IASNode; -import org.apache.royale.compiler.tree.as.IBinaryOperatorNode; -import org.apache.royale.compiler.tree.as.IBlockNode; -import org.apache.royale.compiler.tree.as.ICatchNode; -import org.apache.royale.compiler.tree.as.IClassNode; -import org.apache.royale.compiler.tree.as.IContainerNode; -import org.apache.royale.compiler.tree.as.IDynamicAccessNode; -import org.apache.royale.compiler.tree.as.IEmbedNode; -import org.apache.royale.compiler.tree.as.IForLoopNode; -import org.apache.royale.compiler.tree.as.IFunctionCallNode; -import org.apache.royale.compiler.tree.as.IFunctionNode; -import org.apache.royale.compiler.tree.as.IFunctionObjectNode; -import org.apache.royale.compiler.tree.as.IGetterNode; -import org.apache.royale.compiler.tree.as.IIdentifierNode; -import org.apache.royale.compiler.tree.as.IIfNode; -import org.apache.royale.compiler.tree.as.IImportNode; -import org.apache.royale.compiler.tree.as.IInterfaceNode; -import org.apache.royale.compiler.tree.as.IIterationFlowNode; -import org.apache.royale.compiler.tree.as.IKeywordNode; -import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode; -import org.apache.royale.compiler.tree.as.ILiteralContainerNode; -import org.apache.royale.compiler.tree.as.ILiteralNode; -import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode; -import org.apache.royale.compiler.tree.as.INamespaceAccessExpressionNode; -import org.apache.royale.compiler.tree.as.INamespaceNode; -import org.apache.royale.compiler.tree.as.INumericLiteralNode; -import org.apache.royale.compiler.tree.as.IObjectLiteralValuePairNode; -import org.apache.royale.compiler.tree.as.IParameterNode; -import org.apache.royale.compiler.tree.as.IReturnNode; -import org.apache.royale.compiler.tree.as.ISetterNode; -import org.apache.royale.compiler.tree.as.ISwitchNode; -import org.apache.royale.compiler.tree.as.ITernaryOperatorNode; -import org.apache.royale.compiler.tree.as.IThrowNode; -import org.apache.royale.compiler.tree.as.ITryNode; -import org.apache.royale.compiler.tree.as.ITypedExpressionNode; -import org.apache.royale.compiler.tree.as.IUnaryOperatorNode; -import org.apache.royale.compiler.tree.as.IUseNamespaceNode; -import org.apache.royale.compiler.tree.as.IVariableExpressionNode; -import org.apache.royale.compiler.tree.as.IVariableNode; -import org.apache.royale.compiler.tree.as.IWhileLoopNode; -import org.apache.royale.compiler.tree.as.IWithNode; +import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.tree.metadata.IMetaTagNode; import org.apache.royale.compiler.visitor.IASNodeStrategy; import org.apache.royale.compiler.visitor.IBlockWalker; @@ -366,6 +326,8 @@ public interface IASEmitter extends INestingEmitter void emitContainer(IContainerNode node); void emitE4XFilter(IMemberAccessExpressionNode node); + + void emitE4XDefaultNamespaceDirective(IDefaultXMLNamespaceNode node); void emitUseNamespace(IUseNamespaceNode node); diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASBlockWalker.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASBlockWalker.java index d8f26ab..781aaa1 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASBlockWalker.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASBlockWalker.java @@ -453,8 +453,7 @@ public class ASBlockWalker implements IASBlockVisitor, IASBlockWalker public void visitDefaultXMLNamespace(IDefaultXMLNamespaceNode node) { debug("visitDefaultXMLNamespace()"); - walk(node.getKeywordNode()); // default xml namespace - walk(node.getExpressionNode()); // "http://ns.whatever.com" + emitter.emitE4XDefaultNamespaceDirective(node); } @Override diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java index d04b4ee..f2ef37d 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/as/ASEmitter.java @@ -44,57 +44,8 @@ import org.apache.royale.compiler.internal.tree.as.FunctionNode; import org.apache.royale.compiler.internal.tree.as.LabeledStatementNode; import org.apache.royale.compiler.problems.ICompilerProblem; import org.apache.royale.compiler.tree.ASTNodeID; -import org.apache.royale.compiler.tree.as.IASNode; -import org.apache.royale.compiler.tree.as.IAccessorNode; -import org.apache.royale.compiler.tree.as.IBinaryOperatorNode; -import org.apache.royale.compiler.tree.as.ICatchNode; -import org.apache.royale.compiler.tree.as.IClassNode; -import org.apache.royale.compiler.tree.as.IConditionalNode; -import org.apache.royale.compiler.tree.as.IContainerNode; +import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.tree.as.IContainerNode.ContainerType; -import org.apache.royale.compiler.tree.as.IDefinitionNode; -import org.apache.royale.compiler.tree.as.IDynamicAccessNode; -import org.apache.royale.compiler.tree.as.IEmbedNode; -import org.apache.royale.compiler.tree.as.IExpressionNode; -import org.apache.royale.compiler.tree.as.IForLoopNode; -import org.apache.royale.compiler.tree.as.IFunctionCallNode; -import org.apache.royale.compiler.tree.as.IFunctionNode; -import org.apache.royale.compiler.tree.as.IFunctionObjectNode; -import org.apache.royale.compiler.tree.as.IGetterNode; -import org.apache.royale.compiler.tree.as.IIdentifierNode; -import org.apache.royale.compiler.tree.as.IIfNode; -import org.apache.royale.compiler.tree.as.IImportNode; -import org.apache.royale.compiler.tree.as.IInterfaceNode; -import org.apache.royale.compiler.tree.as.IIterationFlowNode; -import org.apache.royale.compiler.tree.as.IKeywordNode; -import org.apache.royale.compiler.tree.as.ILanguageIdentifierNode; -import org.apache.royale.compiler.tree.as.ILiteralContainerNode; -import org.apache.royale.compiler.tree.as.ILiteralNode; -import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode; -import org.apache.royale.compiler.tree.as.INamespaceAccessExpressionNode; -import org.apache.royale.compiler.tree.as.INamespaceNode; -import org.apache.royale.compiler.tree.as.INumericLiteralNode; -import org.apache.royale.compiler.tree.as.IObjectLiteralValuePairNode; -import org.apache.royale.compiler.tree.as.IOperatorNode; -import org.apache.royale.compiler.tree.as.IPackageNode; -import org.apache.royale.compiler.tree.as.IParameterNode; -import org.apache.royale.compiler.tree.as.IReturnNode; -import org.apache.royale.compiler.tree.as.IScopedNode; -import org.apache.royale.compiler.tree.as.ISetterNode; -import org.apache.royale.compiler.tree.as.IStatementNode; -import org.apache.royale.compiler.tree.as.ISwitchNode; -import org.apache.royale.compiler.tree.as.ITerminalNode; -import org.apache.royale.compiler.tree.as.ITernaryOperatorNode; -import org.apache.royale.compiler.tree.as.IThrowNode; -import org.apache.royale.compiler.tree.as.ITryNode; -import org.apache.royale.compiler.tree.as.ITypeNode; -import org.apache.royale.compiler.tree.as.ITypedExpressionNode; -import org.apache.royale.compiler.tree.as.IUnaryOperatorNode; -import org.apache.royale.compiler.tree.as.IUseNamespaceNode; -import org.apache.royale.compiler.tree.as.IVariableExpressionNode; -import org.apache.royale.compiler.tree.as.IVariableNode; -import org.apache.royale.compiler.tree.as.IWhileLoopNode; -import org.apache.royale.compiler.tree.as.IWithNode; import org.apache.royale.compiler.tree.metadata.IMetaTagNode; import org.apache.royale.compiler.utils.ASNodeUtils; import org.apache.royale.compiler.visitor.IBlockWalker; @@ -1557,6 +1508,11 @@ public class ASEmitter implements IASEmitter, IEmitter { // ToDo (erikdebruin) } + + @Override + public void emitE4XDefaultNamespaceDirective(IDefaultXMLNamespaceNode node) + { + } @Override public void emitUseNamespace(IUseNamespaceNode node) 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 55eb732..bf25cda 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 @@ -19,18 +19,12 @@ package org.apache.royale.compiler.internal.codegen.js; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Stack; +import java.util.*; import org.apache.royale.compiler.definitions.IClassDefinition; import org.apache.royale.compiler.definitions.ITypeDefinition; -import org.apache.royale.compiler.tree.as.IFunctionNode; -import org.apache.royale.compiler.tree.as.IGetterNode; -import org.apache.royale.compiler.tree.as.ISetterNode; -import org.apache.royale.compiler.tree.as.IVariableNode; +import org.apache.royale.compiler.internal.scopes.FunctionScope; +import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.tree.metadata.IMetaTagNode; /** @@ -76,7 +70,9 @@ public class JSSessionModel public ArrayList<IFunctionNode> methods; public IClassDefinition classDefinition; public ImplicitBindableImplementation bindableImplementation; - public Boolean suppressExports; + public Boolean suppressExports; //global + public ArrayList<IASNode> suppressedExportNodes; //specific + public Boolean defaultXMLNamespaceActive; } public JSSessionModel() @@ -91,11 +87,17 @@ public class JSSessionModel public boolean isExterns = false; public boolean inE4xFilter = false; + + public Boolean defaultXMLNamespaceActive = false; + + private HashMap<FunctionScope, IExpressionNode> defaultXMLNamespaces = new HashMap<FunctionScope, IExpressionNode>(); public boolean inStaticInitializer = false; public boolean suppressExports = false; + public ArrayList<IASNode> suppressedExportNodes = new ArrayList<IASNode>(); + private LinkedHashMap<String, PropertyNodes> propertyMap = new LinkedHashMap<String, PropertyNodes>(); private List<String> interfacePropertyMap = new ArrayList<String>(); @@ -141,6 +143,28 @@ public class JSSessionModel implicitBindableImplementations.remove(classDefinition); } } + + public void registerDefaultXMLNamespace(FunctionScope forFunctionScope, IExpressionNode defaultNamespace) { + if (forFunctionScope != null) { + if (defaultNamespace == null) { + //unregister + defaultXMLNamespaces.remove(forFunctionScope); + if (defaultXMLNamespaces.isEmpty()) { + defaultXMLNamespaceActive = false; + } + } else { + defaultXMLNamespaceActive = true; + defaultXMLNamespaces.put(forFunctionScope, defaultNamespace); + } + } + } + + public IExpressionNode getDefaultXMLNamespace(FunctionScope forFunctionScope) { + if (defaultXMLNamespaceActive) { + return defaultXMLNamespaces.get(forFunctionScope); + } + return null; + } public void pushClass(IClassDefinition currentClass) { @@ -154,8 +178,11 @@ public class JSSessionModel context.methods = methods; context.bindableImplementation = implicitBindableImplementation; context.suppressExports = suppressExports; + context.suppressedExportNodes = suppressedExportNodes; + context.defaultXMLNamespaceActive = defaultXMLNamespaceActive; stack.push(context); suppressExports = false; //always defaults to false + suppressedExportNodes = new ArrayList<IASNode>(); this.currentClass = currentClass; bindableVars = new HashMap<String, BindableVarInfo>(); staticPropertyMap = new LinkedHashMap<String, PropertyNodes>(); @@ -166,6 +193,7 @@ public class JSSessionModel implicitBindableImplementation = implicitBindableImplementations.get(currentClass); if (implicitBindableImplementation == null) implicitBindableImplementation = ImplicitBindableImplementation.NONE; + defaultXMLNamespaceActive = false; } public void popClass() @@ -180,6 +208,8 @@ public class JSSessionModel methods = context.methods; implicitBindableImplementation = context.bindableImplementation; suppressExports = context.suppressExports; + suppressedExportNodes = context.suppressedExportNodes; + defaultXMLNamespaceActive = context.defaultXMLNamespaceActive; } public HashMap<String, PropertyNodes> getPropertyMap() diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java index e55ed32..a9066d8 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/BinaryOperatorEmitter.java @@ -39,11 +39,7 @@ import org.apache.royale.compiler.internal.projects.RoyaleJSProject; import org.apache.royale.compiler.internal.semantics.SemanticUtils; import org.apache.royale.compiler.internal.tree.as.*; import org.apache.royale.compiler.tree.ASTNodeID; -import org.apache.royale.compiler.tree.as.IASNode; -import org.apache.royale.compiler.tree.as.IBinaryOperatorNode; -import org.apache.royale.compiler.tree.as.IClassNode; -import org.apache.royale.compiler.tree.as.IExpressionNode; -import org.apache.royale.compiler.tree.as.IIdentifierNode; +import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.utils.ASNodeUtils; public class BinaryOperatorEmitter extends JSSubEmitter implements @@ -428,6 +424,23 @@ public class BinaryOperatorEmitter extends JSSubEmitter implements } } + + if (id == ASTNodeID.Op_EqualID) { + //QName == QName + if (leftDef != null && leftDef.getQualifiedName().equals("QName")) { + IDefinition rightDef = node.getRightOperandNode().resolveType(getProject()); + if (rightDef != null && rightDef.getQualifiedName().equals("QName")) { + //handle non-strict equality a little differently + write("QName.equality("); + getWalker().walk(node.getLeftOperandNode()); + write(","); + getWalker().walk(node.getRightOperandNode()); + write(")"); + return; + } + } + } + super_emitBinaryOperator(node, isAssignment); } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java index 4c1877d..c623780 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/ClassEmitter.java @@ -35,15 +35,10 @@ import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterToke import org.apache.royale.compiler.internal.codegen.js.utils.DocEmitterUtils; import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils; import org.apache.royale.compiler.internal.projects.RoyaleJSProject; +import org.apache.royale.compiler.internal.scopes.FunctionScope; import org.apache.royale.compiler.internal.tree.as.IdentifierNode; import org.apache.royale.compiler.tree.ASTNodeID; -import org.apache.royale.compiler.tree.as.IASNode; -import org.apache.royale.compiler.tree.as.IAccessorNode; -import org.apache.royale.compiler.tree.as.IClassNode; -import org.apache.royale.compiler.tree.as.IDefinitionNode; -import org.apache.royale.compiler.tree.as.IExpressionNode; -import org.apache.royale.compiler.tree.as.IFunctionNode; -import org.apache.royale.compiler.tree.as.IVariableNode; +import org.apache.royale.compiler.tree.as.*; public class ClassEmitter extends JSSubEmitter implements ISubEmitter<IClassNode> @@ -192,6 +187,9 @@ public class ClassEmitter extends JSSubEmitter implements writeNewline(); getEmitter().emitMethod((IFunctionNode) dnode); write(ASEmitterTokens.SEMICOLON); + if (getModel().defaultXMLNamespaceActive) { + getModel().registerDefaultXMLNamespace((FunctionScope) ((IFunctionNode) dnode).getScopedNode().getScope(), null); + } } } else if (dnode.getNodeID() == ASTNodeID.GetterID @@ -214,6 +212,14 @@ public class ClassEmitter extends JSSubEmitter implements startMapping(dnode, dnode); write(ASEmitterTokens.SEMICOLON); endMapping(dnode); + } else if (dnode.getNodeID() == ASTNodeID.NamespaceID) { + writeNewline(); + writeNewline(); + writeNewline(); + getEmitter().emitNamespace((INamespaceNode) dnode); + startMapping(dnode, dnode); + write(ASEmitterTokens.SEMICOLON); + endMapping(dnode); } } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java index 5b78317..520acbb 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/DynamicAccessEmitter.java @@ -79,6 +79,15 @@ public class DynamicAccessEmitter extends JSSubEmitter implements isProxy = fjs.isProxy((IExpressionNode)leftOperandNode); if (isXML) { + if (type == null) { + //this can happen if myThing is of type Object or AnyType (*) + //with example: myXml.somethingChild[myThing.id] + //use Stringify with 'child' method, which has support for attributes vs elements + write(".child('' +"); + getWalker().walk(rightOperandNode); + write(")"); + return; + } if (type.isInstanceOf("String", getProject())) { String field = fjs.stringifyNode(rightOperandNode); diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java index c92f189..cbd786a 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallArgumentsEmitter.java @@ -26,6 +26,7 @@ import org.apache.royale.compiler.definitions.IFunctionDefinition; import org.apache.royale.compiler.definitions.IParameterDefinition; import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter; +import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils; import org.apache.royale.compiler.tree.as.IContainerNode; import org.apache.royale.compiler.tree.as.IExpressionNode; import org.apache.royale.compiler.tree.as.IFunctionCallNode; @@ -45,6 +46,14 @@ public class FunctionCallArgumentsEmitter extends JSSubEmitter implements write(ASEmitterTokens.PAREN_OPEN); endMapping(node); + emitContents(node); + + startMapping(node, node.getLine(), node.getColumn() + node.getAbsoluteEnd() - node.getAbsoluteStart() - 1); + write(ASEmitterTokens.PAREN_CLOSE); + endMapping(node); + } + + public void emitContents(IContainerNode node) { IParameterDefinition[] paramDefs = null; IFunctionCallNode functionCallNode = (IFunctionCallNode) node.getAncestorOfType(IFunctionCallNode.class); if (functionCallNode != null) @@ -56,12 +65,16 @@ public class FunctionCallArgumentsEmitter extends JSSubEmitter implements paramDefs = functionDef.getParameters(); } } - + //arguments needs patching to deal with something that seems off-spec (discussed in dev list) + //check once for function, because it assumes a function with only one arg + boolean needsQNamePatching = EmitterUtils.needsXMLQNameArgumentsPatch(functionCallNode, getProject()); + int len = node.getChildCount(); for (int i = 0; i < len; i++) { IExpressionNode argumentNode = (IExpressionNode) node.getChild(i); IDefinition paramTypeDef = null; + String postArgPatch = null; if (paramDefs != null && paramDefs.length > i) { IParameterDefinition paramDef = paramDefs[i]; @@ -75,8 +88,18 @@ public class FunctionCallArgumentsEmitter extends JSSubEmitter implements } } + if (needsQNamePatching) { + //check patch needed + postArgPatch = ")"; + write("XML.swfCompatibleQuery("); + } + getEmitter().emitAssignmentCoercion(argumentNode, paramTypeDef); - + + if (postArgPatch != null){ + write(postArgPatch); //reset to null on next iteration + } + if (i < len - 1) { //we're mapping the comma to the container, but we use the @@ -87,9 +110,5 @@ public class FunctionCallArgumentsEmitter extends JSSubEmitter implements endMapping(node); } } - - startMapping(node, node.getLine(), node.getColumn() + node.getAbsoluteEnd() - node.getAbsoluteStart() - 1); - write(ASEmitterTokens.PAREN_CLOSE); - endMapping(node); } } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java index 4de1d14..b450073 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/FunctionCallEmitter.java @@ -37,6 +37,7 @@ import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterToke import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils; import org.apache.royale.compiler.internal.definitions.*; import org.apache.royale.compiler.internal.projects.RoyaleJSProject; +import org.apache.royale.compiler.internal.scopes.FunctionScope; import org.apache.royale.compiler.internal.tree.as.*; import org.apache.royale.compiler.problems.TooFewFunctionParametersProblem; import org.apache.royale.compiler.problems.TooManyFunctionParametersProblem; @@ -78,7 +79,19 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu if (nameNode instanceof IdentifierNode && (((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.String) || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Boolean) - || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Number))) + || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Number) + || ( + ( + ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.QName) || + ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.XML) + ) + //use an alternate 'constructor' if there is an alternate default namespace + && getModel().defaultXMLNamespaceActive + && node.getContainingScope().getScope() instanceof FunctionScope + && getModel().getDefaultXMLNamespace((FunctionScope)node.getContainingScope().getScope()) != null + ) + ) + ) { omitNew = true; } @@ -228,6 +241,45 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu write(JSRoyaleEmitterTokens.UNDERSCORE); write(def.getQualifiedName()); endMapping(nameNode); + } else if( def.getQualifiedName().equals("QName") + && getModel().defaultXMLNamespaceActive + //is the execution context relevant + && node.getContainingScope().getScope() instanceof FunctionScope + && getModel().getDefaultXMLNamespace(((FunctionScope)node.getContainingScope().getScope()))!=null + ) { + + IExpressionNode alternateDefaultNS = getModel().getDefaultXMLNamespace(((FunctionScope)node.getContainingScope().getScope())); + + write("QName.createWithDefaultNamespace"); + endMapping(nameNode); + startMapping(node.getArgumentsNode()); + write(ASEmitterTokens.PAREN_OPEN); + endMapping(node.getArgumentsNode()); + write("/* compiler-added default namespace: */ "); + getEmitter().getWalker().walk(alternateDefaultNS); + + int argCount = node.getArgumentsNode().getChildCount(); + if (argCount>0) + write(","); + + ((FunctionCallArgumentsEmitter) ((JSRoyaleEmitter) getEmitter()).functionCallArgumentsEmitter).emitContents(node.getArgumentsNode()); + + startMapping(node.getArgumentsNode()); + write(ASEmitterTokens.PAREN_CLOSE); + endMapping(node.getArgumentsNode()); + return; + } else if( def.getQualifiedName().equals("XML") + && node.getArgumentsNode().getChildCount() == 1 + && getModel().defaultXMLNamespaceActive + //is the execution context relevant + && node.getContainingScope().getScope() instanceof FunctionScope + && getModel().getDefaultXMLNamespace(((FunctionScope)node.getContainingScope().getScope()))!=null + ){ + write("XML.constructWithDefaultXmlNS"); + //patch in the defaultNS arg (at position 1. + EmitterUtils.createDefaultNamespaceArg(node.getArgumentsNode(),1,getModel().getDefaultXMLNamespace(((FunctionScope)node.getContainingScope().getScope()))); + getEmitter().emitArguments(node.getArgumentsNode()); + return; } else { @@ -513,6 +565,16 @@ public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFu else if (def.getBaseName().equals(IASLanguageConstants.XML)) { write("XML.conversion"); + if (getModel().defaultXMLNamespaceActive) { + //add the default namespace as a second param + if (node.getContainingScope().getScope() instanceof FunctionScope) { + IExpressionNode defaultNS = getModel().getDefaultXMLNamespace((FunctionScope)(node.getContainingScope().getScope())); + if (defaultNS != null) { + //append the 'default' namespace as a second argument in the conversion function. Only applies if parsing is required. + EmitterUtils.createDefaultNamespaceArg(node.getArgumentsNode(), 1, defaultNS); + } + } + } getEmitter().emitArguments(node.getArgumentsNode()); return; } diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java index f6363ea..2b1008a 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/IdentifierEmitter.java @@ -41,9 +41,6 @@ import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterToke import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils; import org.apache.royale.compiler.internal.definitions.*; import org.apache.royale.compiler.internal.projects.RoyaleJSProject; -import org.apache.royale.compiler.internal.tree.as.BinaryOperatorAssignmentNode; -import org.apache.royale.compiler.internal.tree.as.BinaryOperatorDivisionAssignmentNode; -import org.apache.royale.compiler.internal.tree.as.MemberAccessExpressionNode; import org.apache.royale.compiler.internal.tree.as.NonResolvingIdentifierNode; import org.apache.royale.compiler.tree.ASTNodeID; import org.apache.royale.compiler.tree.as.*; @@ -73,7 +70,7 @@ public class IdentifierEmitter extends JSSubEmitter implements IASNode parentNode = node.getParent(); ASTNodeID parentNodeId = parentNode.getNodeID(); IASNode grandparentNode = parentNode.getParent(); - ASTNodeID grandparentNodeId = (parentNode != null) ? grandparentNode.getNodeID() : null; + // ASTNodeID grandparentNodeId = (parentNode != null) ? grandparentNode.getNodeID() : null; boolean identifierIsAccessorFunction = nodeDef instanceof AccessorDefinition; boolean identifierIsPlainFunction = nodeDef instanceof FunctionDefinition @@ -292,10 +289,7 @@ public class IdentifierEmitter extends JSSubEmitter implements emitName = false; } } - - //IDefinition parentDef = (nodeDef != null) ? nodeDef.getParent() : null; - //boolean isNative = (parentDef != null) - // && NativeUtils.isNative(parentDef.getBaseName()); + if (emitName) { if (nodeDef != null) @@ -389,8 +383,10 @@ public class IdentifierEmitter extends JSSubEmitter implements } endMapping(node); } - else if (grandparentNodeId == ASTNodeID.E4XFilterID && - (!(parentNodeId == ASTNodeID.MemberAccessExpressionID || parentNodeId == ASTNodeID.Op_DescendantsID))) + else if (getModel().inE4xFilter && EmitterUtils.writeE4xFilterNode(getProject(), getModel(), node) /* swapped this out to allow for deeper nesting inside the filter expression ... instead of original:grandparentNodeId == ASTNodeID.E4XFilterID*/ + && (!(parentNodeId == ASTNodeID.MemberAccessExpressionID + || parentNodeId == ASTNodeID.Op_DescendantsID + || parentNodeId == ASTNodeID.FunctionCallID))) { startMapping(node); write("child('"); diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java index 939f498..5de72a3 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/LiteralEmitter.java @@ -30,6 +30,7 @@ import org.apache.royale.compiler.common.IMetaInfo; import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter; import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens; +import org.apache.royale.compiler.internal.scopes.FunctionScope; import org.apache.royale.compiler.internal.tree.as.LiteralNode; import org.apache.royale.compiler.internal.tree.as.RegExpLiteralNode; import org.apache.royale.compiler.internal.tree.as.XMLLiteralNode; @@ -139,7 +140,21 @@ public class LiteralEmitter extends JSSubEmitter implements s = "\"" + s + "\""; } // use formatQualifiedName to get XML in the usedNames dependencies - s = "new " + getEmitter().formatQualifiedName("XML") + "( " + s + ")"; + if (getModel().defaultXMLNamespaceActive && + xmlNode.getContainingScope().getScope() instanceof FunctionScope && + getModel().getDefaultXMLNamespace((FunctionScope)(xmlNode.getContainingScope().getScope())) != null) { + s = getEmitter().formatQualifiedName("XML") + + ASEmitterTokens.MEMBER_ACCESS.getToken() + + "constructWithDefaultXmlNS" + + "(" + + s + //we need to append the default ns arg: + +"," + + getEmitter().stringifyNode(getModel().getDefaultXMLNamespace((FunctionScope)(xmlNode.getContainingScope().getScope()))) + +")"; + + } + else s = "new " + getEmitter().formatQualifiedName("XML") + "( " + s + ")"; } } else diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java index d6e5ccb..8d7dd16 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/jx/MemberAccessEmitter.java @@ -21,12 +21,14 @@ package org.apache.royale.compiler.internal.codegen.js.jx; import org.apache.royale.compiler.codegen.ISubEmitter; import org.apache.royale.compiler.codegen.js.IJSEmitter; +import org.apache.royale.compiler.common.DependencyType; import org.apache.royale.compiler.constants.IASKeywordConstants; import org.apache.royale.compiler.constants.IASLanguageConstants; import org.apache.royale.compiler.constants.INamespaceConstants; import org.apache.royale.compiler.definitions.IDefinition; import org.apache.royale.compiler.definitions.INamespaceDefinition; import org.apache.royale.compiler.definitions.IPackageDefinition; +import org.apache.royale.compiler.definitions.IVariableDefinition; 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; @@ -37,7 +39,9 @@ import org.apache.royale.compiler.internal.codegen.js.goog.JSGoogEmitterTokens; import org.apache.royale.compiler.internal.codegen.js.jx.BinaryOperatorEmitter.DatePropertiesGetters; 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.projects.RoyaleJSProject; +import org.apache.royale.compiler.internal.scopes.FunctionScope; import org.apache.royale.compiler.internal.tree.as.*; import org.apache.royale.compiler.projects.ICompilerProject; import org.apache.royale.compiler.tree.ASTNodeID; @@ -45,6 +49,8 @@ import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.tree.as.IOperatorNode.OperatorType; import org.apache.royale.compiler.utils.ASNodeUtils; +import java.util.ArrayList; + public class MemberAccessEmitter extends JSSubEmitter implements ISubEmitter<IMemberAccessExpressionNode> { @@ -93,7 +99,7 @@ public class MemberAccessEmitter extends JSSubEmitter implements if (isXML) { boolean descendant = (node.getOperator() == OperatorType.DESCENDANT_ACCESS); - boolean child = (node.getOperator() == OperatorType.MEMBER_ACCESS) && + boolean child = !descendant && (node.getOperator() == OperatorType.MEMBER_ACCESS) && (!(parentNode instanceof FunctionCallNode)) && rightNode.getNodeID() != ASTNodeID.Op_AtID && !((rightNode.getNodeID() == ASTNodeID.ArrayIndexExpressionID) && @@ -106,46 +112,113 @@ public class MemberAccessEmitter extends JSSubEmitter implements write(".child("); String closeMethodCall = "')"; String s = ""; - if (rightNode instanceof INamespaceAccessExpressionNode) { - NamespaceIdentifierNode namespaceIdentifierNode = (NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode(); - IDefinition nsDef = namespaceIdentifierNode.resolve(getProject()); - if (nsDef instanceof INamespaceDefinition - && ((INamespaceDefinition)nsDef).getNamespaceClassification().equals(INamespaceDefinition.NamespaceClassification.LANGUAGE)) { - //deal with built-ins - String name = ((NamespaceIdentifierNode) ((INamespaceAccessExpressionNode) rightNode).getLeftOperandNode()).getName(); - if (name.equals(INamespaceConstants.ANY)) { - //let the internal support within 'QName' class deal with it - write("new QName('*', '"); - //only stringify the right node at the next step (it is the localName part) - rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); - closeMethodCall = "'))"; - } else if (name.equals(IASKeywordConstants.PUBLIC) - || name.equals(IASKeywordConstants.PROTECTED)) { - //@todo check this, but both public and protected appear to have the effect of skipping the namespace part in swf, so just use default namespace - write("/* as3 " + name + " */ '"); - //skip the namespace to just output the name - rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); + 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 { - //this is an unlikely condition, but do something that should give same results as swf... - //private, internal namespaces used in an XML context (I don't think this makes sense) - //@todo check this, but it seems like it should never match anything in a valid XML query - write("new QName('"); - //provide an 'unlikely' 'uri': - write("_as3Lang_" + fjs.stringifyNode(namespaceIdentifierNode)); - write(s + "', '"); + write("new QName("); + s = fjs.stringifyNode(namespaceIdentifierNode); + write(s + ",'"); //only stringify the right node at the next step (it is the localName part) rightNode = ((INamespaceAccessExpressionNode) rightNode).getRightOperandNode(); closeMethodCall = "'))"; } } else { - write("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(); + //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 write("'"); //normal string name for child + } 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('.'); 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 86bc80d..650906a 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 @@ -447,6 +447,7 @@ public class PackageFooterEmitter extends JSSubEmitter implements String ns = fnNode.getNamespace(); if (isInterface || (ns != null && ns.equals(IASKeywordConstants.PUBLIC))) { + if (getModel().suppressedExportNodes.contains(fnNode)) continue; MethodData data = new MethodData(); data.isStatic = isStatic; methodData.add(data); 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 0c32ad3..3c1616d 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 @@ -267,8 +267,11 @@ public class JSRoyaleDocEmitter extends JSGoogDocEmitter suppressClosure = true; String suppressExport = JSRoyaleEmitterTokens.SUPPRESS_EXPORT.getToken(); - if (docText.contains(suppressExport)) + if (docText.contains(suppressExport)) { emitExports = false; + if (IASKeywordConstants.PUBLIC.equals(ns)) // suppress it for reflection data checks: + ((JSRoyaleEmitter) (emitter)).getModel().suppressedExportNodes.add(node); + } write(changeAnnotations(asDoc.commentNoEnd())); } @@ -443,6 +446,10 @@ public class JSRoyaleDocEmitter extends JSGoogDocEmitter } } + public boolean hasIgnore(String qName) { + return ignoreList !=null && qName != null && ignoreList.contains(qName); + } + private void loadKeepers(String doc) { coercionList = new ArrayList<String>(); diff --git a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java index d3a65ab..daaa3b0 100644 --- a/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java +++ b/compiler-jx/src/main/java/org/apache/royale/compiler/internal/codegen/js/royale/JSRoyaleEmitter.java @@ -79,39 +79,15 @@ import org.apache.royale.compiler.internal.embedding.EmbedMIMEType; import org.apache.royale.compiler.internal.projects.CompilerProject; import org.apache.royale.compiler.internal.projects.RoyaleJSProject; import org.apache.royale.compiler.internal.projects.RoyaleProject; +import org.apache.royale.compiler.internal.scopes.FunctionScope; +import org.apache.royale.compiler.internal.scopes.PackageScope; import org.apache.royale.compiler.internal.semantics.SemanticUtils; import org.apache.royale.compiler.internal.tree.as.*; import org.apache.royale.compiler.problems.EmbedUnableToReadSourceProblem; import org.apache.royale.compiler.problems.FilePrivateItemsWithMainVarWarningProblem; import org.apache.royale.compiler.projects.ICompilerProject; import org.apache.royale.compiler.tree.ASTNodeID; -import org.apache.royale.compiler.tree.as.IASNode; -import org.apache.royale.compiler.tree.as.IAccessorNode; -import org.apache.royale.compiler.tree.as.IBinaryOperatorNode; -import org.apache.royale.compiler.tree.as.IClassNode; -import org.apache.royale.compiler.tree.as.IContainerNode; -import org.apache.royale.compiler.tree.as.IDefinitionNode; -import org.apache.royale.compiler.tree.as.IEmbedNode; -import org.apache.royale.compiler.tree.as.IExpressionNode; -import org.apache.royale.compiler.tree.as.IFileNode; -import org.apache.royale.compiler.tree.as.IForLoopNode; -import org.apache.royale.compiler.tree.as.IFunctionCallNode; -import org.apache.royale.compiler.tree.as.IFunctionNode; -import org.apache.royale.compiler.tree.as.IFunctionObjectNode; -import org.apache.royale.compiler.tree.as.IGetterNode; -import org.apache.royale.compiler.tree.as.IIdentifierNode; -import org.apache.royale.compiler.tree.as.IInterfaceNode; -import org.apache.royale.compiler.tree.as.ILiteralNode; -import org.apache.royale.compiler.tree.as.IMemberAccessExpressionNode; -import org.apache.royale.compiler.tree.as.INamespaceDecorationNode; -import org.apache.royale.compiler.tree.as.INamespaceNode; -import org.apache.royale.compiler.tree.as.IPackageNode; -import org.apache.royale.compiler.tree.as.IScopedNode; -import org.apache.royale.compiler.tree.as.ISetterNode; -import org.apache.royale.compiler.tree.as.ITypedExpressionNode; -import org.apache.royale.compiler.tree.as.IUnaryOperatorNode; -import org.apache.royale.compiler.tree.as.IVariableNode; -import org.apache.royale.compiler.units.ICompilationUnit; +import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.utils.ASNodeUtils; import com.google.common.base.Joiner; @@ -587,25 +563,58 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter public void emitNamespace(INamespaceNode node) { needNamespace = true; - write(formatQualifiedName(node.getQualifiedName())); + if (node.getContainingScope().getScope() instanceof PackageScope) { + startMapping(node); + write(formatQualifiedName(node.getQualifiedName())); + endMapping(node); + } else if (node.getContainingScope().getScope() instanceof FunctionScope){ + writeToken(ASEmitterTokens.VAR); + write("/** @type {"+IASLanguageConstants.Namespace+"} */"); + startMapping(node); + write(node.getName()); + endMapping(node); + } else { + //class member - static scope + if (!(node.getDefinition().getParent() instanceof IClassDefinition)) { + startMapping(node); + write(node.getQualifiedName()); + endMapping(node); + } else { + write(node.getDefinition().getParent().getQualifiedName()); + write(ASEmitterTokens.MEMBER_ACCESS); + startMapping(node); + write(node.getName()); + endMapping(node); + } + } write(ASEmitterTokens.SPACE); writeToken(ASEmitterTokens.EQUAL); writeToken(ASEmitterTokens.NEW); + startMapping(node); write(IASLanguageConstants.Namespace); + endMapping(node); write(ASEmitterTokens.PAREN_OPEN); if (!staticUsedNames.contains(IASLanguageConstants.Namespace)) staticUsedNames.add(IASLanguageConstants.Namespace); IExpressionNode uriNode = node.getNamespaceURINode(); if (uriNode == null) { + startMapping(node); write(ASEmitterTokens.SINGLE_QUOTE); write(node.getName()); write(ASEmitterTokens.SINGLE_QUOTE); + endMapping(node); } else getWalker().walk(uriNode); write(ASEmitterTokens.PAREN_CLOSE); - write(ASEmitterTokens.SEMICOLON); + } + + @Override + public void emitUseNamespace(IUseNamespaceNode node) + { + write("//use namespace "); + getWalker().walk(node.getTargetNamespaceNode()); } public boolean isCustomNamespace(FunctionNode node) @@ -981,14 +990,36 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter { getWalker().walk(node.getLeftOperandNode()); getModel().inE4xFilter = true; - write(".filter(function(node){return ("); String s = stringifyNode(node.getRightOperandNode()); if (s.startsWith("(") && s.endsWith(")")) s = s.substring(1, s.length() - 1); - write(s); - write(")})"); + if (s.contains("this")) { + //it *could* be in some string content, but most likely is an actual 'this' reference + //so always bind to 'this' to correctly resolve the external references for the instance scope of the original code. + write(".filter((function(/** @type {XML} */ node){return ("); + write(s); + write(")})"); + write(".bind(this))"); + } else { + write(".filter(function(/** @type {XML} */ node){return ("); + write(s); + write(")})"); + } getModel().inE4xFilter = false; } + + @Override + public void emitE4XDefaultNamespaceDirective(IDefaultXMLNamespaceNode node){ + //leave a comment at the original code location + write("// e4x default namespace active: "); + getWalker().walk(node.getKeywordNode()); + write(" = "); + getWalker().walk(node.getExpressionNode()); + //register the namespace for the current function scope (and only for function scopes (observed behavior) ) + if (node.getContainingScope().getScope() instanceof FunctionScope) { + getModel().registerDefaultXMLNamespace(((FunctionScope)node.getContainingScope().getScope()), node.getExpressionNode()); + } + } @Override public void emitBinaryOperator(IBinaryOperatorNode node) @@ -1253,9 +1284,39 @@ public class JSRoyaleEmitter extends JSGoogEmitter implements IJSRoyaleEmitter { if (EmitterUtils.writeE4xFilterNode(getWalker().getProject(), getModel(), node)) write("node."); - write("attribute('"); - getWalker().walk(node.getOperandNode()); - write("')"); + write("attribute("); + if (op instanceof INamespaceAccessExpressionNode) { + //parent.@ns::attributeName + write("XML.createAttributeQName("); + write("new QName("); + getWalker().walk(((INamespaceAccessExpressionNode) op).getLeftOperandNode()); + write(",'"); + getWalker().walk(((INamespaceAccessExpressionNode) op).getRightOperandNode()); + write("')"); + write(")"); + } else { + if (getModel().defaultXMLNamespaceActive + && op instanceof IIdentifierNode + && node.getContainingScope().getScope() instanceof FunctionScope + && getModel().getDefaultXMLNamespace((FunctionScope)(node.getContainingScope().getScope())) !=null) { + //apply default namespace to this attributes query + //parent.@attributeName (with default xml namespace set in scope) + write("XML.swfCompatibleQuery("); + write("new QName("); + getWalker().walk(getModel().getDefaultXMLNamespace((FunctionScope)(node.getContainingScope().getScope()))); + write(",'"); + getWalker().walk(node.getOperandNode()); + write("')"); + write(", true"); //attribute flag + write(")"); + } else { + //default namespace is '' + write("'"); + getWalker().walk(node.getOperandNode()); + write("'"); + } + } + write(")"); } else if (node.getParent().getNodeID() == ASTNodeID.ArrayIndexExpressionID) { 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 eeec0c2..5f9ad14 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 @@ -41,27 +41,11 @@ import org.apache.royale.compiler.internal.definitions.InterfaceDefinition; import org.apache.royale.compiler.internal.definitions.NamespaceDefinition.INamepaceDeclarationDirective; import org.apache.royale.compiler.internal.definitions.ParameterDefinition; import org.apache.royale.compiler.internal.definitions.VariableDefinition; -import org.apache.royale.compiler.internal.tree.as.ContainerNode; -import org.apache.royale.compiler.internal.tree.as.NodeBase; -import org.apache.royale.compiler.internal.tree.as.ParameterNode; +import org.apache.royale.compiler.internal.semantics.SemanticUtils; +import org.apache.royale.compiler.internal.tree.as.*; import org.apache.royale.compiler.projects.ICompilerProject; import org.apache.royale.compiler.tree.ASTNodeID; -import org.apache.royale.compiler.tree.as.IASNode; -import org.apache.royale.compiler.tree.as.IAccessorNode; -import org.apache.royale.compiler.tree.as.IClassNode; -import org.apache.royale.compiler.tree.as.IContainerNode; -import org.apache.royale.compiler.tree.as.IDefinitionNode; -import org.apache.royale.compiler.tree.as.IExpressionNode; -import org.apache.royale.compiler.tree.as.IFunctionNode; -import org.apache.royale.compiler.tree.as.IIdentifierNode; -import org.apache.royale.compiler.tree.as.INamespaceNode; -import org.apache.royale.compiler.tree.as.IPackageNode; -import org.apache.royale.compiler.tree.as.IParameterNode; -import org.apache.royale.compiler.tree.as.IScopedNode; -import org.apache.royale.compiler.tree.as.ITypeNode; -import org.apache.royale.compiler.tree.as.IUnaryOperatorNode; -import org.apache.royale.compiler.tree.as.IVariableExpressionNode; -import org.apache.royale.compiler.tree.as.IVariableNode; +import org.apache.royale.compiler.tree.as.*; import org.apache.royale.compiler.utils.NativeUtils; /** @@ -473,9 +457,89 @@ public class EmitterUtils if (node == firstChild) return true; - + //support alternate ordering of checks, e.g. listItem.(3 == @id) as well as the normal listItem.(@id == 3) + if (parentNode instanceof IBinaryOperatorNode + && node == parentNode.getChild(1)) { + return !(parentNode instanceof IMemberAccessExpressionNode); + } + return false; } + + /* public static ArrayList<String> amendE4XFilterComparison(ICompilerProject project, + JSSessionModel model, IBinaryOperatorNode node, boolean isLeft) { + if (!model.inE4xFilter) return null; + IExpressionNode leftNode = node.getLeftOperandNode(); + IDefinition left = null; + IDefinition right = null; + boolean leftNodeMember = false; + boolean leftNodeQName = false; + boolean rightNodeMember = false; + boolean rightNodeQName = false; + if (writeE4xFilterNode(project, model, leftNode)) { + leftNodeMember = true; + if (leftNode instanceof IFunctionCallNode && + ((IFunctionCallNode) leftNode).getNameNode() != null){ + leftNodeQName = ((IFunctionCallNode) leftNode).getNameNode().equals("name"); + } + } else { + left = node.getLeftOperandNode().resolveType(project); + } + IExpressionNode rightNode = node.getRightOperandNode(); + if (writeE4xFilterNode(project, model, rightNode)) { + rightNodeMember = true; + if (rightNode instanceof IFunctionCallNode && + ((IFunctionCallNode) rightNode).getNameNode() != null){ + rightNodeQName = ((IFunctionCallNode) rightNode).getNameNode().equals("name"); + } + } else { + right = node.getRightOperandNode().resolveType(project); + } + if (!leftNodeMember && !rightNodeMember) return null; + ArrayList<String> s = null; + if (leftNodeMember) { + //left side is a node.something() function + if (right!= null && leftNodeQName) { + //node.name() == right + if (right.getQualifiedName().equals("String")) { + if (isLeft) { + s=new ArrayList<String>(); + s.add(".toString()"); + } //else make no change for right side + } else if (rightNodeQName || right.getQualifiedName().equals("QName")) { + //use qname.equals(otherQName) + if (isLeft) { + s.add(".equals("); + } else { + s.add(")"); //close the equals + } + } + } + } + if (s == null && rightNodeMember) { + //right side is a node.something() function that has not already been addressed + if (left!= null && rightNodeQName) { + //left == node.name() + if (left.getQualifiedName().equals("String")) { + if (!isLeft) { + //node.name().toString() + s=new ArrayList<String>(); + s.add(".toString()"); + } //else make no change for right side + } else if (rightNodeQName || right.getQualifiedName().equals("QName")) { + //use qname.equals(otherQName) + if (isLeft) { + s.add(".equals("); + } else { + s.add(")"); //close the equals + } + } + } + } + + + return s; + }*/ public static boolean isScalar(IExpressionNode node) { @@ -661,5 +725,150 @@ public class EmitterUtils } return defaultInitializers; } + + + /** + * resolveType on an XML expression returns null + * (see IdentiferNode.resolveType). + * So, we have to walk the tree ourselves and resolve + * individual pieces. + * @param obj + * @return + */ + public static boolean isXML(IExpressionNode obj, ICompilerProject project ) + { + // See if the left side is XML or XMLList + IDefinition leftDef = obj.resolveType(project); + if (leftDef == null && obj.getNodeID() == ASTNodeID.MemberAccessExpressionID) + { + return isXML(((MemberAccessExpressionNode)obj).getLeftOperandNode(), project); + } + else if (leftDef != null && leftDef.getBaseName().equals("*") && obj instanceof DynamicAccessNode) { + return isXML(((DynamicAccessNode)obj).getLeftOperandNode(), project); + } + return SemanticUtils.isXMLish(leftDef, project); + } + + + /** + * resolveType on an XML expression returns null + * (see IdentiferNode.resolveType). + * So, we have to walk the tree ourselves and resolve + * individual pieces. + * We want to know not just whether the node is of type XML, + * but whether it is a property of a property of type XML. + * For example, this.foo might be XML or XMLList, but since + * 'this' isn't also XML, we return false. That's because + * assignment to this.foo shouldn't use setChild() but + * just do an assignment. + * @param obj + * @return + */ + public static boolean isXMLList(MemberAccessExpressionNode obj, ICompilerProject project) + { + IExpressionNode leftNode = obj.getLeftOperandNode(); + IExpressionNode rightNode = obj.getRightOperandNode(); + ASTNodeID rightID = rightNode.getNodeID(); + if (rightID == ASTNodeID.IdentifierID) + { + IDefinition rightDef = rightNode.resolveType(project); + if (rightDef != null) + { + if (SemanticUtils.isXMLish(rightDef, project)) + { + return isLeftNodeXMLish(leftNode, project); + } + return false; + } + return isLeftNodeXMLish(leftNode, project); + } + else if (rightID == ASTNodeID.Op_AtID) + return true; + return false; + } + + + public static boolean isLeftNodeXMLish(IExpressionNode leftNode, ICompilerProject project) + { + ASTNodeID leftID = leftNode.getNodeID(); + if (leftID == ASTNodeID.IdentifierID) + { + IDefinition leftDef = leftNode.resolveType(project); + if (leftDef != null) + return SemanticUtils.isXMLish(leftDef, project); + } + else if (leftID == ASTNodeID.MemberAccessExpressionID || leftID == ASTNodeID.Op_DescendantsID) + { + MemberAccessExpressionNode maen = (MemberAccessExpressionNode)leftNode; + IExpressionNode rightNode = maen.getRightOperandNode(); + ASTNodeID rightID = rightNode.getNodeID(); + if (rightID == ASTNodeID.IdentifierID) + { + IDefinition rightDef = rightNode.resolveType(project); + if (rightDef != null) + { + return SemanticUtils.isXMLish(rightDef, project); + } + } + leftNode = maen.getLeftOperandNode(); + return isLeftNodeXMLish(leftNode, project); + } + else if (leftID == ASTNodeID.FunctionCallID) + { + FunctionCallNode fcn = (FunctionCallNode)leftNode; + String fname = fcn.getFunctionName(); + if (fname.equals("XML") || fname.equals("XMLList")) + return true; + } + else if (leftID == ASTNodeID.Op_AsID) + { + BinaryOperatorAsNode boan = (BinaryOperatorAsNode)leftNode; + String fname = ((IdentifierNode)boan.getChild(1)).getName(); + if (fname.equals("XML") || fname.equals("XMLList")) + return true; + } + else if (leftID == ASTNodeID.ArrayIndexExpressionID) + { + leftNode = (IExpressionNode)(leftNode.getChild(0)); + IDefinition leftDef = leftNode.resolveType(project); + if (leftDef != null) + return SemanticUtils.isXMLish(leftDef, project); + + } + else if (leftID == ASTNodeID.E4XFilterID) + return true; + return false; + } + + public static boolean needsXMLQNameArgumentsPatch(IFunctionCallNode node, ICompilerProject project) { + if (node.getNameNode() instanceof MemberAccessExpressionNode + && ((MemberAccessExpressionNode)node.getNameNode()).getRightOperandNode() instanceof IdentifierNode) { + String methodName = ((IdentifierNode)((MemberAccessExpressionNode)node.getNameNode()).getRightOperandNode()).getName(); + if ("child".equals(methodName) || "descendants".equals(methodName) || "attribute".equals(methodName)) { + //double check it is not a method with the same name on a non-XMLish class + IASNode leftNode = ((MemberAccessExpressionNode)node.getNameNode()).getLeftOperandNode(); + boolean isXML = leftNode instanceof MemberAccessExpressionNode + && isLeftNodeXMLish((MemberAccessExpressionNode) leftNode, project); + if (!isXML) { + isXML = leftNode instanceof IExpressionNode && isXML((IExpressionNode)leftNode, project); + } + if (isXML) { + //check argumentsNode + if (node.getArgumentsNode().getChildCount() == 1) { + IDefinition def = node.getArgumentNodes()[0].resolveType(project); + if (def != null && def.getQualifiedName().equals("QName")) { + return true; + } + } + } + } + } + return false; + } + + public static void createDefaultNamespaceArg(ContainerNode argsNode, int position, IExpressionNode defaultNamespace) { + argsNode.addChild((NodeBase) defaultNamespace, position); + ((NodeBase) defaultNamespace).setParent(argsNode); + } } diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java index 23d50fa..4f600f3 100644 --- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleGlobalClasses.java @@ -1182,7 +1182,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses IASNode parentNode = node.getParent(); node = (IVariableNode) parentNode.getChild(1); asBlockWalker.visitVariable(node); - assertOut("var /** @type {XMLList} */ b = a.descendants('grandchild').filter(function(node){return (node.attribute('attr2') == 'fish')})"); + assertOut("var /** @type {XMLList} */ b = a.descendants('grandchild').filter(function(/** @type {XML} */ node){return (node.attribute('attr2') == 'fish')})"); } @Test @@ -1192,7 +1192,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses IASNode parentNode = node.getParent(); node = (IVariableNode) parentNode.getChild(1); asBlockWalker.visitVariable(node); - assertOut("var /** @type {XMLList} */ b = a.descendants('grandchild').filter(function(node){return (node.child('year') == '2016')})"); + assertOut("var /** @type {XMLList} */ b = a.descendants('grandchild').filter(function(/** @type {XML} */ node){return (node.child('year') == '2016')})"); } @Test @@ -1200,7 +1200,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses { IBinaryOperatorNode node = (IBinaryOperatorNode)getNode("private var attribute:Function; private function test() {var a:XMLList; a = a.(attribute('name').length())};", IBinaryOperatorNode.class, WRAP_LEVEL_CLASS); asBlockWalker.visitBinaryOperator(node); - assertOut("a = a.filter(function(node){return (node.attribute('name').length())})"); + assertOut("a = a.filter(function(/** @type {XML} */ node){return (node.attribute('name').length())})"); } @Test @@ -1264,7 +1264,7 @@ public class TestRoyaleGlobalClasses extends TestGoogGlobalClasses { IBinaryOperatorNode node = getBinaryNode("var a:XMLList;a.(@id==3).@height = '100px'"); asBlockWalker.visitBinaryOperator(node); - assertOut("a.filter(function(node){return (node.attribute('id') == 3)}).setAttribute('height', '100px')"); + assertOut("a.filter(function(/** @type {XML} */ node){return (node.attribute('id') == 3)}).setAttribute('height', '100px')"); } @Test diff --git a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java index d71b6d6..a898440 100644 --- a/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java +++ b/compiler-jx/src/test/java/org/apache/royale/compiler/internal/codegen/js/royale/TestRoyaleStatements.java @@ -59,7 +59,7 @@ public class TestRoyaleStatements extends TestGoogStatements INamespaceNode node = (INamespaceNode) getNode("public namespace foo;", INamespaceNode.class, WRAP_LEVEL_NONE); asBlockWalker.visitNamespace(node); - assertOut("foo = new Namespace('foo');"); + assertOut("foo = new Namespace('foo')"); } @Test @@ -68,7 +68,7 @@ public class TestRoyaleStatements extends TestGoogStatements INamespaceNode node = (INamespaceNode) getNode("public namespace foo = 'bar';", INamespaceNode.class, WRAP_LEVEL_NONE); asBlockWalker.visitNamespace(node); - assertOut("foo = new Namespace('bar');"); + assertOut("foo = new Namespace('bar')"); } @Test
