http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitter.java new file mode 100644 index 0000000..e08fb84 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitter.java @@ -0,0 +1,1120 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.goog; + +import java.io.FilterWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.apache.flex.compiler.codegen.IASGlobalFunctionConstants.BuiltinType; +import org.apache.flex.compiler.codegen.js.goog.IJSGoogDocEmitter; +import org.apache.flex.compiler.codegen.js.goog.IJSGoogEmitter; +import org.apache.flex.compiler.common.ASModifier; +import org.apache.flex.compiler.common.ModifiersSet; +import org.apache.flex.compiler.constants.IASLanguageConstants; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.definitions.IFunctionDefinition; +import org.apache.flex.compiler.definitions.IPackageDefinition; +import org.apache.flex.compiler.definitions.ITypeDefinition; +import org.apache.flex.compiler.definitions.IVariableDefinition; +import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSEmitter; +import org.apache.flex.compiler.internal.codegen.js.JSEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSSessionModel; +import org.apache.flex.compiler.internal.codegen.js.utils.EmitterUtils; +import org.apache.flex.compiler.internal.definitions.AccessorDefinition; +import org.apache.flex.compiler.internal.definitions.FunctionDefinition; +import org.apache.flex.compiler.internal.scopes.PackageScope; +import org.apache.flex.compiler.internal.tree.as.ChainedVariableNode; +import org.apache.flex.compiler.internal.tree.as.FunctionCallNode; +import org.apache.flex.compiler.internal.tree.as.FunctionNode; +import org.apache.flex.compiler.internal.tree.as.MemberAccessExpressionNode; +import org.apache.flex.compiler.problems.ICompilerProblem; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.scopes.IASScope; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IAccessorNode; +import org.apache.flex.compiler.tree.as.IBinaryOperatorNode; +import org.apache.flex.compiler.tree.as.IClassNode; +import org.apache.flex.compiler.tree.as.IContainerNode; +import org.apache.flex.compiler.tree.as.IDefinitionNode; +import org.apache.flex.compiler.tree.as.IEmbedNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IForLoopNode; +import org.apache.flex.compiler.tree.as.IFunctionCallNode; +import org.apache.flex.compiler.tree.as.IFunctionNode; +import org.apache.flex.compiler.tree.as.IGetterNode; +import org.apache.flex.compiler.tree.as.IIdentifierNode; +import org.apache.flex.compiler.tree.as.IInterfaceNode; +import org.apache.flex.compiler.tree.as.INamespaceAccessExpressionNode; +import org.apache.flex.compiler.tree.as.IParameterNode; +import org.apache.flex.compiler.tree.as.ISetterNode; +import org.apache.flex.compiler.tree.as.ITypeNode; +import org.apache.flex.compiler.tree.as.IVariableExpressionNode; +import org.apache.flex.compiler.tree.as.IVariableNode; +import org.apache.flex.compiler.utils.ASNodeUtils; + +/** + * Concrete implementation of the 'goog' JavaScript production. + * + * @author Michael Schmalle + * @author Erik de Bruin + */ +public class JSGoogEmitter extends JSEmitter implements IJSGoogEmitter +{ + protected List<String> propertyNames = new ArrayList<String>(); + + // TODO (mschmalle) Remove this (not used in JSFlexJSEmitter and JSGoogEmitter anymore) + public ICompilerProject project; + + private JSGoogDocEmitter docEmitter; + + // TODO (mschmalle) Fix; this is not using the backend doc strategy for replacement + @Override + public IJSGoogDocEmitter getDocEmitter() + { + if (docEmitter == null) + docEmitter = new JSGoogDocEmitter(this); + return docEmitter; + } + + @Override + public String formatQualifiedName(String name) + { + return name; + } + + //-------------------------------------------------------------------------- + // Package Level + //-------------------------------------------------------------------------- + + // XXX DEAD + @Override + public void emitPackageHeader(IPackageDefinition definition) + { + IASScope containedScope = definition.getContainedScope(); + ITypeDefinition type = findType(containedScope.getAllLocalDefinitions()); + if (type == null) + return; + + /* goog.provide('x');\n\n */ + write(JSGoogEmitterTokens.GOOG_PROVIDE); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.SINGLE_QUOTE); + write(type.getQualifiedName()); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + writeNewline(); + } + + // XXX DEAD + @Override + public void emitPackageHeaderContents(IPackageDefinition definition) + { + PackageScope containedScope = (PackageScope) definition + .getContainedScope(); + + ITypeDefinition type = findType(containedScope.getAllLocalDefinitions()); + if (type == null) + return; + + List<String> list = EmitterUtils.resolveImports(type); + for (String imp : list) + { + if (imp.indexOf(JSGoogEmitterTokens.AS3.getToken()) != -1) + continue; + + /* goog.require('x');\n */ + write(JSGoogEmitterTokens.GOOG_REQUIRE); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.SINGLE_QUOTE); + write(imp); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + } + + // (erikdebruin) only write 'closing' line break when there are + // actually imports... + if (list.size() > 1 + || (list.size() == 1 && list.get(0).indexOf( + JSGoogEmitterTokens.AS3.getToken()) == -1)) + { + writeNewline(); + } + } + + // XXX DEAD + @Override + public void emitPackageContents(IPackageDefinition definition) + { + IASScope containedScope = definition.getContainedScope(); + + ITypeDefinition type = EmitterUtils.findType(containedScope.getAllLocalDefinitions()); + if (type != null) + { + ITypeNode tnode = EmitterUtils.findTypeNode(definition.getNode()); + if (tnode != null) + { + getWalker().walk(tnode); // IClassNode | IInterfaceNode + } + return; + } + + IFunctionDefinition func = EmitterUtils.findFunction(containedScope.getAllLocalDefinitions()); + if (func != null) + { + IFunctionNode fnode = EmitterUtils.findFunctionNode(definition.getNode()); + if (fnode != null) + { + getWalker().walk(fnode); + } + return; + } + + IVariableDefinition variable = EmitterUtils.findVariable(containedScope.getAllLocalDefinitions()); + if (variable != null) + { + IVariableNode vnode = EmitterUtils.findVariableNode(definition.getNode()); + if (vnode != null) + { + getWalker().walk(vnode); + } + } + } + + // XXX DEAD + @Override + public void emitPackageFooter(IPackageDefinition definition) + { + } + + //-------------------------------------------------------------------------- + // Class + //-------------------------------------------------------------------------- + + // XXX DEAD + @Override + public void emitClass(IClassNode node) + { + IClassDefinition definition = node.getDefinition(); + getModel().setCurrentClass(definition); + + IFunctionDefinition ctorDefinition = definition.getConstructor(); + + // Static-only (Singleton) classes may not have a constructor + if (ctorDefinition != null) + { + IFunctionNode ctorNode = (IFunctionNode) ctorDefinition.getNode(); + if (ctorNode != null) + { + // constructor + emitMethod(ctorNode); + write(ASEmitterTokens.SEMICOLON); + } + else + { + String qname = definition.getQualifiedName(); + if (qname != null && !qname.equals("")) + { + write(qname); + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.EQUAL); + write(ASEmitterTokens.FUNCTION); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.PAREN_CLOSE); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + writeNewline(); + write(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.SEMICOLON); + } + } + } + + IDefinitionNode[] dnodes = node.getAllMemberNodes(); + for (IDefinitionNode dnode : dnodes) + { + if (dnode.getNodeID() == ASTNodeID.VariableID) + { + writeNewline(); + writeNewline(); + emitField((IVariableNode) dnode); + write(ASEmitterTokens.SEMICOLON); + } + else if (dnode.getNodeID() == ASTNodeID.FunctionID) + { + if (!((IFunctionNode) dnode).isConstructor()) + { + writeNewline(); + writeNewline(); + emitMethod((IFunctionNode) dnode); + write(ASEmitterTokens.SEMICOLON); + } + } + else if (dnode.getNodeID() == ASTNodeID.GetterID + || dnode.getNodeID() == ASTNodeID.SetterID) + { + writeNewline(); + writeNewline(); + emitAccessors((IAccessorNode) dnode); + write(ASEmitterTokens.SEMICOLON); + } + } + } + + // XXX Dead [InterfaceEmitter] + @Override + public void emitInterface(IInterfaceNode node) + { + ICompilerProject project = getWalker().getProject(); + + getDocEmitter().emitInterfaceDoc(node, project); + + String qname = node.getQualifiedName(); + if (qname != null && !qname.equals("")) + { + write(formatQualifiedName(qname)); + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.EQUAL); + write(ASEmitterTokens.FUNCTION); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.PAREN_CLOSE); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + writeNewline(); + write(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.SEMICOLON); + } + + final IDefinitionNode[] members = node.getAllMemberDefinitionNodes(); + for (IDefinitionNode mnode : members) + { + boolean isAccessor = mnode.getNodeID() == ASTNodeID.GetterID + || mnode.getNodeID() == ASTNodeID.SetterID; + + if (!isAccessor || !propertyNames.contains(qname)) + { + writeNewline(); + + write(formatQualifiedName(qname)); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.PROTOTYPE); + write(ASEmitterTokens.MEMBER_ACCESS); + write(mnode.getQualifiedName()); + + if (isAccessor && !propertyNames.contains(qname)) + { + propertyNames.add(qname); + } + else + { + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.EQUAL); + write(ASEmitterTokens.FUNCTION); + + emitParameters(((IFunctionNode) mnode).getParametersContainerNode()); + + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + writeNewline(); + write(ASEmitterTokens.BLOCK_CLOSE); + } + + write(ASEmitterTokens.SEMICOLON); + } + } + } + + // XXX Dead + @Override + public void emitField(IVariableNode node) + { + IClassDefinition definition = EmitterUtils.getClassDefinition(node); + + IDefinition def = null; + IExpressionNode enode = node.getVariableTypeNode();//getAssignedValueNode(); + if (enode != null) + def = enode.resolveType(getWalker().getProject()); + + getDocEmitter().emitFieldDoc(node, def, getWalker().getProject()); + + /* x.prototype.y = z */ + + ModifiersSet modifierSet = node.getDefinition().getModifiers(); + String root = ""; + if (modifierSet != null && !modifierSet.hasModifier(ASModifier.STATIC)) + { + root = JSEmitterTokens.PROTOTYPE.getToken(); + root += ASEmitterTokens.MEMBER_ACCESS.getToken(); + } + write(definition.getQualifiedName() + + ASEmitterTokens.MEMBER_ACCESS.getToken() + root + + node.getName()); + + IExpressionNode vnode = node.getAssignedValueNode(); + if (vnode != null) + { + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.EQUAL); + getWalker().walk(vnode); + } + + if (!(node instanceof ChainedVariableNode)) + { + int len = node.getChildCount(); + for (int i = 0; i < len; i++) + { + IASNode child = node.getChild(i); + if (child instanceof ChainedVariableNode) + { + writeNewline(ASEmitterTokens.SEMICOLON); + writeNewline(); + emitField((IVariableNode) child); + } + } + } + } + + // XXX Dead [VarDeclarationEmitter] + @Override + public void emitVarDeclaration(IVariableNode node) + { + if (!(node instanceof ChainedVariableNode) && !node.isConst()) + { + emitMemberKeyword(node); + } + + IExpressionNode avnode = node.getAssignedValueNode(); + if (avnode != null) + { + IDefinition def = avnode.resolveType(getWalker().getProject()); + + String opcode = avnode.getNodeID().getParaphrase(); + if (opcode != "AnonymousFunction") + getDocEmitter().emitVarDoc(node, def, getWalker().getProject()); + } + else + { + getDocEmitter().emitVarDoc(node, null, getWalker().getProject()); + } + + emitDeclarationName(node); + if (avnode != null && !(avnode instanceof IEmbedNode)) + { + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.EQUAL); + emitAssignedValue(avnode); + } + + if (!(node instanceof ChainedVariableNode)) + { + // check for chained variables + int len = node.getChildCount(); + for (int i = 0; i < len; i++) + { + IASNode child = node.getChild(i); + if (child instanceof ChainedVariableNode) + { + writeToken(ASEmitterTokens.COMMA); + emitVarDeclaration((IVariableNode) child); + } + } + } + } + + // XXX Dead + public void emitAccessors(IAccessorNode node) + { + String qname = node.getQualifiedName(); + if (!propertyNames.contains(qname)) + { + emitField(node); + write(ASEmitterTokens.SEMICOLON); + writeNewline(); + writeNewline(); + + propertyNames.add(qname); + } + + if (node.getNodeID() == ASTNodeID.GetterID) + { + emitGetAccessor((IGetterNode) node); + } + else if (node.getNodeID() == ASTNodeID.SetterID) + { + emitSetAccessor((ISetterNode) node); + } + } + + // XXX Dead + @Override + public void emitGetAccessor(IGetterNode node) + { + emitObjectDefineProperty(node); + } + + // XXX Dead + @Override + public void emitSetAccessor(ISetterNode node) + { + emitObjectDefineProperty(node); + } + + // XXX Dead [MethodEmitter] + @Override + public void emitMethod(IFunctionNode node) + { + FunctionNode fn = (FunctionNode) node; + fn.parseFunctionBody(new ArrayList<ICompilerProblem>()); + + ICompilerProject project = getWalker().getProject(); + + getDocEmitter().emitMethodDoc(node, project); + + boolean isConstructor = node.isConstructor(); + + String qname = EmitterUtils.getTypeDefinition(node).getQualifiedName(); + if (qname != null && !qname.equals("")) + { + write(formatQualifiedName(qname)); + if (!isConstructor) + { + write(ASEmitterTokens.MEMBER_ACCESS); + if (!fn.hasModifier(ASModifier.STATIC)) + { + write(JSEmitterTokens.PROTOTYPE); + write(ASEmitterTokens.MEMBER_ACCESS); + } + } + } + + if (!isConstructor) + emitMemberName(node); + + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.EQUAL); + write(ASEmitterTokens.FUNCTION); + + emitParameters(node.getParametersContainerNode()); + + boolean hasSuperClass = EmitterUtils.hasSuperClass(project, node); + + if (isConstructor && node.getScopedNode().getChildCount() == 0) + { + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + if (hasSuperClass) + emitSuperCall(node, JSSessionModel.CONSTRUCTOR_EMPTY); + writeNewline(); + write(ASEmitterTokens.BLOCK_CLOSE); + } + + if (!isConstructor || node.getScopedNode().getChildCount() > 0) + emitMethodScope(node.getScopedNode()); + + if (isConstructor && hasSuperClass) + { + writeNewline(ASEmitterTokens.SEMICOLON); + write(JSGoogEmitterTokens.GOOG_INHERITS); + write(ASEmitterTokens.PAREN_OPEN); + write(formatQualifiedName(qname)); + writeToken(ASEmitterTokens.COMMA); + String sname = EmitterUtils.getSuperClassDefinition(node, project) + .getQualifiedName(); + write(formatQualifiedName(sname)); + write(ASEmitterTokens.PAREN_CLOSE); + } + } + + // XXX Dead + @Override + public void emitFunctionCall(IFunctionCallNode node) + { + IASNode cnode = node.getChild(0); + + if (cnode.getNodeID() == ASTNodeID.MemberAccessExpressionID) + cnode = cnode.getChild(0); + + ASTNodeID id = cnode.getNodeID(); + if (id != ASTNodeID.SuperID) + { + if (node.isNewExpression()) + { + writeToken(ASEmitterTokens.NEW); + } + + getWalker().walk(node.getNameNode()); + + emitArguments(node.getArgumentsNode()); + } + else + { + emitSuperCall(node, JSSessionModel.SUPER_FUNCTION_CALL); + } + } + + // XXX Dead + @Override + public void emitIdentifier(IIdentifierNode node) + { + ICompilerProject project = getWalker().getProject(); + + IClassNode cnode = (IClassNode) node + .getAncestorOfType(IClassNode.class); + + IDefinition def = node.resolve(project); + + ITypeDefinition type = node.resolveType(project); + + IASNode pnode = node.getParent(); + ASTNodeID inode = pnode.getNodeID(); + + boolean writeSelf = false; + if (cnode != null) + { + IDefinitionNode[] members = cnode.getAllMemberNodes(); + for (IDefinitionNode mnode : members) + { + if ((type != null && type.getQualifiedName().equalsIgnoreCase( + IASLanguageConstants.Function)) + || (def != null && def.getQualifiedName() + .equalsIgnoreCase(mnode.getQualifiedName()))) + { + if (!(pnode instanceof FunctionNode) + && inode != ASTNodeID.MemberAccessExpressionID) + { + writeSelf = true; + break; + } + else if (inode == ASTNodeID.MemberAccessExpressionID + && !def.isStatic()) + { + String tname = type.getQualifiedName(); + writeSelf = !tname.equalsIgnoreCase(cnode + .getQualifiedName()) + && !tname.equals(IASLanguageConstants.Function); + break; + } + } + } + } + + boolean isRunningInTestMode = cnode != null + && cnode.getQualifiedName().equalsIgnoreCase("FalconTest_A"); + if (writeSelf && !isRunningInTestMode) + { + write(JSGoogEmitterTokens.SELF); + write(ASEmitterTokens.MEMBER_ACCESS); + } + else + { + String pname = (type != null) ? type.getPackageName() : ""; + if (cnode != null && pname != "" + && !pname.equalsIgnoreCase(cnode.getPackageName()) + && inode != ASTNodeID.ArgumentID + && inode != ASTNodeID.VariableID + && inode != ASTNodeID.TypedExpressionID) + { + write(pname); + write(ASEmitterTokens.MEMBER_ACCESS); + } + } + + super.emitIdentifier(node); + } + + @Override + public void emitFunctionBlockHeader(IFunctionNode node) + { + IDefinition def = node.getDefinition(); + boolean isStatic = false; + if (def != null && def.isStatic()) + isStatic = true; + boolean isLocal = false; + if (node.getFunctionClassification() == IFunctionDefinition.FunctionClassification.LOCAL) + isLocal = true; + if (EmitterUtils.hasBody(node) && !isStatic && !isLocal) + emitSelfReference(node); + + if (node.isConstructor() + && EmitterUtils.hasSuperClass(getWalker().getProject(), node) + && !EmitterUtils.hasSuperCall(node.getScopedNode())) + emitSuperCall(node, JSSessionModel.CONSTRUCTOR_FULL); + + emitRestParameterCodeBlock(node); + + emitDefaultParameterCodeBlock(node); + } + + // XXX Dead + protected void emitSelfReference(IFunctionNode node) + { + writeToken(ASEmitterTokens.VAR); + writeToken(JSGoogEmitterTokens.SELF); + writeToken(ASEmitterTokens.EQUAL); + write(ASEmitterTokens.THIS); + writeNewline(ASEmitterTokens.SEMICOLON); + } + + // XXX Dead + protected void emitSuperCall(IASNode node, String type) + { + IFunctionNode fnode = (node instanceof IFunctionNode) ? (IFunctionNode) node + : null; + IFunctionCallNode fcnode = (node instanceof IFunctionCallNode) ? (FunctionCallNode) node + : null; + + if (type == JSSessionModel.CONSTRUCTOR_EMPTY) + { + indentPush(); + writeNewline(); + indentPop(); + } + else if (type == JSSessionModel.SUPER_FUNCTION_CALL) + { + if (fnode == null) + fnode = (IFunctionNode) fcnode + .getAncestorOfType(IFunctionNode.class); + } + + if (fnode.isConstructor() + && !EmitterUtils.hasSuperClass(getWalker().getProject(), fnode)) + return; + + IClassNode cnode = (IClassNode) node + .getAncestorOfType(IClassNode.class); + + if (cnode == null) + { + IDefinition cdef = getModel().getCurrentClass(); + write(formatQualifiedName(cdef.getQualifiedName())); + } + else + write(formatQualifiedName(cnode.getQualifiedName())); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSGoogEmitterTokens.GOOG_BASE); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.THIS); + + if (fnode.isConstructor()) + { + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SINGLE_QUOTE); + write(JSGoogEmitterTokens.GOOG_CONSTRUCTOR); + write(ASEmitterTokens.SINGLE_QUOTE); + } + + if (fnode != null && !fnode.isConstructor()) + { + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SINGLE_QUOTE); + write(fnode.getName()); + write(ASEmitterTokens.SINGLE_QUOTE); + } + + IASNode[] anodes = null; + boolean writeArguments = false; + if (fcnode != null) + { + anodes = fcnode.getArgumentNodes(); + + writeArguments = anodes.length > 0; + } + else if (fnode.isConstructor()) + { + anodes = fnode.getParameterNodes(); + + writeArguments = (anodes != null && anodes.length > 0); + } + + if (writeArguments) + { + int len = anodes.length; + for (int i = 0; i < len; i++) + { + writeToken(ASEmitterTokens.COMMA); + + getWalker().walk(anodes[i]); + } + } + + write(ASEmitterTokens.PAREN_CLOSE); + + if (type == JSSessionModel.CONSTRUCTOR_FULL) + { + write(ASEmitterTokens.SEMICOLON); + writeNewline(); + } + else if (type == JSSessionModel.CONSTRUCTOR_EMPTY) + { + write(ASEmitterTokens.SEMICOLON); + } + } + + protected void emitDefaultParameterCodeBlock(IFunctionNode node) + { + IParameterNode[] pnodes = node.getParameterNodes(); + if (pnodes.length == 0) + return; + + Map<Integer, IParameterNode> defaults = EmitterUtils + .getDefaults(pnodes); + + if (defaults != null) + { + final StringBuilder code = new StringBuilder(); + + if (!EmitterUtils.hasBody(node)) + { + indentPush(); + writeIndent(); + } + + List<IParameterNode> parameters = new ArrayList<IParameterNode>( + defaults.values()); + + for (int i = 0, n = parameters.size(); i < n; i++) + { + IParameterNode pnode = parameters.get(i); + + if (pnode != null) + { + code.setLength(0); + + /* x = typeof y !== 'undefined' ? y : z;\n */ + code.append(pnode.getName()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.EQUAL.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.TYPEOF.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(pnode.getName()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.STRICT_NOT_EQUAL.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.SINGLE_QUOTE.getToken()); + code.append(ASEmitterTokens.UNDEFINED.getToken()); + code.append(ASEmitterTokens.SINGLE_QUOTE.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.TERNARY.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(pnode.getName()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.COLON.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(pnode.getDefaultValue()); + code.append(ASEmitterTokens.SEMICOLON.getToken()); + + write(code.toString()); + + if (i == n - 1 && !EmitterUtils.hasBody(node)) + indentPop(); + + writeNewline(); + } + } + } + } + + protected void emitRestParameterCodeBlock(IFunctionNode node) + { + IParameterNode[] pnodes = node.getParameterNodes(); + + IParameterNode rest = EmitterUtils.getRest(pnodes); + if (rest != null) + { + final StringBuilder code = new StringBuilder(); + + /* x = Array.prototype.slice.call(arguments, y);\n */ + code.append(rest.getName()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(ASEmitterTokens.EQUAL.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(BuiltinType.ARRAY.getName()); + code.append(ASEmitterTokens.MEMBER_ACCESS.getToken()); + code.append(JSEmitterTokens.PROTOTYPE.getToken()); + code.append(ASEmitterTokens.MEMBER_ACCESS.getToken()); + code.append(JSEmitterTokens.SLICE.getToken()); + code.append(ASEmitterTokens.MEMBER_ACCESS.getToken()); + code.append(JSEmitterTokens.CALL.getToken()); + code.append(ASEmitterTokens.PAREN_OPEN.getToken()); + code.append(JSEmitterTokens.ARGUMENTS.getToken()); + code.append(ASEmitterTokens.COMMA.getToken()); + code.append(ASEmitterTokens.SPACE.getToken()); + code.append(String.valueOf(pnodes.length - 1)); + code.append(ASEmitterTokens.PAREN_CLOSE.getToken()); + code.append(ASEmitterTokens.SEMICOLON.getToken()); + + write(code.toString()); + + writeNewline(); + } + } + + @Override + public void emitParameter(IParameterNode node) + { + getWalker().walk(node.getNameExpressionNode()); + } + + @Override + public void emitAssignedValue(IExpressionNode node) + { + if (node == null) + { + return; + } + IDefinition definition = node.resolve(getWalker().getProject()); + if (node.getNodeID() == ASTNodeID.ClassReferenceID) + { + write(definition.getQualifiedName()); + } + else + { + // AJH need Language.bind here and maybe not require + // that the node is a MemberAccessExpression + if (definition instanceof FunctionDefinition && + !((FunctionDefinition)definition).isStatic() && + (!(definition instanceof AccessorDefinition)) && + node instanceof MemberAccessExpressionNode) + { + emitClosureStart(); + getWalker().walk(node); + writeToken(ASEmitterTokens.COMMA); + getWalker().walk(((MemberAccessExpressionNode)node).getLeftOperandNode()); + emitClosureEnd(((MemberAccessExpressionNode)node).getLeftOperandNode()); + } + else + getWalker().walk(node); + } + } + + // XXX Dead + @Override + public void emitForEachLoop(IForLoopNode node) + { + IContainerNode xnode = (IContainerNode) node.getChild(1); + IBinaryOperatorNode bnode = (IBinaryOperatorNode) node + .getConditionalsContainerNode().getChild(0); + IASNode childNode = bnode.getChild(0); + + write(JSGoogEmitterTokens.GOOG_ARRAY_FOREACH); + write(ASEmitterTokens.PAREN_OPEN); + getWalker().walk(bnode.getChild(1)); + writeToken(ASEmitterTokens.COMMA); + writeToken(ASEmitterTokens.FUNCTION); + write(ASEmitterTokens.PAREN_OPEN); + if (childNode instanceof IVariableExpressionNode) + write(((IVariableNode) childNode.getChild(0)).getName()); + else + write(((IIdentifierNode) childNode).getName()); + writeToken(ASEmitterTokens.PAREN_CLOSE); + if (isImplicit(xnode)) + write(ASEmitterTokens.BLOCK_OPEN); + getWalker().walk(node.getStatementContentsNode()); + if (isImplicit(xnode)) + { + writeNewline(); + write(ASEmitterTokens.BLOCK_CLOSE); + } + write(ASEmitterTokens.PAREN_CLOSE); + } + + public JSGoogEmitter(FilterWriter out) + { + super(out); + } + + // XXX Dead + protected void emitObjectDefineProperty(IAccessorNode node) + { + /* + Object.defineProperty( + A.prototype, + 'foo', + {get: function() {return -1;}, + configurable: true} + ); + */ + + FunctionNode fn = (FunctionNode) node; + fn.parseFunctionBody(getProblems()); + + // head + write(JSGoogEmitterTokens.OBJECT); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.DEFINE_PROPERTY); + writeNewline(ASEmitterTokens.PAREN_OPEN, true); + + // Type + IFunctionDefinition definition = node.getDefinition(); + ITypeDefinition type = (ITypeDefinition) definition.getParent(); + write(type.getQualifiedName()); + if (!node.hasModifier(ASModifier.STATIC)) + { + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.PROTOTYPE); + } + writeToken(ASEmitterTokens.COMMA); + writeNewline(); + + // name + write(ASEmitterTokens.SINGLE_QUOTE); + write(definition.getBaseName()); + write(ASEmitterTokens.SINGLE_QUOTE); + writeToken(ASEmitterTokens.COMMA); + writeNewline(); + + // info object + // declaration + write(ASEmitterTokens.BLOCK_OPEN); + write(node.getNodeID() == ASTNodeID.GetterID ? ASEmitterTokens.GET + : ASEmitterTokens.SET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.FUNCTION); + emitParameters(node.getParametersContainerNode()); + + emitDefinePropertyFunction(node); + + writeToken(ASEmitterTokens.COMMA); + write(JSEmitterTokens.CONFIGURABLE); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.TRUE); + writeNewline(ASEmitterTokens.BLOCK_CLOSE, false); + + // tail, no colon; parent container will add it + write(ASEmitterTokens.PAREN_CLOSE); + } + + // XXX Dead + protected void emitDefinePropertyFunction(IAccessorNode node) + { + emitMethodScope(node.getScopedNode()); + } + + //-------------------------------------------------------------------------- + // Operators + //-------------------------------------------------------------------------- + + @Override + public void emitNamespaceAccessExpression( + INamespaceAccessExpressionNode node) + { + getWalker().walk(node.getLeftOperandNode()); + write(ASEmitterTokens.MEMBER_ACCESS); + getWalker().walk(node.getRightOperandNode()); + } + + @Override + public void emitAsOperator(IBinaryOperatorNode node) + { + emitBinaryOperator(node); + } + + @Override + public void emitIsOperator(IBinaryOperatorNode node) + { + emitBinaryOperator(node); + } + + // XXX Dead + @Override + public void emitBinaryOperator(IBinaryOperatorNode node) + { + if (ASNodeUtils.hasParenOpen(node)) + write(ASEmitterTokens.PAREN_OPEN); + + ASTNodeID id = node.getNodeID(); + + if (id == ASTNodeID.Op_IsID) + { + write(ASEmitterTokens.IS); + write(ASEmitterTokens.PAREN_OPEN); + getWalker().walk(node.getLeftOperandNode()); + writeToken(ASEmitterTokens.COMMA); + getWalker().walk(node.getRightOperandNode()); + write(ASEmitterTokens.PAREN_CLOSE); + } + else if (id == ASTNodeID.Op_AsID) + { + // (is(a, b) ? a : null) + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.IS); + write(ASEmitterTokens.PAREN_OPEN); + getWalker().walk(node.getLeftOperandNode()); + writeToken(ASEmitterTokens.COMMA); + getWalker().walk(node.getRightOperandNode()); + writeToken(ASEmitterTokens.PAREN_CLOSE); + writeToken(ASEmitterTokens.TERNARY); + getWalker().walk(node.getLeftOperandNode()); + write(ASEmitterTokens.SPACE); + writeToken(ASEmitterTokens.COLON); + write(ASEmitterTokens.NULL); + write(ASEmitterTokens.PAREN_CLOSE); + } + else + { + getWalker().walk(node.getLeftOperandNode()); + + if (id != ASTNodeID.Op_CommaID) + write(ASEmitterTokens.SPACE); + + // (erikdebruin) rewrite 'a &&= b' to 'a = a && b' + if (id == ASTNodeID.Op_LogicalAndAssignID + || id == ASTNodeID.Op_LogicalOrAssignID) + { + IIdentifierNode lnode = (IIdentifierNode) node + .getLeftOperandNode(); + + writeToken(ASEmitterTokens.EQUAL); + writeToken(lnode.getName()); + write((id == ASTNodeID.Op_LogicalAndAssignID) ? ASEmitterTokens.LOGICAL_AND + : ASEmitterTokens.LOGICAL_OR); + } + else + { + write(node.getOperator().getOperatorText()); + } + + write(ASEmitterTokens.SPACE); + + getWalker().walk(node.getRightOperandNode()); + } + + if (ASNodeUtils.hasParenOpen(node)) + write(ASEmitterTokens.PAREN_CLOSE); + } + + protected void emitClosureStart(FunctionNode node) + { + write(JSGoogEmitterTokens.GOOG_BIND); + write(ASEmitterTokens.PAREN_OPEN); + } + + protected void emitClosureEnd(FunctionNode node) + { + write(ASEmitterTokens.PAREN_CLOSE); + } +}
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitterTokens.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitterTokens.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitterTokens.java new file mode 100644 index 0000000..fd41804 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogEmitterTokens.java @@ -0,0 +1,52 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.goog; + +import org.apache.flex.compiler.codegen.IEmitterTokens; + +public enum JSGoogEmitterTokens implements IEmitterTokens +{ + AS3("__AS3__"), + GOOG_ARRAY_FOREACH("goog.array.forEach"), + GOOG_BASE("base"), + GOOG_CALL("call"), + GOOG_BIND("goog.bind"), + GOOG_CONSTRUCTOR("constructor"), + GOOG_GOOG("goog"), + GOOG_INHERITS("goog.inherits"), + GOOG_PROVIDE("goog.provide"), + GOOG_REQUIRE("goog.require"), + OBJECT("Object"), + ARRAY("Array"), + ERROR("Error"), + SELF("self"), + SUPERCLASS("superClass_"); + + private String token; + + private JSGoogEmitterTokens(String value) + { + token = value; + } + + public String getToken() + { + return token; + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java new file mode 100644 index 0000000..a031737 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/goog/JSGoogPublisher.java @@ -0,0 +1,360 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.goog; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.io.filefilter.DirectoryFileFilter; +import org.apache.commons.io.filefilter.RegexFileFilter; +import org.apache.flex.compiler.clients.JSConfiguration; +import org.apache.flex.compiler.clients.MXMLJSC.JSOutputType; +import org.apache.flex.compiler.clients.problems.ProblemQuery; +import org.apache.flex.compiler.codegen.js.IJSPublisher; +import org.apache.flex.compiler.config.Configuration; +import org.apache.flex.compiler.internal.codegen.js.JSPublisher; +import org.apache.flex.compiler.internal.codegen.js.JSSharedData; +import org.apache.flex.compiler.internal.driver.js.goog.JSGoogConfiguration; +import org.apache.flex.compiler.utils.JSClosureCompilerUtil; + +import com.google.javascript.jscomp.CheckLevel; +import com.google.javascript.jscomp.ErrorManager; +import com.google.javascript.jscomp.JSError; +import com.google.javascript.jscomp.SourceFile; +import com.google.javascript.jscomp.SourceMap; +import com.google.javascript.jscomp.deps.DepsGenerator; +import com.google.javascript.jscomp.deps.DepsGenerator.InclusionStrategy; + +public class JSGoogPublisher extends JSPublisher implements IJSPublisher +{ + + public static final String GOOG_INTERMEDIATE_DIR_NAME = "js-intermediate"; + public static final String GOOG_RELEASE_DIR_NAME = "js-release"; + + public JSGoogPublisher(Configuration config) + { + super(config); + } + + @Override + public File getOutputFolder() + { + outputParentFolder = new File(configuration.getTargetFileDirectory()).getParentFile(); + outputFolder = new File(outputParentFolder, + JSGoogPublisher.GOOG_INTERMEDIATE_DIR_NAME); + + setupOutputFolder(); + + return outputFolder; + } + + @Override + public boolean publish(ProblemQuery problems) throws IOException + { + final String intermediateDirPath = getOutputFolder().getPath(); + + final String projectName = FilenameUtils.getBaseName(configuration.getTargetFile()); + final String outputFileName = projectName + "." + + JSSharedData.OUTPUT_EXTENSION; + + File releaseDir = new File( + new File(intermediateDirPath).getParentFile(), + GOOG_RELEASE_DIR_NAME); + final String releaseDirPath = releaseDir.getPath(); + if (releaseDir.exists()) + org.apache.commons.io.FileUtils.deleteQuietly(releaseDir); + releaseDir.mkdir(); + + final String closureLibDirPath = ((JSGoogConfiguration) configuration).getClosureLib(); + final String closureGoogSrcLibDirPath = closureLibDirPath + + "/closure/goog/"; + final String closureGoogTgtLibDirPath = intermediateDirPath + + "/library/closure/goog"; + final String closureTPSrcLibDirPath = closureLibDirPath + + "/third_party/closure/goog/"; + final String closureTPTgtLibDirPath = intermediateDirPath + + "/library/third_party/closure/goog"; + final List<String> vanillaSDKSrcLibDirPath = ((JSGoogConfiguration) configuration).getSDKJSLib(); + final String vanillaSDKTgtLibDirPath = intermediateDirPath + + "/VanillaSDK"; + + final String depsSrcFilePath = intermediateDirPath + + "/library/closure/goog/deps.js"; + final String depsTgtFilePath = intermediateDirPath + "/deps.js"; + final String projectIntermediateJSFilePath = intermediateDirPath + + File.separator + outputFileName; + final String projectReleaseJSFilePath = releaseDirPath + File.separator + + outputFileName; + + appendExportSymbol(projectIntermediateJSFilePath, projectName); + + copyFile(vanillaSDKSrcLibDirPath.get(0), vanillaSDKTgtLibDirPath); + + List<SourceFile> inputs = new ArrayList<SourceFile>(); + Collection<File> files = org.apache.commons.io.FileUtils.listFiles( + new File(intermediateDirPath), + new RegexFileFilter("^.*(\\.js)"), + DirectoryFileFilter.DIRECTORY); + for (File file : files) + { + inputs.add(SourceFile.fromFile(file)); + } + + copyFile(closureGoogSrcLibDirPath, closureGoogTgtLibDirPath); + copyFile(closureTPSrcLibDirPath, closureTPTgtLibDirPath); + + File srcDeps = new File(depsSrcFilePath); + + final List<SourceFile> deps = new ArrayList<SourceFile>(); + deps.add(SourceFile.fromFile(srcDeps)); + + ErrorManager errorManager = new JSGoogErrorManager(); + DepsGenerator depsGenerator = new DepsGenerator(deps, inputs, + InclusionStrategy.ALWAYS, closureGoogTgtLibDirPath, + errorManager); + writeFile(depsTgtFilePath, depsGenerator.computeDependencyCalls(), + false); + + org.apache.commons.io.FileUtils.deleteQuietly(srcDeps); + org.apache.commons.io.FileUtils.moveFile(new File(depsTgtFilePath), + srcDeps); + + // XXX (mschmalle) until we figure out what is going on with this configuration, just skip + // HTML generation for JSC output type + String outputType = ((JSConfiguration) configuration).getJSOutputType(); + if (!outputType.equals(JSOutputType.JSC.getText())) + { + writeHTML("intermediate", projectName, intermediateDirPath); + writeHTML("release", projectName, releaseDirPath); + } + + ArrayList<String> optionList = new ArrayList<String>(); + + files = org.apache.commons.io.FileUtils.listFiles(new File( + intermediateDirPath), new RegexFileFilter("^.*(\\.js)"), + DirectoryFileFilter.DIRECTORY); + for (File file : files) + { + optionList.add("--js=" + file.getCanonicalPath()); + } + + optionList.add("--closure_entry_point=" + projectName); + optionList.add("--only_closure_dependencies"); + optionList.add("--compilation_level=ADVANCED_OPTIMIZATIONS"); + optionList.add("--js_output_file=" + projectReleaseJSFilePath); + optionList.add("--output_manifest=" + releaseDirPath + File.separator + + "manifest.txt"); + optionList.add("--create_source_map=" + projectReleaseJSFilePath + + ".map"); + optionList.add("--source_map_format=" + SourceMap.Format.V3); + + String[] options = optionList.toArray(new String[0]); + + JSClosureCompilerUtil.run(options); + + appendSourceMapLocation(projectReleaseJSFilePath, projectName); + + System.out.println("The project '" + projectName + + "' has been successfully compiled and optimized."); + + return true; + } + + private void appendExportSymbol(String path, String projectName) + throws IOException + { + StringBuilder appendString = new StringBuilder(); + appendString.append("\n\n// Ensures the symbol will be visible after compiler renaming.\n"); + appendString.append("goog.exportSymbol('"); + appendString.append(projectName); + appendString.append("', "); + appendString.append(projectName); + appendString.append(");\n"); + writeFile(path, appendString.toString(), true); + } + + protected void appendSourceMapLocation(String path, String projectName) + throws IOException + { + StringBuilder appendString = new StringBuilder(); + appendString.append("\n//# sourceMappingURL=./" + projectName + + ".js.map"); + writeFile(path, appendString.toString(), true); + } + + protected void copyFile(String srcPath, String tgtPath) throws IOException + { + File srcFile = new File(srcPath); + if (srcFile.isDirectory()) + org.apache.commons.io.FileUtils.copyDirectory(srcFile, new File( + tgtPath)); + else + org.apache.commons.io.FileUtils.copyFile(srcFile, new File(tgtPath)); + } + + protected void writeHTML(String type, String projectName, String dirPath) + throws IOException + { + StringBuilder htmlFile = new StringBuilder(); + htmlFile.append("<!DOCTYPE html>\n"); + htmlFile.append("<html>\n"); + htmlFile.append("<head>\n"); + htmlFile.append("\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge,chrome=1\">\n"); + htmlFile.append("\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"); + + if (type == "intermediate") + { + htmlFile.append("\t<script type=\"text/javascript\" src=\"./library/closure/goog/base.js\"></script>\n"); + htmlFile.append("\t<script type=\"text/javascript\">\n"); + htmlFile.append("\t\tgoog.require(\""); + htmlFile.append(projectName); + htmlFile.append("\");\n"); + htmlFile.append("\t</script>\n"); + } + else + { + htmlFile.append("\t<script type=\"text/javascript\" src=\"./"); + htmlFile.append(projectName); + htmlFile.append(".js\"></script>\n"); + } + + htmlFile.append("</head>\n"); + htmlFile.append("<body>\n"); + htmlFile.append("\t<script type=\"text/javascript\">\n"); + htmlFile.append("\t\tnew "); + htmlFile.append(projectName); + htmlFile.append("();\n"); + htmlFile.append("\t</script>\n"); + htmlFile.append("</body>\n"); + htmlFile.append("</html>"); + + writeFile(dirPath + File.separator + "index.html", htmlFile.toString(), + false); + } + + protected void writeFile(String path, String content, boolean append) + throws IOException + { + File tgtFile = new File(path); + + if (!tgtFile.exists()) + tgtFile.createNewFile(); + + FileWriter fw = new FileWriter(tgtFile, append); + fw.write(content); + fw.close(); + } + + protected void dumpJar(File jarFile, File outputDir) throws IOException + { + // TODO (mschmalle) for some reason ide thinks this has not been closed + @SuppressWarnings("resource") + JarFile jar = new JarFile(jarFile); + + for (Enumeration<JarEntry> jarEntries = jar.entries(); jarEntries.hasMoreElements();) + { + JarEntry jarEntry = jarEntries.nextElement(); + if (!jarEntry.getName().endsWith("/")) + { + File file = new File(outputDir, jarEntry.getName()); + + // Check if the parent directory exists. If not -> create it. + File dir = file.getParentFile(); + if (!dir.exists()) + { + if (!dir.mkdirs()) + { + throw new IOException("Unable to create directory " + + dir.getAbsolutePath()); + } + } + + // Dump the file. + InputStream is = jar.getInputStream(jarEntry); + FileOutputStream fos = new FileOutputStream(file); + while (is.available() > 0) + { + fos.write(is.read()); + } + fos.close(); + is.close(); + } + } + + jar.close(); + } + + public class JSGoogErrorManager implements ErrorManager + { + @Override + public void setTypedPercent(double arg0) + { + } + + @Override + public void report(CheckLevel arg0, JSError arg1) + { + } + + @Override + public JSError[] getWarnings() + { + return null; + } + + @Override + public int getWarningCount() + { + return 0; + } + + @Override + public double getTypedPercent() + { + return 0; + } + + @Override + public JSError[] getErrors() + { + return null; + } + + @Override + public int getErrorCount() + { + return 0; + } + + @Override + public void generateReport() + { + } + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCJSEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCJSEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCJSEmitter.java new file mode 100644 index 0000000..1a10804 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCJSEmitter.java @@ -0,0 +1,39 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.jsc; + +import java.io.FilterWriter; + +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitter; + +/** + * Concrete implementation of the 'FlexJS' JavaScript production. + * + * @author Michael Schmalle + * @author Erik de Bruin + */ +public class JSCJSEmitter extends JSFlexJSEmitter +{ + + public JSCJSEmitter(FilterWriter out) + { + super(out); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCPublisher.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCPublisher.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCPublisher.java new file mode 100644 index 0000000..1f39d50 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jsc/JSCPublisher.java @@ -0,0 +1,53 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.jsc; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import org.apache.flex.compiler.config.Configuration; +import org.apache.flex.compiler.internal.codegen.mxml.flexjs.MXMLFlexJSPublisher; +import org.apache.flex.compiler.internal.projects.FlexJSProject; + +public class JSCPublisher extends MXMLFlexJSPublisher +{ + + public JSCPublisher(Configuration config, FlexJSProject project) + { + super(config, project); + } + + @Override + protected void writeHTML(String type, String projectName, String dirPath, + String deps, List<String> additionalHTML) throws IOException + { + if ("intermediate".equals(type)) + { + StringBuilder depsFile = new StringBuilder(); + depsFile.append(deps); + depsFile.append("goog.require(\""); + depsFile.append(projectName); + depsFile.append("\");\n"); + writeFile(dirPath + File.separator + projectName + "-dependencies.js", depsFile.toString(), false); + } + // super.writeHTML(type, projectName, dirPath, deps, additionalHTML); + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AccessorEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AccessorEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AccessorEmitter.java new file mode 100644 index 0000000..f2910d7 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AccessorEmitter.java @@ -0,0 +1,420 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.jx; + +import java.util.HashMap; +import java.util.Set; + +import org.apache.flex.compiler.codegen.ISubEmitter; +import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.common.ASModifier; +import org.apache.flex.compiler.common.IMetaInfo; +import org.apache.flex.compiler.common.ModifiersSet; +import org.apache.flex.compiler.definitions.IAccessorDefinition; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.IFunctionDefinition; +import org.apache.flex.compiler.definitions.ITypeDefinition; +import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSDocEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSSessionModel.PropertyNodes; +import org.apache.flex.compiler.internal.codegen.js.JSSubEmitter; +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSDocEmitter; +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitter; +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogEmitterTokens; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.internal.semantics.SemanticUtils; +import org.apache.flex.compiler.internal.tree.as.FunctionNode; +import org.apache.flex.compiler.internal.tree.as.SetterNode; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IAccessorNode; +import org.apache.flex.compiler.tree.as.IGetterNode; +import org.apache.flex.compiler.tree.as.ISetterNode; + +public class AccessorEmitter extends JSSubEmitter implements + ISubEmitter<IAccessorNode> +{ + + public AccessorEmitter(IJSEmitter emitter) + { + super(emitter); + } + + @Override + public void emit(IAccessorNode node) + { + if (node.getNodeID() == ASTNodeID.GetterID) + { + emitGet((IGetterNode) node); + } + else if (node.getNodeID() == ASTNodeID.SetterID) + { + emitSet((ISetterNode) node); + } + } + + public void emit(IClassDefinition definition) + { + // TODO (mschmalle) will remove this cast as more things get abstracted + JSFlexJSEmitter fjs = (JSFlexJSEmitter) getEmitter(); + + if (!getModel().getPropertyMap().isEmpty()) + { + writeNewline(); + writeNewline(); + writeNewline(); + write(JSGoogEmitterTokens.OBJECT); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.DEFINE_PROPERTIES); + write(ASEmitterTokens.PAREN_OPEN); + String qname = definition.getQualifiedName(); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.PROTOTYPE); + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + write("/** @lends {" + getEmitter().formatQualifiedName(qname) + + ".prototype} */ "); + writeNewline(ASEmitterTokens.BLOCK_OPEN); + + Set<String> propertyNames = getModel().getPropertyMap().keySet(); + boolean firstTime = true; + for (String propName : propertyNames) + { + if (firstTime) + firstTime = false; + else + writeNewline(ASEmitterTokens.COMMA); + + boolean wroteGetter = false; + PropertyNodes p = getModel().getPropertyMap().get(propName); + writeNewline("/** @export */"); + write(propName); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + writeNewline(ASEmitterTokens.BLOCK_OPEN); + if (p.getter != null) + { + write(ASEmitterTokens.GET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_OPEN); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.ATSIGN); + write(ASEmitterTokens.THIS); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_CLOSE); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.FUNCTION); + fjs.emitParameters(p.getter.getParametersContainerNode()); + + fjs.emitDefinePropertyFunction(p.getter); + wroteGetter = true; + } + else if (p.setter != null && p.setter.getDefinition().isOverride()) + { + // see if there is a getter on a base class. If so, we have to + // generate a call to the super from this class because + // Object.defineProperty doesn't allow overriding just the setter. + // If there is no getter defineProp'd the property will seen as + // write-only. + IAccessorDefinition other = (IAccessorDefinition)SemanticUtils.resolveCorrespondingAccessor(p.setter.getDefinition(), getProject()); + if (other != null) + { + write(ASEmitterTokens.GET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_OPEN); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.ATSIGN); + write(ASEmitterTokens.THIS); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_CLOSE); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.FUNCTION); + write(ASEmitterTokens.PAREN_OPEN); + write(ASEmitterTokens.PAREN_CLOSE); + write(ASEmitterTokens.SPACE); + writeNewline(ASEmitterTokens.BLOCK_OPEN); + + ICompilerProject project = this.getProject(); + if (project instanceof FlexJSProject) + ((FlexJSProject)project).needLanguage = true; + // setter is handled in binaryOperator + write(ASEmitterTokens.RETURN); + write(ASEmitterTokens.SPACE); + write(JSFlexJSEmitterTokens.LANGUAGE_QNAME); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSFlexJSEmitterTokens.SUPERGETTER); + write(ASEmitterTokens.PAREN_OPEN); + write(getEmitter().formatQualifiedName(qname)); + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.THIS); + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SINGLE_QUOTE); + write(propName); + write(ASEmitterTokens.SINGLE_QUOTE); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + write(ASEmitterTokens.BLOCK_CLOSE); + wroteGetter = true; + } + } + if (p.setter != null) + { + if (wroteGetter) + writeNewline(ASEmitterTokens.COMMA); + + write(ASEmitterTokens.SET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_OPEN); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.ATSIGN); + write(ASEmitterTokens.THIS); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_CLOSE); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.FUNCTION); + fjs.emitParameters(p.setter.getParametersContainerNode()); + + fjs.emitDefinePropertyFunction(p.setter); + } + else if (p.getter != null && p.getter.getDefinition().isOverride()) + { + // see if there is a getter on a base class. If so, we have to + // generate a call to the super from this class because + // Object.defineProperty doesn't allow overriding just the getter. + // If there is no setter defineProp'd the property will seen as + // read-only. + IAccessorDefinition other = (IAccessorDefinition)SemanticUtils.resolveCorrespondingAccessor(p.getter.getDefinition(), getProject()); + if (other != null) + { + if (wroteGetter) + writeNewline(ASEmitterTokens.COMMA); + + write(ASEmitterTokens.SET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_OPEN); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.ATSIGN); + write(ASEmitterTokens.THIS); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.BLOCK_OPEN); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.SPACE); + write(JSDocEmitterTokens.JSDOC_CLOSE); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.FUNCTION); + write(ASEmitterTokens.PAREN_OPEN); + write("value"); + write(ASEmitterTokens.PAREN_CLOSE); + write(ASEmitterTokens.SPACE); + writeNewline(ASEmitterTokens.BLOCK_OPEN); + + ICompilerProject project = this.getProject(); + if (project instanceof FlexJSProject) + ((FlexJSProject)project).needLanguage = true; + + write(JSFlexJSEmitterTokens.LANGUAGE_QNAME); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSFlexJSEmitterTokens.SUPERSETTER); + write(ASEmitterTokens.PAREN_OPEN); + write(getEmitter().formatQualifiedName(qname)); + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.THIS); + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SINGLE_QUOTE); + write(propName); + write(ASEmitterTokens.SINGLE_QUOTE); + writeToken(ASEmitterTokens.COMMA); + write("value"); + write(ASEmitterTokens.PAREN_CLOSE); + writeNewline(ASEmitterTokens.SEMICOLON); + write(ASEmitterTokens.BLOCK_CLOSE); + } + } + write(ASEmitterTokens.BLOCK_CLOSE); + } + writeNewline(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.PAREN_CLOSE); + write(ASEmitterTokens.SEMICOLON); + } + if (!getModel().getStaticPropertyMap().isEmpty()) + { + write(JSGoogEmitterTokens.OBJECT); + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.DEFINE_PROPERTIES); + write(ASEmitterTokens.PAREN_OPEN); + String qname = definition.getQualifiedName(); + write(getEmitter().formatQualifiedName(qname)); + write(ASEmitterTokens.COMMA); + write(ASEmitterTokens.SPACE); + write("/** @lends {" + getEmitter().formatQualifiedName(qname) + + "} */ "); + writeNewline(ASEmitterTokens.BLOCK_OPEN); + + Set<String> propertyNames = getModel().getStaticPropertyMap() + .keySet(); + boolean firstTime = true; + for (String propName : propertyNames) + { + if (firstTime) + firstTime = false; + else + writeNewline(ASEmitterTokens.COMMA); + + PropertyNodes p = getModel().getStaticPropertyMap().get( + propName); + writeNewline("/** @export */"); + write(propName); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + writeNewline(ASEmitterTokens.BLOCK_OPEN); + if (p.getter != null) + { + write(ASEmitterTokens.GET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.FUNCTION); + fjs.emitParameters(p.getter.getParametersContainerNode()); + + fjs.emitDefinePropertyFunction(p.getter); + } + if (p.setter != null) + { + if (p.getter != null) + writeNewline(ASEmitterTokens.COMMA); + + write(ASEmitterTokens.SET); + write(ASEmitterTokens.COLON); + write(ASEmitterTokens.SPACE); + write(ASEmitterTokens.FUNCTION); + fjs.emitParameters(p.setter.getParametersContainerNode()); + + fjs.emitDefinePropertyFunction(p.setter); + } + write(ASEmitterTokens.BLOCK_CLOSE); + } + writeNewline(ASEmitterTokens.BLOCK_CLOSE); + write(ASEmitterTokens.PAREN_CLOSE); + write(ASEmitterTokens.SEMICOLON); + } + } + + public void emitGet(IGetterNode node) + { + // TODO (mschmalle) will remove this cast as more things get abstracted + JSFlexJSEmitter fjs = (JSFlexJSEmitter) getEmitter(); + + ModifiersSet modifierSet = node.getDefinition().getModifiers(); + boolean isStatic = (modifierSet != null && modifierSet + .hasModifier(ASModifier.STATIC)); + HashMap<String, PropertyNodes> map = isStatic ? getModel() + .getStaticPropertyMap() : getModel().getPropertyMap(); + String name = node.getName(); + PropertyNodes p = map.get(name); + if (p == null) + { + p = new PropertyNodes(); + map.put(name, p); + } + p.getter = node; + FunctionNode fn = (FunctionNode) node; + fn.parseFunctionBody(fjs.getProblems()); + } + + public void emitSet(ISetterNode node) + { + // TODO (mschmalle) will remove this cast as more things get abstracted + JSFlexJSEmitter fjs = (JSFlexJSEmitter) getEmitter(); + JSFlexJSDocEmitter doc = (JSFlexJSDocEmitter) fjs.getDocEmitter(); + + ModifiersSet modifierSet = node.getDefinition().getModifiers(); + boolean isStatic = (modifierSet != null && modifierSet + .hasModifier(ASModifier.STATIC)); + HashMap<String, PropertyNodes> map = isStatic ? getModel() + .getStaticPropertyMap() : getModel().getPropertyMap(); + String name = node.getName(); + PropertyNodes p = map.get(name); + if (p == null) + { + p = new PropertyNodes(); + map.put(name, p); + } + p.setter = node; + FunctionNode fn = (FunctionNode) node; + fn.parseFunctionBody(fjs.getProblems()); + + boolean isBindableSetter = false; + if (node instanceof SetterNode) + { + IMetaInfo[] metaInfos = null; + metaInfos = node.getMetaInfos(); + for (IMetaInfo metaInfo : metaInfos) + { + name = metaInfo.getTagName(); + if (name.equals("Bindable") + && metaInfo.getAllAttributes().length == 0) + { + isBindableSetter = true; + break; + } + } + } + if (isBindableSetter) + { + IFunctionDefinition definition = node.getDefinition(); + ITypeDefinition type = (ITypeDefinition) definition.getParent(); + doc.emitMethodDoc(fn, getProject()); + write(fjs.formatQualifiedName(type.getQualifiedName())); + if (!node.hasModifier(ASModifier.STATIC)) + { + write(ASEmitterTokens.MEMBER_ACCESS); + write(JSEmitterTokens.PROTOTYPE); + } + + write(ASEmitterTokens.MEMBER_ACCESS); + write("__bindingWrappedSetter__"); + writeToken(node.getName()); + writeToken(ASEmitterTokens.EQUAL); + write(ASEmitterTokens.FUNCTION); + fjs.emitParameters(node.getParametersContainerNode()); + //writeNewline(); + fjs.emitMethodScope(node.getScopedNode()); + } + } +} http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/c3dce49f/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AsIsEmitter.java ---------------------------------------------------------------------- diff --git a/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AsIsEmitter.java b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AsIsEmitter.java new file mode 100644 index 0000000..ee8a5e6 --- /dev/null +++ b/compiler-jx/src/main/java/org/apache/flex/compiler/internal/codegen/js/jx/AsIsEmitter.java @@ -0,0 +1,197 @@ +/* + * + * 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.flex.compiler.internal.codegen.js.jx; + +import org.apache.flex.compiler.asdoc.flexjs.ASDocComment; +import org.apache.flex.compiler.codegen.js.IJSEmitter; +import org.apache.flex.compiler.definitions.IClassDefinition; +import org.apache.flex.compiler.definitions.IDefinition; +import org.apache.flex.compiler.internal.codegen.as.ASEmitterTokens; +import org.apache.flex.compiler.internal.codegen.js.JSSubEmitter; +import org.apache.flex.compiler.internal.codegen.js.flexjs.JSFlexJSEmitterTokens; +import org.apache.flex.compiler.internal.projects.FlexJSProject; +import org.apache.flex.compiler.projects.ICompilerProject; +import org.apache.flex.compiler.tree.ASTNodeID; +import org.apache.flex.compiler.tree.as.IASNode; +import org.apache.flex.compiler.tree.as.IBinaryOperatorNode; +import org.apache.flex.compiler.tree.as.IExpressionNode; +import org.apache.flex.compiler.tree.as.IFunctionNode; + +public class AsIsEmitter extends JSSubEmitter +{ + + public AsIsEmitter(IJSEmitter emitter) + { + super(emitter); + } + + public void emitIsAs(IExpressionNode node, IExpressionNode left, IExpressionNode right, + ASTNodeID id, boolean coercion) + { + // project is null in unit tests + //IDefinition dnode = project != null ? (right).resolve(project) : null; + IDefinition dnode = getProject() != null ? (right) + .resolve(getProject()) : null; + if (id != ASTNodeID.Op_IsID && dnode != null) + { + boolean emit = coercion ? + !((FlexJSProject)getProject()).config.getJSOutputOptimizations().contains(JSFlexJSEmitterTokens.SKIP_FUNCTION_COERCIONS.getToken()) : + !((FlexJSProject)getProject()).config.getJSOutputOptimizations().contains(JSFlexJSEmitterTokens.SKIP_AS_COERCIONS.getToken()); + + // find the function node + IFunctionNode functionNode = (IFunctionNode) left + .getAncestorOfType(IFunctionNode.class); + if (functionNode != null) // can be null in synthesized binding code + { + if (coercion) + { + // see if the cast is inside a try/catch in this function. If so, + // assume that we want an exception. + IASNode child = left.getParent(); + while (child != functionNode) + { + if (child.getNodeID() == ASTNodeID.TryID) + { + emit = true; + break; + } + child = child.getParent(); + } + } + ASDocComment asDoc = (ASDocComment) functionNode + .getASDocComment(); + if (asDoc != null) + { + String asDocString = asDoc.commentNoEnd(); + String coercionToken = JSFlexJSEmitterTokens.EMIT_COERCION + .getToken(); + int emitIndex = asDocString.indexOf(coercionToken); + while (emitIndex != -1) + { + String emitable = asDocString.substring(emitIndex + + coercionToken.length()); + int endIndex = emitable.indexOf("\n"); + emitable = emitable.substring(0, endIndex); + emitable = emitable.trim(); + String rightSide = dnode.getQualifiedName(); + if (emitable.equals(rightSide)) + { + emit = true; + break; + } + emitIndex = asDocString.indexOf(coercionToken, + emitIndex + coercionToken.length()); + } + String ignoreToken = JSFlexJSEmitterTokens.IGNORE_COERCION + .getToken(); + int ignoreIndex = asDocString.indexOf(ignoreToken); + while (ignoreIndex != -1) + { + String ignorable = asDocString.substring(ignoreIndex + + ignoreToken.length()); + int endIndex = ignorable.indexOf("\n"); + ignorable = ignorable.substring(0, endIndex); + ignorable = ignorable.trim(); + String rightSide = dnode.getQualifiedName(); + if (ignorable.equals(rightSide)) + { + emit = false; + break; + } + ignoreIndex = asDocString.indexOf(ignoreToken, + ignoreIndex + ignoreToken.length()); + } + } + } + if (!emit) + { + getWalker().walk(left); + return; + } + } + + ICompilerProject project = this.getProject(); + if (project instanceof FlexJSProject) + ((FlexJSProject)project).needLanguage = true; + + if (node instanceof IBinaryOperatorNode) + { + IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node; + startMapping(node, binaryOperatorNode.getLeftOperandNode()); + } + else + { + startMapping(node); + } + write(JSFlexJSEmitterTokens.LANGUAGE_QNAME); + write(ASEmitterTokens.MEMBER_ACCESS); + + if (id == ASTNodeID.Op_IsID) + write(ASEmitterTokens.IS); + else + write(ASEmitterTokens.AS); + + write(ASEmitterTokens.PAREN_OPEN); + endMapping(node); + + getWalker().walk(left); + if (node instanceof IBinaryOperatorNode) + { + IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node; + startMapping(node, binaryOperatorNode.getLeftOperandNode()); + } + else + { + startMapping(node); + } + writeToken(ASEmitterTokens.COMMA); + endMapping(node); + + if (dnode instanceof IClassDefinition) + { + startMapping(right); + write(getEmitter().formatQualifiedName(dnode.getQualifiedName())); + endMapping(right); + } + else + { + getWalker().walk(right); + } + + if (node instanceof IBinaryOperatorNode) + { + IBinaryOperatorNode binaryOperatorNode = (IBinaryOperatorNode) node; + startMapping(node, binaryOperatorNode.getLeftOperandNode()); + } + else + { + startMapping(node); + } + if (coercion) + { + writeToken(ASEmitterTokens.COMMA); + write(ASEmitterTokens.TRUE); + } + + write(ASEmitterTokens.PAREN_CLOSE); + endMapping(node); + } + +}