You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by cd...@apache.org on 2014/10/31 09:28:32 UTC

[10/23] git commit: [flex-falcon] [refs/heads/feature/flexmojos-tests] - Added super class to handle VF2JS specific JS emitting

Added super class to handle VF2JS specific JS emitting

Signed-off-by: Erik de Bruin <er...@ixsoftware.nl>


Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/82588644
Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/82588644
Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/82588644

Branch: refs/heads/feature/flexmojos-tests
Commit: 82588644538bc1a3701d65ed319877ead121ea74
Parents: 601605b
Author: Erik de Bruin <er...@ixsoftware.nl>
Authored: Tue Oct 21 13:34:48 2014 +0200
Committer: Erik de Bruin <er...@ixsoftware.nl>
Committed: Thu Oct 23 19:42:52 2014 +0200

----------------------------------------------------------------------
 .../codegen/js/vf2js/JSVF2JSEmitter.java        | 1156 ++++++++++++++++++
 1 file changed, 1156 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/82588644/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/vf2js/JSVF2JSEmitter.java
----------------------------------------------------------------------
diff --git a/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/vf2js/JSVF2JSEmitter.java b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/vf2js/JSVF2JSEmitter.java
new file mode 100644
index 0000000..a0686c8
--- /dev/null
+++ b/compiler.jx/src/org/apache/flex/compiler/internal/codegen/js/vf2js/JSVF2JSEmitter.java
@@ -0,0 +1,1156 @@
+/*
+ *
+ *  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.vf2js;
+
+import java.io.FilterWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.flex.compiler.codegen.IASGlobalFunctionConstants.BuiltinType;
+import org.apache.flex.compiler.codegen.IDocEmitter;
+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.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.goog.JSGoogDocEmitter;
+import org.apache.flex.compiler.internal.codegen.js.goog.JSGoogEmitterTokens;
+import org.apache.flex.compiler.internal.definitions.ClassDefinition;
+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.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.IScopedNode;
+import org.apache.flex.compiler.tree.as.ISetterNode;
+import org.apache.flex.compiler.tree.as.ITypeNode;
+import org.apache.flex.compiler.tree.as.ITypedExpressionNode;
+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 JSVF2JSEmitter extends JSEmitter implements IJSGoogEmitter
+{
+
+    protected static final String CONSTRUCTOR_EMPTY = "emptyConstructor";
+    protected static final String CONSTRUCTOR_FULL = "fullConstructor";
+    protected static final String SUPER_FUNCTION_CALL = "replaceSuperFunction";
+
+    protected List<String> propertyNames = new ArrayList<String>();
+
+    protected ICompilerProject project;
+
+    protected IJSGoogDocEmitter getDoc()
+    {
+        return (IJSGoogDocEmitter) getDocEmitter();
+    }
+
+    @Override
+    public IDocEmitter getDocEmitter()
+    {
+        return new JSGoogDocEmitter(this);
+    }
+
+    //--------------------------------------------------------------------------
+    // 
+    //--------------------------------------------------------------------------
+
+    @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();
+    }
+
+    @Override
+    public void emitPackageHeaderContents(IPackageDefinition definition)
+    {
+        PackageScope containedScope = (PackageScope) definition
+                .getContainedScope();
+
+        ITypeDefinition type = findType(containedScope.getAllLocalDefinitions());
+        if (type == null)
+            return;
+
+        List<String> list = 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();
+        }
+    }
+
+    @Override
+    public void emitPackageContents(IPackageDefinition definition)
+    {
+        IASScope containedScope = definition.getContainedScope();
+        ITypeDefinition type = findType(containedScope.getAllLocalDefinitions());
+        if (type == null)
+            return;
+
+        ITypeNode tnode = findTypeNode(definition.getNode());
+        if (tnode != null)
+        {
+            getWalker().walk(tnode); // IClassNode | IInterfaceNode
+        }
+    }
+
+    @Override
+    public void emitPackageFooter(IPackageDefinition definition)
+    {
+    }
+
+    //--------------------------------------------------------------------------
+    // 
+    //--------------------------------------------------------------------------
+
+    @Override
+    public void emitClass(IClassNode node)
+    {
+        IClassDefinition definition = node.getDefinition();
+
+        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);
+            }
+        }
+    }
+
+    @Override
+    public void emitInterface(IInterfaceNode node)
+    {
+        ICompilerProject project = getWalker().getProject();
+
+        getDoc().emitInterfaceDoc(node, project);
+
+        String qname = node.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);
+        }
+
+        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(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).getParameterNodes());
+
+                    write(ASEmitterTokens.SPACE);
+                    write(ASEmitterTokens.BLOCK_OPEN);
+                    writeNewline();
+                    write(ASEmitterTokens.BLOCK_CLOSE);
+                }
+
+                write(ASEmitterTokens.SEMICOLON);
+            }
+        }
+    }
+
+    @Override
+    public void emitField(IVariableNode node)
+    {
+        IClassDefinition definition = getClassDefinition(node);
+
+        IDefinition def = null;
+        IExpressionNode enode = node.getVariableTypeNode();//getAssignedValueNode();
+        if (enode != null)
+            def = enode.resolveType(getWalker().getProject());
+
+        getDoc().emitFieldDoc(node, def);
+
+        /* 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);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void emitVarDeclaration(IVariableNode node)
+    {
+        if (!(node instanceof ChainedVariableNode))
+        {
+            emitMemberKeyword(node);
+        }
+
+        IExpressionNode avnode = node.getAssignedValueNode();
+        if (avnode != null)
+        {
+            IDefinition def = avnode.resolveType(getWalker().getProject());
+
+            String opcode = avnode.getNodeID().getParaphrase();
+            if (opcode != "AnonymousFunction")
+                getDoc().emitVarDoc(node, def);
+        }
+        else
+        {
+            getDoc().emitVarDoc(node, null);
+        }
+
+        emitDeclarationName(node);
+        if (!(avnode instanceof IEmbedNode))
+        	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);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void emitGetAccessor(IGetterNode node)
+    {
+        emitObjectDefineProperty(node);
+    }
+
+    @Override
+    public void emitSetAccessor(ISetterNode node)
+    {
+        emitObjectDefineProperty(node);
+    }
+
+    protected 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);
+        }
+    }
+
+    @Override
+    public void emitMethod(IFunctionNode node)
+    {
+        FunctionNode fn = (FunctionNode) node;
+        fn.parseFunctionBody(new ArrayList<ICompilerProblem>());
+
+        ICompilerProject project = getWalker().getProject();
+
+        getDoc().emitMethodDoc(node, project);
+
+        boolean isConstructor = node.isConstructor();
+
+        String qname = getTypeDefinition(node).getQualifiedName();
+        if (qname != null && !qname.equals(""))
+        {
+            write(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.getParameterNodes());
+
+        boolean hasSuperClass = hasSuperClass(node);
+
+        if (isConstructor && node.getScopedNode().getChildCount() == 0)
+        {
+            write(ASEmitterTokens.SPACE);
+            write(ASEmitterTokens.BLOCK_OPEN);
+            if (hasSuperClass)
+                emitSuperCall(node, CONSTRUCTOR_EMPTY);
+            writeNewline();
+            write(ASEmitterTokens.BLOCK_CLOSE);
+        }
+
+        if (!isConstructor || node.getScopedNode().getChildCount() > 0)
+            emitMethodScope(node.getScopedNode());
+
+        if (isConstructor && hasSuperClass)
+        {
+            writeNewline();
+            write(JSGoogEmitterTokens.GOOG_INHERITS);
+            write(ASEmitterTokens.PAREN_OPEN);
+            write(qname);
+            writeToken(ASEmitterTokens.COMMA);
+            String sname = getSuperClassDefinition(node, project)
+                    .getQualifiedName();
+            write(sname);
+            write(ASEmitterTokens.PAREN_CLOSE);
+        }
+    }
+
+    @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());
+
+            write(ASEmitterTokens.PAREN_OPEN);
+            walkArguments(node.getArgumentNodes());
+            write(ASEmitterTokens.PAREN_CLOSE);
+        }
+        else
+        {
+            emitSuperCall(node, SUPER_FUNCTION_CALL);
+        }
+    }
+
+    @Override
+    public void emitIdentifier(IIdentifierNode node)
+    {
+        ICompilerProject project = getWalker().getProject();
+
+        IClassNode cnode = (IClassNode) node
+                .getAncestorOfType(IClassNode.class);
+
+        IDefinition def = ((IIdentifierNode) node).resolve(project);
+
+        ITypeDefinition type = ((IIdentifierNode) 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 (hasBody(node) && !isStatic && !isLocal)
+            emitSelfReference(node);
+
+        if (node.isConstructor()
+                && hasSuperClass(node) && !hasSuperCall(node.getScopedNode()))
+            emitSuperCall(node, CONSTRUCTOR_FULL);
+
+        emitRestParameterCodeBlock(node);
+
+        emitDefaultParameterCodeBlock(node);
+    }
+
+    protected void emitSelfReference(IFunctionNode node)
+    {
+        writeToken(ASEmitterTokens.VAR);
+        writeToken(JSGoogEmitterTokens.SELF);
+        writeToken(ASEmitterTokens.EQUAL);
+        write(ASEmitterTokens.THIS);
+        writeNewline(ASEmitterTokens.SEMICOLON);
+    }
+
+    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 == CONSTRUCTOR_EMPTY)
+        {
+            indentPush();
+            writeNewline();
+            indentPop();
+        }
+        else if (type == SUPER_FUNCTION_CALL)
+        {
+            if (fnode == null)
+                fnode = (IFunctionNode) fcnode
+                        .getAncestorOfType(IFunctionNode.class);
+        }
+
+        if (fnode.isConstructor() && !hasSuperClass(fnode))
+            return;
+
+        IClassNode cnode = (IClassNode) node
+                .getAncestorOfType(IClassNode.class);
+
+        write(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 == CONSTRUCTOR_FULL)
+        {
+            write(ASEmitterTokens.SEMICOLON);
+            writeNewline();
+        }
+        else if (type == CONSTRUCTOR_EMPTY)
+        {
+            write(ASEmitterTokens.SEMICOLON);
+        }
+    }
+
+    protected void emitDefaultParameterCodeBlock(IFunctionNode node)
+    {
+        IParameterNode[] pnodes = node.getParameterNodes();
+        if (pnodes.length == 0)
+            return;
+
+        Map<Integer, IParameterNode> defaults = getDefaults(pnodes);
+
+        if (defaults != null)
+        {
+            final StringBuilder code = new StringBuilder();
+
+            if (!hasBody(node))
+            {
+                indentPush();
+                write(ASEmitterTokens.INDENT);
+            }
+
+            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 && !hasBody(node))
+                        indentPop();
+
+                    writeNewline();
+                }
+            }
+        }
+    }
+
+    private void emitRestParameterCodeBlock(IFunctionNode node)
+    {
+        IParameterNode[] pnodes = node.getParameterNodes();
+
+        IParameterNode rest = 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
+    protected void emitAssignedValue(IExpressionNode node)
+    {
+        if (node != null)
+        {
+            write(ASEmitterTokens.SPACE);
+            writeToken(ASEmitterTokens.EQUAL);
+            if (node.getNodeID() == ASTNodeID.ClassReferenceID)
+            {
+                IDefinition definition = node.resolve(getWalker().getProject());
+                write(definition.getQualifiedName());
+            }
+            else
+            {
+                getWalker().walk(node);
+            }
+        }
+    }
+
+    @Override
+    public void emitTypedExpression(ITypedExpressionNode node)
+    {
+        getWalker().walk(node.getCollectionNode());
+    }
+
+    @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 JSVF2JSEmitter(FilterWriter out)
+    {
+        super(out);
+    }
+
+    protected Map<Integer, IParameterNode> getDefaults(IParameterNode[] nodes)
+    {
+        Map<Integer, IParameterNode> result = new HashMap<Integer, IParameterNode>();
+        int i = 0;
+        boolean hasDefaults = false;
+        for (IParameterNode node : nodes)
+        {
+            if (node.hasDefaultValue())
+            {
+                hasDefaults = true;
+                result.put(i, node);
+            }
+            else
+            {
+                result.put(i, null);
+            }
+            i++;
+        }
+
+        if (!hasDefaults)
+            return null;
+
+        return result;
+    }
+
+    private IParameterNode getRest(IParameterNode[] nodes)
+    {
+        for (IParameterNode node : nodes)
+        {
+            if (node.isRest())
+                return node;
+        }
+
+        return null;
+    }
+
+    private static ITypeDefinition getTypeDefinition(IDefinitionNode node)
+    {
+        ITypeNode tnode = (ITypeNode) node.getAncestorOfType(ITypeNode.class);
+        return (ITypeDefinition) tnode.getDefinition();
+    }
+
+    protected static IClassDefinition getClassDefinition(IDefinitionNode node)
+    {
+        IClassNode tnode = (IClassNode) node
+                .getAncestorOfType(IClassNode.class);
+        return (tnode != null) ? tnode.getDefinition() : null;
+    }
+
+    private static IClassDefinition getSuperClassDefinition(
+            IDefinitionNode node, ICompilerProject project)
+    {
+        IClassDefinition parent = (IClassDefinition) node.getDefinition()
+                .getParent();
+        IClassDefinition superClass = parent.resolveBaseClass(project);
+        return superClass;
+    }
+
+    protected boolean hasSuperClass(IDefinitionNode node)
+    {
+        ICompilerProject project = getWalker().getProject();
+        IClassDefinition superClassDefinition = getSuperClassDefinition(node,
+                project);
+        // XXX (mschmalle) this is nulling for MXML super class, figure out why
+        if (superClassDefinition == null)
+            return false;
+        String qname = superClassDefinition.getQualifiedName();
+        return superClassDefinition != null
+                && !qname.equals(IASLanguageConstants.Object);
+    }
+
+    private boolean hasSuperCall(IScopedNode node)
+    {
+        for (int i = node.getChildCount() - 1; i > -1; i--)
+        {
+            IASNode cnode = node.getChild(i);
+            if (cnode.getNodeID() == ASTNodeID.FunctionCallID
+                    && cnode.getChild(0).getNodeID() == ASTNodeID.SuperID)
+                return true;
+        }
+
+        return false;
+    }
+
+    protected static boolean hasBody(IFunctionNode node)
+    {
+        IScopedNode scope = node.getScopedNode();
+        return scope.getChildCount() > 0;
+    }
+
+    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.getParameterNodes());
+
+        emitMethodScope(node.getScopedNode());
+
+        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);
+    }
+
+    //--------------------------------------------------------------------------
+    // 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);
+    }
+
+    @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);
+    }
+
+    //--------------------------------------------------------------------------
+    // 
+    //--------------------------------------------------------------------------
+
+    private List<String> resolveImports(ITypeDefinition type)
+    {
+        ArrayList<String> list = new ArrayList<String>();
+        IScopedNode scopeNode = type.getContainedScope().getScopeNode();
+        if (scopeNode != null)
+        {
+            scopeNode.getAllImports(list);
+        }
+        else
+        {
+            // MXML
+            ClassDefinition cdefinition = (ClassDefinition) type;
+            String[] implicitImports = cdefinition.getImplicitImports();
+            for (String imp : implicitImports)
+            {
+                list.add(imp);
+            }
+        }
+        return list;
+    }
+}