| /* |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| */ |
| |
| package org.apache.royale.compiler.internal.codegen.js.jx; |
| |
| import org.apache.royale.compiler.codegen.IASGlobalFunctionConstants; |
| import org.apache.royale.compiler.codegen.IDocEmitter; |
| import org.apache.royale.compiler.codegen.ISubEmitter; |
| import org.apache.royale.compiler.codegen.js.IJSEmitter; |
| import org.apache.royale.compiler.common.SourceLocation; |
| import org.apache.royale.compiler.constants.IASLanguageConstants; |
| import org.apache.royale.compiler.constants.IASLanguageConstants.BuiltinType; |
| import org.apache.royale.compiler.definitions.IDefinition; |
| import org.apache.royale.compiler.definitions.ITypeDefinition; |
| import org.apache.royale.compiler.internal.codegen.as.ASEmitterTokens; |
| import org.apache.royale.compiler.internal.codegen.js.JSSessionModel; |
| import org.apache.royale.compiler.internal.codegen.js.JSSubEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleDocEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitter; |
| import org.apache.royale.compiler.internal.codegen.js.royale.JSRoyaleEmitterTokens; |
| import org.apache.royale.compiler.internal.codegen.js.utils.EmitterUtils; |
| import org.apache.royale.compiler.internal.definitions.*; |
| import org.apache.royale.compiler.internal.projects.RoyaleJSProject; |
| import org.apache.royale.compiler.internal.tree.as.*; |
| import org.apache.royale.compiler.problems.TooFewFunctionParametersProblem; |
| import org.apache.royale.compiler.problems.TooManyFunctionParametersProblem; |
| import org.apache.royale.compiler.projects.ICompilerProject; |
| import org.apache.royale.compiler.tree.ASTNodeID; |
| import org.apache.royale.compiler.tree.as.*; |
| import org.apache.royale.compiler.utils.NativeUtils; |
| |
| public class FunctionCallEmitter extends JSSubEmitter implements ISubEmitter<IFunctionCallNode> |
| { |
| |
| public FunctionCallEmitter(IJSEmitter emitter) |
| { |
| super(emitter); |
| } |
| |
| @Override |
| public void emit(IFunctionCallNode node) |
| { |
| // TODO (mschmalle) will remove this cast as more things get abstracted |
| JSRoyaleEmitter fjs = (JSRoyaleEmitter) getEmitter(); |
| IASNode cnode = node.getChild(0); |
| |
| if (cnode.getNodeID() == ASTNodeID.MemberAccessExpressionID) |
| cnode = cnode.getChild(0); |
| String postCallAppend = null; |
| ASTNodeID id = cnode.getNodeID(); |
| if (id != ASTNodeID.SuperID) |
| { |
| IDefinition def = null; |
| IExpressionNode nameNode = node.getNameNode(); |
| def = nameNode.resolve(getProject()); |
| |
| boolean isClassCast = false; |
| boolean wrapResolve = false; |
| if (node.isNewExpression()) |
| { |
| boolean omitNew = false; |
| if (nameNode instanceof IdentifierNode |
| && (((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.String) |
| || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Boolean) |
| || ((IdentifierNode) nameNode).getName().equals(IASLanguageConstants.Number))) |
| { |
| omitNew = true; |
| } |
| |
| if (!((node.getChild(1) instanceof VectorLiteralNode))) |
| { |
| if (!omitNew |
| && ((def == null |
| || !(def.getBaseName().equals(IASGlobalFunctionConstants._int) || def.getBaseName().equals(IASGlobalFunctionConstants.uint))) |
| && !(def instanceof AppliedVectorDefinition && ( |
| ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass()!= null |
| && ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass().equals("Array")) |
| )) |
| ) |
| { |
| if (getProject() instanceof RoyaleJSProject |
| && nameNode.resolveType(getProject()) != null |
| && nameNode.resolveType(getProject()).getQualifiedName().equals("Class")) { |
| |
| wrapResolve = shouldResolveUncertain(nameNode, false); |
| |
| if (wrapResolve) { |
| ((RoyaleJSProject) getProject()).needLanguage = true; |
| getModel().needLanguage = true; |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write("resolveUncertain"); |
| write(ASEmitterTokens.PAREN_OPEN); |
| } |
| } |
| startMapping(node.getNewKeywordNode()); |
| writeToken(ASEmitterTokens.NEW); |
| endMapping(node.getNewKeywordNode()); |
| } |
| } |
| else |
| { |
| VectorLiteralNode vectorLiteralNode = (VectorLiteralNode) node.getChild(1); |
| String vectorEmulationClass = (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass()); |
| SourceLocation mappingLocation; |
| String elementClassName; |
| IDefinition elementClass = (((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject())); |
| elementClassName = getEmitter().formatQualifiedName(elementClass.getQualifiedName()); |
| if (vectorEmulationClass != null) |
| { |
| if (!vectorEmulationClass.equals("Array")) { |
| //Explanation: |
| //this was how it was originally set up, but it assumes the constructor of the emulation |
| //class can handle first argument being an Array or numeric value... |
| writeToken(ASEmitterTokens.NEW); |
| write(vectorEmulationClass); |
| write(ASEmitterTokens.PAREN_OPEN); |
| }// otherwise.... if 'Array' is the emulation class, then just use the literal content |
| } else { |
| //no 'new' output in this case, just coercion, so map from the start of 'new' |
| startMapping(node); |
| write(JSRoyaleEmitterTokens.SYNTH_VECTOR); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| //the element type of the Vector: |
| write(elementClassName); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| write(ASEmitterTokens.SQUARE_OPEN); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write("coerce"); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.SQUARE_CLOSE); |
| mappingLocation = new SourceLocation(vectorLiteralNode.getCollectionTypeNode()); |
| mappingLocation.setEndColumn(mappingLocation.getEndColumn() + 1); |
| endMapping(mappingLocation); |
| write(ASEmitterTokens.PAREN_OPEN); |
| if (getProject() instanceof RoyaleJSProject) |
| ((RoyaleJSProject)getProject()).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| |
| } |
| mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode()); |
| if (mappingLocation.getColumn()>0) mappingLocation.setColumn(mappingLocation.getColumn() -1); |
| mappingLocation.setEndColumn(mappingLocation.getColumn()+1); |
| startMapping(mappingLocation); |
| write("["); |
| |
| endMapping(mappingLocation); |
| ContainerNode contentsNode = vectorLiteralNode.getContentsNode(); |
| int len = contentsNode.getChildCount(); |
| for (int i = 0; i < len; i++) |
| { |
| getWalker().walk(contentsNode.getChild(i)); |
| if (i < len - 1) |
| { |
| writeToken(ASEmitterTokens.COMMA); |
| } |
| } |
| mappingLocation = new SourceLocation(vectorLiteralNode.getContentsNode()); |
| mappingLocation.setLine(vectorLiteralNode.getContentsNode().getEndLine()); |
| mappingLocation.setColumn(vectorLiteralNode.getContentsNode().getEndColumn()); |
| mappingLocation.setEndColumn(mappingLocation.getColumn() + 1); |
| startMapping(mappingLocation); |
| write("]"); |
| endMapping(mappingLocation); |
| if (vectorEmulationClass != null) |
| { |
| if (!vectorEmulationClass.equals("Array")) { |
| writeToken(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(elementClassName); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| } else { |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| return; |
| } |
| } |
| else |
| { |
| def = node.getNameNode().resolve(getProject()); |
| |
| isClassCast = def != null && (def instanceof ClassDefinition |
| || def instanceof InterfaceDefinition |
| || ( def instanceof VariableDefinition && ((VariableDefinition) def).resolveType(getProject()).getBaseName().equals("Class"))) |
| && !(NativeUtils.isJSNative(def.getBaseName())) |
| && !def.getBaseName().equals(IASLanguageConstants.XML) |
| && !def.getBaseName().equals(IASLanguageConstants.XMLList); |
| |
| } |
| |
| if (node.isNewExpression()) |
| { |
| def = node.resolveCalledExpression(getProject()); |
| // all new calls to a class should be fully qualified names |
| if (def instanceof ClassDefinition) |
| { |
| startMapping(nameNode); |
| boolean isInt = def.getBaseName().equals(IASGlobalFunctionConstants._int); |
| if (isInt || def.getBaseName().equals(IASGlobalFunctionConstants.uint)) |
| { |
| ICompilerProject project = this.getProject(); |
| if (project instanceof RoyaleJSProject) |
| ((RoyaleJSProject) project).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| if (isInt) |
| write(JSRoyaleEmitterTokens.UNDERSCORE); |
| write(def.getQualifiedName()); |
| endMapping(nameNode); |
| } |
| else |
| { |
| write(getEmitter().formatQualifiedName(def.getQualifiedName())); |
| endMapping(nameNode); |
| } |
| } |
| else |
| { |
| // wrap "new someFunctionCall(args)" in parens so the |
| // function call gets parsed and evaluated before new |
| // otherwise it just looks like any other "new function" |
| // in JS. |
| if (nameNode.hasParenthesis()) |
| write(ASEmitterTokens.PAREN_OPEN); |
| // I think we still need this for "new someVarOfTypeClass" |
| getEmitter().getWalker().walk(nameNode); |
| if (nameNode.hasParenthesis()) |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| if ( def instanceof AppliedVectorDefinition |
| && (fjs.getWalker().getProject() instanceof RoyaleJSProject) |
| && (((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass() != null)) |
| { |
| ContainerNode args = node.getArgumentsNode(); |
| String vectorEmulationClass = ((RoyaleJSProject)fjs.getWalker().getProject()).config.getJsVectorEmulationClass(); |
| if (args.getChildCount() == 0) |
| { |
| if (vectorEmulationClass.equals("Array")) { |
| write(ASEmitterTokens.SQUARE_OPEN); |
| write(ASEmitterTokens.SQUARE_CLOSE); |
| } else { |
| write(ASEmitterTokens.PAREN_OPEN); |
| write(ASEmitterTokens.SQUARE_OPEN); |
| write(ASEmitterTokens.SQUARE_CLOSE); |
| write(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(((AppliedVectorDefinition)def).resolveElementType(getWalker().getProject()).getQualifiedName()); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| } else { |
| if (vectorEmulationClass.equals("Array")) { |
| if (getProject() instanceof RoyaleJSProject) |
| ((RoyaleJSProject) getProject()).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| startMapping(node.getNameNode()); |
| write("arrayAsVector"); |
| endMapping(node.getNameNode()); |
| } |
| startMapping(node); |
| write(ASEmitterTokens.PAREN_OPEN); |
| endMapping(node); |
| getWalker().walk(args.getChild(0)); |
| write(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SPACE); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(((AppliedVectorDefinition) def).resolveElementType(getWalker().getProject()).getQualifiedName()); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| if (args.getChildCount() == 2 && !vectorEmulationClass.equals("Array")) { |
| IASNode second = args.getChild(1); |
| if (second instanceof IExpressionNode) { |
| ITypeDefinition secondType = |
| ((IExpressionNode) second).resolveType(fjs.getWalker().getProject()); |
| if (fjs.getWalker().getProject().getBuiltinType(BuiltinType.BOOLEAN).equals(secondType)) { |
| write(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SPACE); |
| getWalker().walk(second); |
| } |
| } |
| } |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| } else { |
| getEmitter().emitArguments(node.getArgumentsNode()); |
| } |
| //end wrap resolve |
| if (wrapResolve) { |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| } |
| else if (!isClassCast) |
| { |
| if (def != null) |
| { |
| boolean isInt = def.getBaseName().equals(IASGlobalFunctionConstants._int); |
| boolean isTrace = def.getParent() == null && def.getBaseName().equals(IASGlobalFunctionConstants.trace); |
| if (isInt || isTrace |
| || def.getBaseName().equals(IASGlobalFunctionConstants.uint)) |
| { |
| ICompilerProject project = this.getProject(); |
| if (project instanceof RoyaleJSProject) |
| ((RoyaleJSProject) project).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| startMapping(node.getNameNode()); |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| if (isInt) |
| write(JSRoyaleEmitterTokens.UNDERSCORE); |
| endMapping(node.getNameNode()); |
| } |
| else if (def.getBaseName().equals("sortOn")) |
| { |
| if (def.getParent() != null && |
| def.getParent().getQualifiedName().equals("Array")) |
| { |
| ICompilerProject project = this.getProject(); |
| if (project instanceof RoyaleJSProject) |
| ((RoyaleJSProject) project).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write("sortOn"); |
| IContainerNode newArgs = EmitterUtils.insertArgumentsBefore(node.getArgumentsNode(), cnode); |
| fjs.emitArguments(newArgs); |
| return; |
| } |
| } |
| else if (def.getBaseName().equals("sort")) |
| { |
| if (def.getParent() != null) { |
| if (def.getParent().getQualifiedName().equals("Array") |
| || (node.getNameNode() instanceof MemberAccessExpressionNode |
| && (((MemberAccessExpressionNode) node.getNameNode()).getLeftOperandNode().resolveType(getProject()) instanceof AppliedVectorDefinition) |
| && getProject() instanceof RoyaleJSProject |
| && (((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass() == null |
| || ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass().equals("Array")))) |
| { |
| IExpressionNode args[] = node.getArgumentNodes(); |
| if (args.length > 0) |
| { |
| IExpressionNode optionsParamCheck = args.length == 1 ? args[0] : args[1]; |
| ICompilerProject project = this.getProject(); |
| IDefinition paramCheck = optionsParamCheck.resolveType(project); |
| |
| if (paramCheck.getBaseName().equals(IASLanguageConstants._int) |
| || paramCheck.getBaseName().equals(IASLanguageConstants.uint) |
| || paramCheck.getBaseName().equals(IASLanguageConstants.Number)) |
| { |
| //deal with specific numeric option argument variations |
| //either: Array.sort(option:uint) or Array.sort(compareFunction:Function, option:uint) |
| //use our Language sort implementation to support these actionscript-specific method signatures |
| if (project instanceof RoyaleJSProject) |
| ((RoyaleJSProject) project).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write("sort"); |
| IContainerNode newArgs = EmitterUtils.insertArgumentsBefore(node.getArgumentsNode(), cnode); |
| fjs.emitArguments(newArgs); |
| return; |
| } |
| } |
| } |
| } |
| |
| } |
| else if ((def.getBaseName().equals("insertAt") |
| || def.getBaseName().equals("removeAt")) |
| && def.getParent() instanceof AppliedVectorDefinition |
| && ((getProject() instanceof RoyaleJSProject) && ( |
| ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass() == null |
| || ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass().equals("Array"))) |
| ) { |
| |
| if ((((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass() != null) |
| && ((RoyaleJSProject)getProject()).config.getJsVectorEmulationClass().equals("Array")) { |
| //use a similar approach to regular 'Array' insertAt/removeAt |
| //for Array Vector emulation only (not for other custom classes) |
| //replace the insertAt/removeAt method with 'splice' |
| IdentifierNode splice = new IdentifierNode("splice"); |
| splice.setSourceLocation(((MemberAccessExpressionNode)node.getNameNode()).getRightOperandNode()); |
| splice.setParent((MemberAccessExpressionNode)node.getNameNode()); |
| ((MemberAccessExpressionNode)node.getNameNode()).setRightOperandNode(splice); |
| NumericLiteralNode spliceArg; |
| if (def.getBaseName().equals("insertAt")) { |
| //insertAt |
| spliceArg = new NumericLiteralNode("0"); |
| //This works like 'insertAt' itself, pushing the insertee to 3rd position (correct position): |
| node.getArgumentsNode().addChild(spliceArg, 1); |
| } else { |
| //removeAt |
| spliceArg = new NumericLiteralNode("1"); |
| node.getArgumentsNode().addChild(spliceArg, 1); |
| postCallAppend = "[0]"; |
| } |
| } else { |
| //default Vector implementation |
| //unlike Array implementation of these methods, the synthetic Vector implementation supports these methods at runtime, |
| //and they behave differently with fixed length vectors compared to the native 'splice' method output which is used to |
| //support them in Array, however they are not protected from GCL renaming in release builds by any actual class definition, |
| //so we explicitly 'protect' them here by using DynamicAccess instead of MemberAccess |
| ExpressionNodeBase leftSide = (ExpressionNodeBase)(((BinaryOperatorNodeBase) (node.getNameNode())).getLeftOperandNode()); |
| LiteralNode dynamicName = new LiteralNode(ILiteralNode.LiteralType.STRING, "'" + def.getBaseName() + "'"); |
| dynamicName.setSourceLocation(((BinaryOperatorNodeBase) (node.getNameNode())).getRightOperandNode()); |
| DynamicAccessNode replacement = new DynamicAccessNode(leftSide); |
| leftSide.setParent(replacement); |
| replacement.setSourceLocation(node.getNameNode()); |
| replacement.setRightOperandNode(dynamicName); |
| dynamicName.setParent(replacement); |
| |
| FunctionCallNode replacer = new FunctionCallNode(replacement) ; |
| replacement.setParent(replacer); |
| IExpressionNode[] args = node.getArgumentNodes(); |
| for (IExpressionNode arg : args) { |
| replacer.getArgumentsNode().addItem((NodeBase) arg); |
| } |
| replacer.getArgumentsNode().setParent(replacer); |
| replacer.getArgumentsNode().setSourceLocation(node.getArgumentsNode()); |
| replacer.setParent((NodeBase) node.getParent()); |
| //swap it out |
| node = replacer; |
| } |
| } |
| else if (def instanceof AppliedVectorDefinition) |
| { |
| IExpressionNode[] argumentNodes = node.getArgumentNodes(); |
| int len = argumentNodes.length; |
| if (len == 0) |
| { |
| getWalker().getProject().getProblems().add(new TooFewFunctionParametersProblem(node, 1)); |
| } |
| else if (len > 1) |
| { |
| getWalker().getProject().getProblems().add(new TooManyFunctionParametersProblem(node, 1)); |
| } |
| else |
| { |
| String elementClassName = getEmitter().formatQualifiedName(((TypedExpressionNode)nameNode).getTypeNode().resolve(getProject()).getQualifiedName()); |
| if (getProject() instanceof RoyaleJSProject |
| && ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass()!= null) { |
| String vectorEmulationClass = ((RoyaleJSProject) getProject()).config.getJsVectorEmulationClass(); |
| if (vectorEmulationClass.equals("Array")) { |
| //just do a slice copy of the array which is the first argument |
| getWalker().walk(node.getArgumentsNode().getChild(0)); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write("slice"); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } else { |
| //assume the emulation class can handle an array or numeric value for first constructor arg... |
| writeToken(ASEmitterTokens.NEW); |
| startMapping(node.getNameNode()); |
| write(vectorEmulationClass); |
| endMapping(node.getNameNode()); |
| write(ASEmitterTokens.PAREN_OPEN); |
| getWalker().walk(node.getArgumentsNode().getChild(0)); |
| writeToken(ASEmitterTokens.COMMA); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| //the element type of the Vector: |
| write(elementClassName); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| } else { |
| //default Vector implementation |
| startMapping(node.getNameNode()); |
| write(JSRoyaleEmitterTokens.SYNTH_VECTOR); |
| write(ASEmitterTokens.PAREN_OPEN); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| //the element type of the Vector: |
| write(elementClassName); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.PAREN_CLOSE); |
| write(ASEmitterTokens.SQUARE_OPEN); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write("coerce"); |
| write(ASEmitterTokens.SINGLE_QUOTE); |
| write(ASEmitterTokens.SQUARE_CLOSE); |
| endMapping(node.getNameNode()); |
| |
| getEmitter().emitArguments(node.getArgumentsNode()); |
| if (getProject() instanceof RoyaleJSProject) |
| ((RoyaleJSProject)getProject()).needLanguage = true; |
| getEmitter().getModel().needLanguage = true; |
| } |
| } |
| return; |
| } |
| else if (def.getBaseName().equals(IASLanguageConstants.XML)) |
| { |
| write("XML.conversion"); |
| getEmitter().emitArguments(node.getArgumentsNode()); |
| return; |
| } |
| else if (def.getBaseName().equals(IASLanguageConstants.XMLList)) |
| { |
| write("XMLList.conversion"); |
| getEmitter().emitArguments(node.getArgumentsNode()); |
| return; |
| } |
| else if (def.getQualifiedName().equals(IASLanguageConstants.Object)) { |
| //'resolveUncertain' always output here |
| //unless a) there are no arguments |
| //or b) it is *explicitly* suppressed for 'Object' |
| if (node.getArgumentNodes().length > 0) { |
| if (shouldResolveUncertain(nameNode, true)) { |
| wrapResolve = true; |
| ((RoyaleJSProject) getProject()).needLanguage = true; |
| getModel().needLanguage = true; |
| write(JSRoyaleEmitterTokens.LANGUAGE_QNAME); |
| write(ASEmitterTokens.MEMBER_ACCESS); |
| write("resolveUncertain"); |
| write(ASEmitterTokens.PAREN_OPEN); |
| } |
| } |
| } |
| else if (nameNode.getNodeID() == ASTNodeID.NamespaceAccessExpressionID && def instanceof FunctionDefinition) |
| { |
| if (fjs.isCustomNamespace((FunctionDefinition)def)) |
| { |
| write(ASEmitterTokens.THIS); |
| NamespaceIdentifierNode nin = (NamespaceIdentifierNode)nameNode.getChild(0); |
| NamespaceDefinition nsDef = (NamespaceDefinition)nin.resolve(getProject()); |
| IdentifierNode idNode = (IdentifierNode)nameNode.getChild(1); |
| String propName = idNode.getName(); |
| fjs.formatQualifiedName(nsDef.getQualifiedName()); // register with used names |
| String s = nsDef.getURI(); |
| write(JSRoyaleEmitter.formatNamespacedProperty(s, propName, true)); |
| getEmitter().emitArguments(node.getArgumentsNode()); |
| return; |
| } |
| } |
| } |
| else if (nameNode.getNodeID() == ASTNodeID.MemberAccessExpressionID && ((JSRoyaleEmitter)getEmitter()).isProxy(((MemberAccessExpressionNode)nameNode).getLeftOperandNode()) && def == null) |
| { |
| MemberAccessExpressionNode mae = (MemberAccessExpressionNode)nameNode; |
| getWalker().walk(mae.getLeftOperandNode()); |
| write(".callProperty('"); |
| getWalker().walk(mae.getRightOperandNode()); |
| write("'"); |
| IExpressionNode[] args = node.getArgumentNodes(); |
| int n = args.length; |
| if (n > 0) |
| { |
| for (int i = 0; i < n; i++) |
| { |
| write(", "); |
| getWalker().walk(args[i]); |
| } |
| } |
| write(ASEmitterTokens.PAREN_CLOSE); |
| return; |
| } |
| getWalker().walk(node.getNameNode()); |
| |
| getEmitter().emitArguments(node.getArgumentsNode()); |
| |
| if (postCallAppend != null) { |
| write(postCallAppend); |
| } |
| //end wrap resolve |
| if (wrapResolve) { |
| write(ASEmitterTokens.PAREN_CLOSE); |
| } |
| } |
| else //function-style cast |
| { |
| fjs.emitIsAs(node, node.getArgumentNodes()[0], node.getNameNode(), ASTNodeID.Op_AsID, true); |
| } |
| } |
| else |
| { |
| fjs.emitSuperCall(node, JSSessionModel.SUPER_FUNCTION_CALL); |
| } |
| } |
| |
| |
| private boolean shouldResolveUncertain(IExpressionNode nameNode, boolean forceExplicit) { |
| //default if not avoided globally |
| boolean should = ((RoyaleJSProject)getProject()).config.getJsResolveUncertain(); |
| //just in case: |
| if (!(getProject() instanceof RoyaleJSProject)) return false; |
| |
| IDocEmitter docEmitter = getEmitter().getDocEmitter(); |
| if (docEmitter instanceof JSRoyaleDocEmitter) |
| { |
| JSRoyaleDocEmitter royaleDocEmitter = (JSRoyaleDocEmitter) docEmitter; |
| //look for local boolean toggle, unless forceExplicit is set |
| boolean suppress = !forceExplicit && royaleDocEmitter.getLocalSettingAsBoolean( |
| JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN, !should); |
| //if it is still on, look for sepcific/named 'off' setting based on name node |
| if (!suppress && nameNode !=null) { |
| //check to suppress for indvidual named node |
| if (nameNode instanceof IdentifierNode) { |
| suppress = royaleDocEmitter.getLocalSettingIncludesString(JSRoyaleEmitterTokens.SUPPRESS_RESOLVE_UNCERTAIN, ((IdentifierNode) nameNode).getName()); |
| } |
| } |
| should = !suppress; |
| } |
| return should; |
| } |
| |
| } |