incubator-flex-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From aha...@apache.org
Subject svn commit: r1413061 [9/14] - in /incubator/flex/falcon/trunk/compiler.js: ./ bin/ build/ in/ intermediates/ localization/ localization/src/ localization/src/org/ localization/src/org/apache/ localization/src/org/apache/flex/ localization/src/org/apach...
Date Fri, 23 Nov 2012 20:58:56 GMT
Added: incubator/flex/falcon/trunk/compiler.js/src/org/apache/flex/compiler/internal/as/codegen/JSGeneratingReducer.java
URL: http://svn.apache.org/viewvc/incubator/flex/falcon/trunk/compiler.js/src/org/apache/flex/compiler/internal/as/codegen/JSGeneratingReducer.java?rev=1413061&view=auto
==============================================================================
--- incubator/flex/falcon/trunk/compiler.js/src/org/apache/flex/compiler/internal/as/codegen/JSGeneratingReducer.java (added)
+++ incubator/flex/falcon/trunk/compiler.js/src/org/apache/flex/compiler/internal/as/codegen/JSGeneratingReducer.java Fri Nov 23 20:58:50 2012
@@ -0,0 +1,11629 @@
+/*
+ *
+ *  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.as.codegen;
+
+import static org.apache.flex.abc.ABCConstants.*;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.text.SimpleDateFormat;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import org.apache.flex.abc.ABCConstants;
+import org.apache.flex.abc.instructionlist.InstructionList;
+import org.apache.flex.abc.semantics.ECMASupport;
+import org.apache.flex.abc.semantics.Instruction;
+import org.apache.flex.abc.semantics.MethodBodyInfo;
+import org.apache.flex.abc.semantics.MethodInfo;
+import org.apache.flex.abc.semantics.Name;
+import org.apache.flex.abc.semantics.Namespace;
+import org.apache.flex.abc.semantics.Nsset;
+import org.apache.flex.abc.semantics.PooledValue;
+import org.apache.flex.abc.visitors.IMethodBodyVisitor;
+import org.apache.flex.abc.visitors.IMethodVisitor;
+import org.apache.flex.abc.visitors.ITraitsVisitor;
+import org.apache.flex.compiler.common.ASModifier;
+import org.apache.flex.compiler.common.DependencyType;
+import org.apache.flex.compiler.constants.IASLanguageConstants;
+import org.apache.flex.compiler.constants.IASLanguageConstants.BuiltinType;
+import org.apache.flex.compiler.definitions.IAccessorDefinition;
+import org.apache.flex.compiler.definitions.IAppliedVectorDefinition;
+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.IGetterDefinition;
+import org.apache.flex.compiler.definitions.IInterfaceDefinition;
+import org.apache.flex.compiler.definitions.INamespaceDefinition;
+import org.apache.flex.compiler.definitions.IParameterDefinition;
+import org.apache.flex.compiler.definitions.ISetterDefinition;
+import org.apache.flex.compiler.definitions.ITypeDefinition;
+import org.apache.flex.compiler.definitions.IVariableDefinition;
+import org.apache.flex.compiler.definitions.metadata.IMetaTag;
+import org.apache.flex.compiler.definitions.references.IReference;
+import org.apache.flex.compiler.exceptions.DuplicateLabelException;
+import org.apache.flex.compiler.filespecs.IFileSpecification;
+import org.apache.flex.compiler.internal.definitions.AmbiguousDefinition;
+import org.apache.flex.compiler.internal.definitions.AppliedVectorDefinition;
+import org.apache.flex.compiler.internal.definitions.ClassDefinition;
+import org.apache.flex.compiler.internal.definitions.DefinitionBase;
+import org.apache.flex.compiler.internal.definitions.FunctionDefinition;
+import org.apache.flex.compiler.internal.definitions.GetterDefinition;
+import org.apache.flex.compiler.internal.definitions.InterfaceDefinition;
+import org.apache.flex.compiler.internal.definitions.MemberedDefinition;
+import org.apache.flex.compiler.internal.definitions.NamespaceDefinition;
+import org.apache.flex.compiler.internal.definitions.PackageDefinition;
+import org.apache.flex.compiler.internal.definitions.ParameterDefinition;
+import org.apache.flex.compiler.internal.definitions.SetterDefinition;
+import org.apache.flex.compiler.internal.definitions.TypeDefinitionBase;
+import org.apache.flex.compiler.internal.definitions.VariableDefinition;
+import org.apache.flex.compiler.internal.legacy.ASDefinitionFilter;
+import org.apache.flex.compiler.internal.legacy.ASDefinitionFilter.AccessValue;
+import org.apache.flex.compiler.internal.legacy.ASDefinitionFilter.ClassificationValue;
+import org.apache.flex.compiler.internal.legacy.ASDefinitionFilter.SearchScopeValue;
+import org.apache.flex.compiler.internal.legacy.ASScopeUtils;
+import org.apache.flex.compiler.internal.legacy.MemberedDefinitionUtils;
+import org.apache.flex.compiler.internal.projects.CompilerProject;
+import org.apache.flex.compiler.internal.scopes.ASFileScope;
+import org.apache.flex.compiler.internal.scopes.ASProjectScope;
+import org.apache.flex.compiler.internal.scopes.ASScope;
+import org.apache.flex.compiler.internal.scopes.CatchScope;
+import org.apache.flex.compiler.internal.semantics.SemanticUtils;
+import org.apache.flex.compiler.internal.tree.as.BaseDefinitionNode;
+import org.apache.flex.compiler.internal.tree.as.BaseVariableNode;
+import org.apache.flex.compiler.internal.tree.as.ExpressionNodeBase;
+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.FunctionObjectNode;
+import org.apache.flex.compiler.internal.tree.as.IdentifierNode;
+import org.apache.flex.compiler.internal.tree.as.LabeledStatementNode;
+import org.apache.flex.compiler.internal.tree.as.MemberAccessExpressionNode;
+import org.apache.flex.compiler.internal.tree.as.NamespaceNode;
+import org.apache.flex.compiler.internal.tree.as.NodeBase;
+import org.apache.flex.compiler.internal.tree.as.ParameterNode;
+import org.apache.flex.compiler.internal.tree.as.SwitchNode;
+import org.apache.flex.compiler.internal.tree.as.VariableExpressionNode;
+import org.apache.flex.compiler.internal.tree.as.VariableNode;
+import org.apache.flex.compiler.problems.CodegenInternalProblem;
+import org.apache.flex.compiler.problems.CodegenProblem;
+import org.apache.flex.compiler.problems.CompilerProblem;
+import org.apache.flex.compiler.problems.DuplicateLabelProblem;
+import org.apache.flex.compiler.problems.DuplicateNamespaceDefinitionProblem;
+import org.apache.flex.compiler.problems.ICompilerProblem;
+import org.apache.flex.compiler.problems.InvalidLvalueProblem;
+import org.apache.flex.compiler.problems.InvalidOverrideProblem;
+import org.apache.flex.compiler.problems.PackageCannotBeUsedAsValueProblem;
+import org.apache.flex.compiler.problems.UnknownNamespaceProblem;
+import org.apache.flex.compiler.problems.VoidTypeProblem;
+import org.apache.flex.compiler.projects.ICompilerProject;
+import org.apache.flex.compiler.scopes.IASScope;
+import org.apache.flex.compiler.tree.as.IASNode;
+import org.apache.flex.compiler.tree.as.IDynamicAccessNode;
+import org.apache.flex.compiler.tree.as.IBinaryOperatorNode;
+import org.apache.flex.compiler.tree.as.ICatchNode;
+import org.apache.flex.compiler.tree.as.IClassNode;
+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.IIdentifierNode;
+import org.apache.flex.compiler.tree.as.IImportNode;
+import org.apache.flex.compiler.tree.as.ILiteralNode;
+import org.apache.flex.compiler.tree.as.IMemberAccessExpressionNode;
+import org.apache.flex.compiler.tree.as.INumericLiteralNode;
+import org.apache.flex.compiler.tree.as.IObjectLiteralValuePairNode;
+import org.apache.flex.compiler.tree.as.IParameterNode;
+import org.apache.flex.compiler.tree.as.IRegExpLiteralNode;
+import org.apache.flex.compiler.tree.as.IScopedNode;
+import org.apache.flex.compiler.tree.as.ITryNode;
+import org.apache.flex.compiler.tree.as.IUnaryOperatorNode;
+import org.apache.flex.compiler.tree.as.IVariableNode;
+import org.apache.flex.compiler.tree.as.IWhileLoopNode;
+import org.apache.flex.compiler.tree.as.IWithNode;
+import org.apache.flex.compiler.tree.mxml.IMXMLEventSpecifierNode;
+import org.apache.flex.compiler.units.ICompilationUnit;
+import org.apache.flex.compiler.units.ICompilationUnit.Operation;
+
+/**
+ * JSGeneratingReducer is modeled after from ABCGeneratingReducer and called by
+ * the generated CmcJSEmitter (see cmc-js.jbg). This is the "meat" of FalconJS.
+ * This implementation is part of FalconJS. For more details on FalconJS see
+ * org.apache.flex.compiler.JSDriver
+ */
+@SuppressWarnings("nls")
+public class JSGeneratingReducer
+{
+    /**
+     * A very high cost, used to trap errors but otherwise well outside normal
+     * bounds.
+     */
+    static final int ERROR_TRAP = 268435456;
+
+    /**
+     * A struct for the decoded pieces of a catch block.
+     */
+    public class CatchPrototype
+    {
+        Name catchType;
+        Name catchVarName;
+        String catchBody;
+    }
+
+    /**
+     * ConditionalFragment holds the disparate elements of a conditional
+     * statement fragment.
+     */
+    public class ConditionalFragment
+    {
+        IASNode site;
+        String condition;
+        String statement;
+
+        // private Label statementLabel = null;
+
+        /**
+         * Construct a ConditionalFragment with a single statement.
+         */
+        ConditionalFragment(IASNode site, String condition, String statement)
+        {
+            this.site = site;
+            this.condition = condition;
+            this.statement = statement;
+        }
+
+        /**
+         * Construct a ConditionalFragment with a list of statements, coalescing
+         * them into a composite statement.
+         */
+        ConditionalFragment(IASNode site, String condition, Vector<String> statements)
+        {
+            this.site = site;
+            this.condition = condition;
+            this.statement = createInstruction(site);
+
+            for (String stmt : statements)
+            {
+                this.statement += stmt;
+            }
+        }
+
+        /**
+         * @return the label of the fragment's condition, or its statement label
+         * if it's the default alternative.
+         */
+        /*
+         * Label getLabel() { if ( !this.isUnconditionalAlternative() ) return
+         * this.condition.getLabel(); else return getStatementLabel(); }
+         */
+
+        /**
+         * Cache and return the label of this conditional fragment's statement
+         * so it can be retrieved after the statement's been added to the
+         * overall conditional statement and this.statement is invalidated.
+         */
+        /*
+         * Label getStatementLabel() { if ( null == this.statementLabel )
+         * this.statementLabel = this.statement.getLabel(); return
+         * this.statementLabel; }
+         */
+
+        /**
+         * @return true if this is an unconditional alternative, i.e. a default
+         * case or the last else in an if/else if/else.
+         */
+        boolean isUnconditionalAlternative()
+        {
+            return null == this.condition;
+        }
+    }
+
+    /**
+     * The RuntimeMultiname class holds the components of the various types of
+     * runtime multiname, and puts them together in the right order to generate
+     * the names and instruction sequences to jamble up the AVM. Only some
+     * permutations of the compile-time/runtime qualifier::name possibilities
+     * are valid: Name::expression generates MultinameL expression::expression
+     * generates RTQnameL expression::name generates RTQname (name::name is a
+     * plain Multiname)
+     */
+    public class RuntimeMultiname
+    {
+        /**
+         * The compile-time qualifier of a MultinameL. compileTimeName isn't
+         * valid (this would be a compile-time constant Multiname).
+         */
+        Name compileTimeQualifier;
+
+        /**
+         * The runtime qualifier of a RTQname or RTQNameL. Compile-time and
+         * runtime names are valid.
+         */
+        String runtimeQualifier;
+
+        /**
+         * The compile-time constant name of a RTQName. compileTimeQualifier
+         * isn't valid (this would be a compile-time constant Multiname).
+         */
+        Name compileTimeName;
+
+        /**
+         * The runtime name of a MultinameL or RTQnameL.
+         */
+        String runtimeName;
+
+        /**
+         * Construct a RTQnameL-type runtime name.
+         * 
+         * @param qualifier - the runtime qualifier.
+         * @param name - the runtime name.
+         */
+        RuntimeMultiname(String qualifier, String runtime_name)
+        {
+            this.runtimeQualifier = qualifier;
+            this.runtimeName = runtime_name;
+        }
+
+        /**
+         * Construct a RTQname-type runtime name.
+         * 
+         * @param qualifier - the runtime qualifier.
+         * @param name - the compile-time name.
+         */
+        RuntimeMultiname(String qualifier, Name name)
+        {
+            this.runtimeQualifier = qualifier;
+            this.compileTimeName = name;
+        }
+
+        /**
+         * Construct a MultinameL-type runtime name.
+         * 
+         * @param qualifier - the Multiname. Note this is the only kind of
+         * runtime name that receives a qualifying name.
+         * @param nameL - the runtime expression that yields the base name.
+         */
+        RuntimeMultiname(Name qualifier, String nameL)
+        {
+            assert (qualifier.getKind() == CONSTANT_MultinameL || qualifier.getKind() == CONSTANT_MultinameLA) : "Bad qualifier kind " + qualifier.getKind() + " on name " + qualifier.toString();
+            this.compileTimeQualifier = qualifier;
+            this.runtimeName = nameL;
+        }
+
+        /**
+         * Assemble the ingredients into an expression.
+         * 
+         * @param opcode - one of OP_getproperty or OP_setproperty.
+         * @param rhs - the value of a setproperty call. Passed to this routine
+         * because there may be name-specific instructions before and after the
+         * value.
+         */
+        private String generateGetOrSet(IASNode iNode, int opcode, String rhs)
+        {
+            //  TODO: Optimize InstructionList size.
+            String result = createInstruction(iNode);
+
+            //  Note: numerous microoptimization opportunities here
+            //  to avoid storing values in temps by creative use of
+            //  OP_dup and OP_swap, especially in getproperty gen.
+
+            if (this.compileTimeQualifier != null && this.runtimeName != null)
+            {
+                result += runtimeName;
+                if (rhs != null)
+                    result += rhs;
+
+                /*
+                 * // Generate MultinameL type code. Binding name_temp =
+                 * currentScope.allocateTemp(); result.addAll(this.runtimeName);
+                 * result.addInstruction(OP_dup);
+                 * result.addInstruction(name_temp.setlocal()); //
+                 * findprop(MultinameL) consumes a name from the value stack.
+                 * result.addInstruction(OP_findpropstrict,
+                 * this.compileTimeQualifier);
+                 * result.addInstruction(name_temp.getlocal()); if ( rhs != null
+                 * ) result.addAll(rhs); // get/setprop(MultinameL) consumes a
+                 * name from the value stack. result.addInstruction(opcode,
+                 * this.compileTimeQualifier);
+                 */
+
+            }
+            else if (this.runtimeQualifier != null && this.runtimeName != null)
+            {
+                /*
+                 * // Generate RTQnameL type code. Binding name_temp =
+                 * currentScope.allocateTemp(); Binding qual_temp =
+                 * currentScope.allocateTemp(); Name rtqnl = new
+                 * Name(CONSTANT_RTQnameL, null, null);
+                 * result.addAll(getRuntimeName(iNode));
+                 * result.addInstruction(name_temp.setlocal());
+                 * result.addAll(getRuntimeQualifier(iNode));
+                 * result.addInstruction(OP_dup);
+                 * result.addInstruction(qual_temp.setlocal());
+                 * result.addInstruction(name_temp.getlocal()); //
+                 * findprop(RTQNameL) consumes namespace and name from the value
+                 * stack. result.addInstruction(OP_findpropstrict, rtqnl);
+                 * result.addInstruction(qual_temp.getlocal());
+                 * result.addInstruction(name_temp.getlocal()); if ( rhs != null
+                 * ) result.addAll(rhs); // get/setprop(RTQNameL) consumes
+                 * namespace and name from the value stack.
+                 * result.addInstruction(opcode, rtqnl);
+                 * result.addAll(currentScope.releaseTemp(name_temp));
+                 */
+
+                result += getRuntimeName(iNode);
+                if (rhs != null)
+                    result += rhs;
+            }
+            else
+            {
+                //  Last valid combination generates a RTQname.
+                assert (this.runtimeQualifier != null && this.compileTimeName != null) : "Unknown runtime name configuration: " + this.toString();
+
+                result += getRuntimeName(iNode);
+                if (rhs != null)
+                    result += rhs;
+
+                /*
+                 * Name rtqn = new Name(CONSTANT_RTQname, null,
+                 * this.compileTimeName.getBaseName());
+                 * result.addAll(getRuntimeQualifier(iNode));
+                 * result.addInstruction(OP_dup); // findprop(RTQName) consumes
+                 * a namespace from the value stack.
+                 * result.addInstruction(OP_findpropstrict, rtqn);
+                 * result.addInstruction(OP_swap); if ( rhs != null )
+                 * result.addAll(rhs); // get/setprop(RTQName) consumes a
+                 * namespace from the value stack. result.addInstruction(opcode,
+                 * rtqn);
+                 */
+            }
+
+            return result;
+        }
+
+        /**
+         * Generate the InstructionList that expresses this RuntimeName's
+         * qualifier.
+         * 
+         * @param iNode - an IASNode to contribute debug info to the result
+         * InstructionList.
+         * @return the runtime qualifier setup instructions.
+         */
+        public String getRuntimeQualifier(IASNode iNode)
+        {
+            assert (hasRuntimeQualifier());
+            String result = createInstruction(iNode);
+
+            result += this.runtimeQualifier;
+
+            /*
+             * // Ensure the last instruction is an OP_coerce to Namespace.
+             * Instruction last = result.lastElement(); if ( last.getOpcode() !=
+             * OP_coerce || last.getOperandCount() == 0 || !
+             * namespaceType.equals(last.getOperand(0)) ) {
+             * result.addInstruction(OP_coerce, namespaceType); }
+             */
+            return result;
+        }
+
+        /**
+         * @return true if this RuntimeName has a runtime qualifier.
+         */
+        public boolean hasRuntimeQualifier()
+        {
+            return this.runtimeQualifier != null;
+        }
+
+        /**
+         * @return true if this RuntimeName has a runtime name.
+         */
+        public boolean hasRuntimeName()
+        {
+            return this.runtimeName != null;
+        }
+
+        /**
+         * Generate the InstructionList that expresses this RuntimeName's name.
+         * 
+         * @param iNode - an IASNode to contribute debug info to the result
+         * InstructionList.
+         * @return the runtime name setup instructions.
+         */
+        public String getRuntimeName(IASNode iNode)
+        {
+            assert (hasRuntimeName());
+
+            String result = createInstructionList(iNode);
+
+            /*
+             * result.addAll(replicate(this.runtimeName)); if (
+             * result.lastElement().getOpcode() != OP_coerce_s)
+             * result.addInstruction(OP_coerce_s);
+             */
+
+            result += this.runtimeName;
+
+            return result;
+        }
+
+        /**
+         * Generate the runtime name appropriate to this qualifier/name
+         * combination.
+         * 
+         * @return the runtime name appropriate to this qualifier/name
+         * combination.
+         */
+        public Name generateName()
+        {
+            Name result;
+
+            if (this.compileTimeQualifier != null)
+            {
+                result = this.compileTimeQualifier;
+            }
+            else if (this.runtimeQualifier != null && this.runtimeName != null)
+            {
+                result = new Name(CONSTANT_RTQnameL, null, null);
+            }
+            else
+            {
+                //  Last valid combination generates a RTQname.
+                assert (this.runtimeQualifier != null && this.compileTimeName != null) : "Unknown runtime name configuration: " + this.toString();
+
+                result = new Name(CONSTANT_RTQname, null, this.compileTimeName.getBaseName());
+            }
+
+            return result;
+        }
+
+        /**
+         * Convenience method generates an assignment
+         * 
+         * @param value - the value to set.
+         * @return the instruction sequence to set a the given multiname's
+         * value.
+         */
+        String generateAssignment(IASNode iNode, String value)
+        {
+            return generateGetOrSet(iNode, OP_setproperty, value);
+        }
+
+        /**
+         * Convenience method generates an r-value.
+         * 
+         * @return the instruction sequence to look up the given multiname.
+         */
+        String generateRvalue(IASNode iNode)
+        {
+            return generateGetOrSet(iNode, OP_getproperty, null);
+        }
+
+        /**
+         * Diagnostic toString() method, used primarily to debug the assertion
+         * in generate().
+         */
+        @Override
+        public String toString()
+        {
+            return "\n\t" + compileTimeQualifier + ",\n\t" + runtimeQualifier + ",\n\t" + compileTimeName + ",\n\t" + runtimeName;
+        }
+    }
+
+    /**
+     * The current LexicalScope. Set by the caller, changes during reduction
+     * when a scoped construct such as an embedded function or a with statement
+     * is encountered.
+     */
+    private LexicalScope currentScope;
+
+    /**
+     * Strings sent by the caller to be added to a function definition. Usually
+     * these are field initialization expressions in a constructor.
+     */
+    // private String instanceInitializers;
+
+    /**
+     * A shared name for the Namespace type.
+     */
+    public static final Name namespaceType = new Name("Namespace");
+
+    /**
+     * A shared name for the XML type.
+     */
+    public static final Name xmlType = new Name("XML");
+
+    /**
+     * A shared name for the XMLList type.
+     */
+    public static final Name xmlListType = new Name("XMLList");
+
+    /**
+     * A shared name for the RegExp type.
+     */
+    public static final Name regexType = new Name("RegExp");
+
+    /**
+     * A shared name for the void type.
+     */
+    public static final Name voidType = new Name("void");
+
+    /**
+     * Generate code to push a numeric constant.
+     */
+    public static void pushNumericConstant(long value, String result_list)
+    {
+        // do nothing
+        // result_list.pushNumericConstant(value);
+    }
+
+    /**
+     * Active labeled control-flow region's substatements. Populated by the
+     * labeledStmt Prologue, and winnowed by the labeledStmt reduction's
+     * epilogue.
+     */
+    private Set<IASNode> labeledNodes = new HashSet<IASNode>();
+
+    /**
+     * @return the currently active collection of problems.
+     */
+    public Collection<ICompilerProblem> getProblems()
+    {
+        return currentScope.getProblems();
+    }
+
+    /**
+     * Generate a binary operator.
+     * 
+     * @param l - the left-hand operand.
+     * @param r - the right-hand operand.
+     * @param opcode - the operator's opcode.
+     * @return the combined String sequence with the operator appended.
+     */
+    String binaryOp(IASNode iNode, String l, String r, int opcode)
+    {
+        checkBinaryOp(iNode, opcode);
+
+        switch (opcode)
+        {
+            //  Binary logical operators.
+            case OP_istypelate:
+                return reduce_istypeExprLate(iNode, l, r);
+            case OP_astypelate:
+                return reduce_astypeExprLate(iNode, l, r);
+            case OP_instanceof:
+                return reduce_instanceofExpr(iNode, l, r);
+            case OP_in:
+                return reduce_inExpr(iNode, l, r);
+        }
+
+        final String operator = opToString(iNode, opcode);
+        String result = createInstruction(iNode, l.length() + r.length() + 1);
+        result += binaryOp(l.toString(), r.toString(), operator);
+        return result;
+
+        /*
+         * String result = createInstruction(iNode, l.size() + r.size() + 1);
+         * result.addAll(l); result.addAll(r); result.addInstruction(opcode);
+         * return result;
+         */
+    }
+
+    public void checkBinaryOp(IASNode iNode, int opcode)
+    {
+        currentScope.getMethodBodySemanticChecker().checkBinaryOperator(iNode, opcode);
+    }
+
+    public String conditionalJump(IASNode iNode, String l, String r, int opcode)
+    {
+        return binaryOp(iNode, l, r, opcode);
+    }
+
+    String binaryOp(String l, String r, String operator)
+    {
+        String result = "(" + stripTabs(stripNS(l.toString())) + " " + operator + " " + stripTabs(stripNS(r.toString())) + ")";
+        return result;
+    }
+
+    /**
+     * Resolve a dotted name, e.g., foo.bar.baz
+     */
+    Binding dottedName(IASNode iNode, String qualifiers, String base_name)
+    {
+        if (iNode instanceof IdentifierNode)
+        {
+            return currentScope.resolveName((IdentifierNode)iNode);
+        }
+        else if (iNode instanceof ExpressionNodeBase)
+        {
+            ExpressionNodeBase expr = (ExpressionNodeBase)iNode;
+            ICompilerProject project = currentScope.getProject();
+            Name n = expr.getMName(project);
+
+            if (n == null)
+            {
+                currentScope.addProblem(new CodegenInternalProblem(iNode, "Unable to resove member name: " + iNode.toString()));
+                n = new Name(CONSTANT_Qname, new Nsset(new Namespace(CONSTANT_PackageNs, qualifiers)), base_name);
+            }
+
+            return currentScope.getBinding(iNode, n, expr.resolve(project));
+        }
+
+        //else
+        currentScope.addProblem(new CodegenInternalProblem(iNode, "Unable to resove to a dotted name: " + iNode.toString()));
+        return new Binding(iNode, new Name(CONSTANT_Qname, new Nsset(new Namespace(CONSTANT_PackageNs, qualifiers)), base_name), null);
+    }
+
+    /**
+     * Resolve a dotted name, e.g., foo.bar.baz, where the whole dotted name is
+     * a package this is an error, and a diagnostic will be emitted
+     */
+    Binding errorPackageName(IASNode iNode, String qualifiers, String base_name)
+    {
+        currentScope.addProblem(new PackageCannotBeUsedAsValueProblem(iNode, qualifiers + "." + base_name));
+        return new Binding(iNode, new Name(qualifiers + "." + base_name), null);
+    }
+
+    /**
+     * Common routine used by reductions that need an empty list.
+     * 
+     * @param iNode - the current AST node.
+     */
+    public String createInstruction(IASNode iNode)
+    {
+        return createInstruction(iNode, 0);
+    }
+
+    /**
+     * Common routine used by reductions that need an empty list.
+     * 
+     * @param iNode - the current AST node.
+     * @param capacity - requested capacity of the new list. May be adjusted to
+     * accomodate debug Strings.
+     */
+    public String createInstruction(IASNode iNode, int capacity)
+    {
+        String result = "";
+
+        String file_name = iNode.getSourcePath();
+
+        if (file_name == null)
+        {
+            //  Fall back on the file specification.
+            //  This may also be null (or assert if it's feeling moody),
+            //  in which case the file name remains null and file/line
+            //  processing noops.
+            try
+            {
+                IFileSpecification fs = iNode.getFileSpecification();
+                if (fs != null)
+                    file_name = fs.getPath();
+            }
+            catch (Throwable no_fs)
+            {
+                //  No file specification available, probably
+                //  because this node is some kind of syntho.
+            }
+        }
+
+        //  Note: getLine() uses zero-based counting.
+        int line_num = iNode.getLine() + 1;
+
+        //  Adjust the capacity requirement if debug
+        //  Strings are to be emitted.
+        if (currentScope.emitFile(file_name))
+            capacity++;
+        if (currentScope.emitLine(line_num))
+            capacity++;
+
+        //  If the required capacity is less than three
+        //  Strings, the String can hold 
+        //  them organically.  Specifying a capacity to
+        //  the String ctor causes it to allocate
+        //  a separate ArrayList.
+        if (capacity > 3)
+            result = new String(/* capacity */);
+        else
+            result = new String();
+
+        if (currentScope.emitFile(file_name))
+        {
+            // result.addInstruction(OP_debugfile, file_name);
+            currentScope.setDebugFile(file_name);
+        }
+
+        if (currentScope.emitLine(line_num))
+        {
+            // result.addInstruction(OP_debugline, line_num);
+            currentScope.setDebugLine(line_num);
+        }
+
+        return result;
+    }
+
+    /**
+     * Error trap.
+     */
+    public Binding error_namespaceAccess(IASNode iNode, IASNode raw_qualifier, Binding qualified_name)
+    {
+        String qualifier = ((IdentifierNode)raw_qualifier).getName();
+
+        //  TODO: In some circumstances, the namespace qualifier
+        //  may be an invalid attribute on a declaration.
+        currentScope.addProblem(new UnknownNamespaceProblem(raw_qualifier, qualifier));
+
+        return qualified_name;
+    }
+
+    /**
+     * Error trap.
+     */
+    public String error_reduce_Op_AssignId(IASNode iNode, String non_lvalue, String rvalue)
+    {
+        currentScope.addProblem(new InvalidLvalueProblem(iNode));
+        return createInstruction(iNode);
+    }
+
+    /**
+     * Generate access to a named entity.
+     * 
+     * @param name - the entity's name.
+     * @return an instruction sequence to access the entity.
+     */
+    String generateAccess(IASNode iNode, Binding name)
+    {
+        StringBuilder result = new StringBuilder();
+        generateAccess(iNode, name, result);
+        return result.toString();
+    }
+
+    /**
+     * Generate access to a named entity.
+     * 
+     * @param name - the entity's name.
+     * @param result - the instruction sequence to generate into.
+     */
+    void generateAccess(IASNode iNode, Binding binding, StringBuilder result)
+    {
+        if (binding.isLocal())
+        {
+            final String name = bindingToString(iNode, binding, false, false);
+            result.append(name);
+        }
+        else
+        {
+            assert (binding.getName() != null) : "non-local Binding " + binding + " must have a name";
+            currentScope.getMethodBodySemanticChecker().checkGetProperty(binding);
+            // generateAccess( iNode, binding.getName(), result);
+            final String name = bindingToString(iNode, binding, true, true);
+            result.append(name);
+        }
+    }
+
+    /**
+     * Generate access to a named entity.
+     * 
+     * @param name - the entity's name.
+     * @param result - the instruction sequence to generate into.
+     */
+    void generateAccess(IASNode iNode, Name name, StringBuilder result)
+    {
+        final String str = nameToString(iNode, name, true, true);
+        result.append(str);
+
+        /*
+         * if ( name.isTypeName() ) { generateAccess(name.getTypeNameBase(),
+         * result); generateTypeNameParameter(name.getTypeNameParameter(),
+         * result); result.addInstruction(OP_applytype, 1); } else {
+         * result.addInstruction(OP_findpropstrict, name);
+         * result.addInstruction(OP_getproperty, name); }
+         */
+    }
+
+    /**
+     * Generate code to assign to a named entity.
+     * 
+     * @param target - the entity to be assigned to.
+     * @param rvalue - the value to assign.
+     * @return an String sequence that stores the given rvalue in the target.
+     */
+    String generateAssignment(IASNode iNode, Binding target, String rvalue)
+    {
+        return generateAssignment(iNode, target, rvalue, false);
+    }
+
+    /**
+     * Generate code to assign to a named entity.
+     * 
+     * @param target - the entity to be assigned to.
+     * @param rvalue - the value to assign.
+     * @param need_value - when true, leave a DUP of the rvalue on the stack.
+     * @return an String sequence that stores the given rvalue in the target,
+     * and leaves a DUP of the rvalue on the stack if need_value is set.
+     */
+    String generateAssignment(IASNode iNode, Binding target, String rvalue, boolean need_value)
+    {
+        String result = createInstruction(iNode, rvalue.length() + 4);
+
+        result += rvalue;
+
+        /*
+         * result.addAll(rvalue); if ( need_value )
+         * result.addInstruction(OP_dup); if ( target.isLocal() ) { if (
+         * target.getDefinition() != null ) { ITypeDefinition type =
+         * target.getDefinition
+         * ().resolveType(currentScope.getDefinitionCache()); if ( type != null
+         * && type != ClassDefinition.getAnyTypeClassDefinition() ) {
+         * result.addInstruction(OP_coerce,
+         * ((DefinitionBase)type).getMName(currentScope.getProject())); } }
+         * result.addInstruction(target.setlocal()); } else {
+         * result.addInstruction(OP_findproperty, target.getName());
+         * result.addInstruction(OP_swap); result.addInstruction(OP_setproperty,
+         * target.getName()); }
+         */
+        return result;
+    }
+
+    /**
+     * Generate a catch block.
+     * 
+     * @param catch_proto - the catch block's prototype.
+     */
+    /*
+     * String generateCatchBlock( Label try_start, Label try_end, CatchPrototype
+     * catch_proto) { String scope_reinit =
+     * currentScope.getFlowManager().getScopeStackReinit(); String current_catch
+     * = new String(catch_proto.catchBody.size() + scope_reinit.size() + 15); //
+     * Common prologue code. current_catch.addInstruction(OP_getlocal0);
+     * current_catch.addInstruction(OP_pushscope); if(
+     * currentScope.needsActivation() ) { // Restore the activation object.
+     * current_catch
+     * .addInstruction(currentScope.getActivationStorage().getlocal());
+     * current_catch.addInstruction(OP_pushscope); } // Re-establish enclosing
+     * exception scopes. current_catch.addAll(scope_reinit); int handler_number
+     * = currentScope.getMethodBodyVisitor().visitException(try_start, try_end,
+     * current_catch.getLabel(), catch_proto.catchType,
+     * catch_proto.catchVarName); Binding exception_storage =
+     * currentScope.getFlowManager().getFinallyContext().getExceptionStorage();
+     * current_catch.addInstruction(OP_newcatch, handler_number);
+     * current_catch.addInstruction(OP_dup); if ( exception_storage != null ) {
+     * current_catch.addInstruction(exception_storage.setlocal());
+     * current_catch.addInstruction(OP_dup); }
+     * current_catch.addInstruction(OP_pushscope);
+     * current_catch.addInstruction(OP_swap);
+     * current_catch.addInstruction(OP_setslot, 1);
+     * current_catch.addAll(catch_proto.catchBody); if (
+     * current_catch.canFallThrough() || current_catch.hasPendingLabels() ) {
+     * current_catch.addInstruction(OP_popscope); } return current_catch; }
+     */
+
+    /**
+     * Generate a compound assignment statement.
+     */
+    String generateCompoundAssignment(IASNode iNode, Binding operand, String expr, int opcode, boolean need_value)
+    {
+        String result = createInstruction(iNode, expr.length() + (operand.isLocal() ? 4 : 8));
+        /*
+         * if ( operand.isLocal() ) { result.addInstruction(operand.getlocal());
+         * result.addAll(expr); result.addInstruction(opcode); if ( need_value )
+         * result.addInstruction(OP_dup);
+         * result.addInstruction(operand.setlocal()); } else { Binding
+         * value_temp = null; result.addInstruction(OP_findpropstrict,
+         * operand.getName()); result.addInstruction(OP_dup);
+         * result.addInstruction(OP_getproperty, operand.getName());
+         * result.addAll(expr); result.addInstruction(opcode); if ( need_value )
+         * { value_temp = currentScope.allocateTemp();
+         * result.addInstruction(OP_dup);
+         * result.addInstruction(value_temp.setlocal()); }
+         * result.addInstruction(OP_setproperty, operand.getName()); if (
+         * need_value ) { result.addInstruction(value_temp.getlocal());
+         * result.addInstruction(value_temp.kill()); } }
+         */
+        final String op = opToString(iNode, opcode);
+        final String methodName = bindingToString(iNode, operand, true, true);
+        if (methodName.contains("."))
+        {
+            final String stem = methodName.substring(0, methodName.lastIndexOf("."));
+            final String member = getBasenameFromBinding(operand);
+            result += resolveSetterName(iNode, stem, makeMemberBinding(iNode, stem, member), op + "=", expr, false, true);
+        }
+        else
+        {
+            result += binaryOp(methodName, expr, op + "=");
+        }
+
+        if (need_value)
+            result = "(" + result + ")";
+        else
+            result += ";" + endl();
+
+        return result;
+    }
+
+    String generateCompoundBracketAssignment(IASNode iNode, String stem, String index, String expr, int opcode, boolean need_value)
+    {
+        String result = createInstruction(iNode, stem.length() * 2 + index.length() + expr.length() + 11);
+
+        /*
+         * // Although ASC evaluates the stem twice, it only evaluates the index
+         * once. // TODO: Inspect the index expression for side effects so the
+         * temp can be // elided in most cases. Binding index_temp =
+         * currentScope.allocateTemp(); result.addAll(index);
+         * result.addInstruction(index_temp.setlocal());
+         * result.addAll(replicate(stem));
+         * result.addInstruction(index_temp.getlocal());
+         * result.addInstruction(OP_getproperty); result.addAll(expr);
+         * result.addInstruction(opcode); Binding value_temp =
+         * currentScope.allocateTemp();
+         * result.addInstruction(value_temp.setlocal()); result.addAll(stem);
+         * result.addInstruction(index_temp.getlocal());
+         * result.addInstruction(value_temp.getlocal());
+         * result.addInstruction(OP_setproperty); if ( need_value )
+         * result.addInstruction(value_temp.getlocal());
+         * result.addAll(currentScope.releaseTemp(value_temp));
+         * result.addAll(currentScope.releaseTemp(index_temp));
+         */
+
+        // String result = binaryOp(stem + "[" + index + "]", expr, opcode + "="); 
+        final String op = opToString(iNode, opcode);
+        result += resolveSetterName(iNode, stem, makeMemberBinding(iNode, stem, index), op + "=", expr, true, true);
+        if (need_value)
+            result = "(" + result + ")";
+        else
+            result += ";" + endl();
+        return result;
+    }
+
+    String generateCompoundMemberAssignment(IASNode iNode, String stem, Binding member, String expr, int fetch_opcode, int assign_opcode, boolean need_value)
+    {
+        String result = createInstruction(iNode, stem.length() * 2 + expr.length() + 5);
+
+        /*
+         * // TODO: Depending on the resolution of ASC-4159 and // the
+         * corresponding Falcon backwards compatibility // issue, cache the stem
+         * expression in a local to avoid // multiple evaluations.
+         * result.addAll(replicate(stem)); result.addInstruction(fetch_opcode,
+         * member.getName()); result.addAll(expr);
+         * result.addInstruction(assign_opcode); if ( need_value ) {
+         * result.addInstruction(OP_dup); } result.addAll(stem);
+         * result.addInstruction(OP_swap); result.addInstruction(OP_setproperty,
+         * member.getName());
+         */
+
+        // String result = binaryOp(stem + "." + getBasenameFromBinding( member ), expr, opcode + "="); 
+        final String op = opToString(iNode, assign_opcode);
+        result += resolveSetterName(iNode, stem, member, op + "=", expr, false, true);
+        if (need_value)
+            result = "(" + result + ")";
+        else
+            result += ";" + endl();
+        return result;
+    }
+
+    String generateCompoundAssignmentToRuntimeName(IASNode iNode, RuntimeMultiname name, String expr, int opcode, boolean need_value)
+    {
+        String rhs = opToString(iNode, opcode) + "= " + expr;
+
+        return name.generateAssignment(iNode, rhs);
+    }
+
+    /**
+     * Generate a compound logical assignment expression to a named lvalue.
+     * 
+     * @param iNode - the assignment operator (root of the subtree).
+     * @param lvalue - the lvalue's name.
+     * @param expr - the expression to assign.
+     * @param is_and - true if the expression is &amp;&amp;=, false if it's ||=.
+     * @param need_value - true if the expression's not used in a void context.
+     */
+    String generateCompoundLogicalAssignment(IASNode iNode, Binding lvalue, String expr, boolean is_and, boolean need_value)
+    {
+        String result = createInstructionList(iNode);
+
+        /*
+         * Label tail = new Label(); int failure_test = is_and? OP_iffalse :
+         * OP_iftrue; if ( lvalue.isLocal() ) { // Fetch and test the current
+         * value. result.addInstruction(lvalue.getlocal()); // The current value
+         * may not be the result value, // but for now assume it is. if (
+         * need_value ) result.addInstruction( OP_dup); result.addInstruction(
+         * failure_test, tail ); // Test succeeded: reset the value, but first
+         * // pop the value speculatively dup'd above. if ( need_value )
+         * result.addInstruction(OP_pop); result.addAll(expr); if ( need_value )
+         * result.addInstruction(OP_dup);
+         * result.addInstruction(lvalue.setlocal()); } else { // Fetch,
+         * speculatively dup, and test the current value.
+         * result.addInstruction(OP_findpropstrict, lvalue.getName());
+         * result.addInstruction(OP_getproperty, lvalue.getName()); if (
+         * need_value ) result.addInstruction(OP_dup);
+         * result.addInstruction(failure_test, tail); if ( need_value )
+         * result.addInstruction(OP_pop); result.addAll(expr); if ( need_value )
+         * { result.addInstruction(OP_dup); }
+         * result.addInstruction(OP_findpropstrict, lvalue.getName());
+         * result.addInstruction(OP_swap); result.addInstruction(OP_setproperty,
+         * lvalue.getName()); } result.labelNext(tail);
+         */
+
+        final String lvalStr = bindingToString(iNode, lvalue, true, true);
+        result += lvalStr + " = (" + lvalStr + ") ";
+        if (is_and)
+            result += "&& ";
+        else
+            result += "|| ";
+        result += "(" + expr + ");\n";
+
+        return result;
+    }
+
+    /**
+     * Generate compound logical assignment to a runtime name, e.g., n::x ||=
+     * foo;
+     * 
+     * @param iNode - the root of the assignment subtree.
+     * @param name - the runtime name.
+     * @param expr - the second operand of the implied binary expression.
+     * @param is_and - true if the result is set to the second operand iff the
+     * first operand is true.
+     * @param need_value - true if the value of the assignment is required.
+     */
+    String generateCompoundLogicalRuntimeNameAssignment(IASNode iNode, RuntimeMultiname name, String expr, boolean is_and, boolean need_value)
+    {
+        return (is_and) ?
+                String.format("%s &&= %s", name.generateRvalue(iNode), expr)
+                :
+                String.format("%s ||= %s", name.generateRvalue(iNode), expr);
+    }
+
+    /**
+     * Generate a compound logical assignment expression to a a[i] type lvalue.
+     * 
+     * @param iNode - the assignment operator (root of the subtree).
+     * @param stem - the expression that generates the lvalue's stem, e.g., a in
+     * a[i]
+     * @param index - the index expression.
+     * @param expr - the expression to assign.
+     * @param is_and - true if the expression is &amp;&amp;=, false if it's ||=.
+     * @param need_value - true if the expression's not used in a void context.
+     */
+    String generateCompoundLogicalBracketAssignment(IASNode iNode, String stem, String index, String expr, boolean is_and, boolean need_value)
+    {
+        String result = createInstructionList(iNode);
+
+        /*
+         * String result = createInstructionList(iNode, stem.size() * 2 +
+         * index.size() + expr.size() + 11 ); Label tail = new Label(); int
+         * failure_test = is_and? OP_iffalse : OP_iftrue; // Although ASC
+         * evaluates the stem twice, it only evaluates the index once. // TODO:
+         * Inspect the index expression for side effects so the temp can be //
+         * elided in most cases. Binding index_temp =
+         * currentScope.allocateTemp(); result.addAll(index);
+         * result.addInstruction(index_temp.setlocal());
+         * result.addAll(replicate(stem));
+         * result.addInstruction(index_temp.getlocal()); result.addAll(stem);
+         * result.addInstruction(index_temp.getlocal());
+         * result.addInstruction(OP_getproperty); // Assume this is the result.
+         * result.addInstruction(OP_dup); result.addInstruction(failure_test,
+         * tail); // Pop the speculative result and assign the correct one.
+         * result.addInstruction(OP_pop); result.addAll(expr);
+         * result.labelNext(tail); Binding value_temp = null; if ( need_value )
+         * { value_temp = currentScope.allocateTemp();
+         * result.addInstruction(OP_dup);
+         * result.addInstruction(value_temp.setlocal()); }
+         * result.addInstruction(OP_setproperty); if ( need_value ) {
+         * result.addInstruction(value_temp.getlocal());
+         * result.addAll(currentScope.releaseTemp(value_temp)); }
+         * result.addAll(currentScope.releaseTemp(index_temp));
+         */
+
+        currentScope.addProblem(new JSUnsupportedFeatureProblem(iNode, "logical bracket assignment"));
+        return result;
+    }
+
+    /**
+     * Generate a compound logical assignment expression to a foo.bar type
+     * lvalue
+     * 
+     * @param iNode - the assignment operator (root of the subtree).
+     * @param stem - the expression that generates the lvalue's stem, e.g., a in
+     * a[i]
+     * @param index - the index expression.
+     * @param expr - the expression to assign.
+     * @param is_and - true if the expression is &amp;&amp;=, false if it's ||=.
+     * @param need_value - true if the expression's not used in a void context.
+     */
+    String generateCompoundLogicalMemberAssignment(IASNode iNode, String stem, Binding member, String expr, int fetch_opcode, boolean is_and, boolean need_value)
+    {
+        String result = createInstructionList(iNode);
+
+        /*
+         * Label tail = new Label(); int failure_test = is_and? OP_iffalse :
+         * OP_iftrue; result.addAll(replicate(stem)); result.addAll(stem);
+         * result.addInstruction(OP_getproperty, member.getName()); // Assume
+         * this is the result. result.addInstruction(OP_dup);
+         * result.addInstruction(failure_test, tail);
+         * result.addInstruction(OP_pop); result.addAll(expr);
+         * result.labelNext(tail); Binding value_temp = null; if ( need_value )
+         * { value_temp = currentScope.allocateTemp();
+         * result.addInstruction(OP_dup);
+         * result.addInstruction(value_temp.setlocal()); }
+         * result.addInstruction(OP_setproperty, member.getName()); if (
+         * need_value ) { result.addInstruction(value_temp.getlocal());
+         * result.addAll(currentScope.releaseTemp(value_temp)); }
+         */
+
+        currentScope.addProblem(new JSUnsupportedFeatureProblem(iNode, "logical member assignment"));
+        return result;
+
+    }
+
+    /**
+     * Generate a for/in or for each/in loop.
+     * 
+     * @param iNode - the for/in or for/each node.
+     * @param opcode - OP_nextname or OP_nextvalue.
+     * @param it - the name of the iterator variable, e.g., v in for (v in foo)
+     * {f(v);}.
+     * @param base - the source of names/values, e.g., foo in for (v in foo)
+     * {f(v);}.
+     * @param body - the loop body, e.g., {f(v);} in for (v in foo) {f(v);}.
+     */
+    private String generateForKeyOrValueLoop(IASNode iNode, int opcode, Binding it, String base, String body)
+    {
+        /*
+         * String result = new String(body.size() + base.size() + 15); Label
+         * test = new Label(); Label loop = new Label(); // Set up the object
+         * and index registers. LexicalScope.Hasnext2Wrapper hasnext =
+         * currentScope.hasnext2(); result.addInstruction(OP_pushbyte, 0);
+         * result.addInstruction(hasnext.index_temp.setlocal());
+         * result.addAll(base); result.addInstruction(OP_coerce_a);
+         * result.addInstruction(hasnext.stem_temp.setlocal()); // Go to the
+         * loop test. result.addInstruction(OP_jump, test); // Top of loop
+         * processing. result.addInstruction(OP_label);
+         * result.labelCurrent(loop); String nextvalue = new String(3);
+         * result.addInstruction(hasnext.stem_temp.getlocal());
+         * result.addInstruction(hasnext.index_temp.getlocal());
+         * nextvalue.addInstruction(opcode);
+         * result.addAll(generateAssignment(iNode, it, nextvalue));
+         * result.addAll(body); // Loop test. // It needs its own list so the
+         * continue target // can be properly resolved; this label is always //
+         * attached to the head of an String. String test_list = new String(1);
+         * test_list.addInstruction(hasnext.String);
+         * test_list.labelCurrent(test);
+         * currentScope.getFlowManager().resolveContinueLabel(test_list);
+         * test_list.addInstruction(OP_iftrue, loop); result.addAll(test_list);
+         * result.addAll(hasnext.release());
+         */
+
+        String result = new String();
+        return result;
+    }
+
+    /**
+     * generateFunctionBody() wrapper suitable for calling from the BURM. See
+     * JBurg ENHRQ <N> : the grammar that accepts the BURM's parameters to a
+     * JBurg.Reduction routine doesn't grok function calls, so the BURM cannot
+     * call generateFunctionBody(body, name.getName());
+     */
+    String generateFunctionBody(IASNode iNode, String function_body, Binding return_type)
+    {
+        return generateFunctionBody(iNode, function_body, return_type != null ? return_type.getName() : null);
+    }
+
+    /**
+     * Generate boilerplate function prolog/epilog code.
+     * 
+     * @param block - the actual CFG.
+     * @param return_type - the function's return type. Not presently used.
+     */
+    String generateFunctionBody(IASNode iNode, String function_body, Name return_type)
+    {
+        currentScope.getMethodInfo().setReturnType(return_type);
+        String result = "";
+        final String methodName = getMethodName();
+        final Boolean isAnonymousFunction = isAnonymousFunction(methodName);
+        final Boolean isCtor = methodName != null && methodName.equals(getCurrentClassName());
+
+        if (return_type != null)
+            usedTypes.add(getBasenameFromName(return_type));
+
+        /*
+         * !isAnonymousFunction is necessary. AS and JS are different in the way
+         * "this" is being treated in anonymous functions. i.e. public function
+         * whoIsThis() : void { const localFunction : Function = funciton():void
+         * { this.callMe(); }; } In this example this.callMe() refers to the
+         * callMe method of the class. In JS "this" refers to the local
+         * function! By supressing "var self = this;" for anonymous functions
+         * we'll emulate the AS behavior. The JS result then looks like this:
+         * tests.Test.whoIsThis.prototype = function() { var self = this; const
+         * localFunction : Function = funciton():void { // NOT EMITTED: var self
+         * = this; self.callMe(); }; };
+         */
+        if (!JSSharedData.m_useSelfParameter && !isAnonymousFunction &&
+                /* TODO: !needsSelfParameter(createFullClassName(false)) && */function_body.contains(JSSharedData.THIS))
+        {
+            // final Binding fullClassName = makeBinding(createFullClassName(false));
+            // this.registerLocalVariable(currentScope, makeBinding("self"), fullClassName, fullClassName);
+
+            final Binding fullClassName = new Binding(iNode, makeName(createFullClassName(false)), null);
+            this.registerLocalVariable(currentScope, new Binding(iNode, makeName("self"), null), fullClassName, fullClassName);
+            result += indentBlock("/** @type {" + createFullClassName(true) + "} */" + endl(), 1);
+            result += indentBlock("var " + JSSharedData.THIS + " = this;" + endl(), 1);
+        }
+
+        //  Constructor-specific processing: add the instance initializers,
+        //  add a constructsuper call if none exists.
+        if (haveAPrioriInstructions() && !isAnonymousFunction)
+        {
+            result += indentBlock(aPrioriInstructions, 1);
+
+            //  If this is a constructor and there's no explicit
+            //  super() call, synthesize one.
+            //  Note that this may be a semantic error if the 
+            //  superclass' constructor needs arguments.
+            /*
+             * if ( isCtor && !block.contains("super(") ) { // Call the
+             * superclass' constructor after the instance // init instructions;
+             * this doesn't seem like an abstractly // correct sequence, but
+             * it's what ASC does. result += "" // TODO: //
+             * result.addInstruction(OP_getlocal0); //
+             * result.addInstruction(OP_constructsuper, 0); }
+             */
+        }
+
+        // http://livedocs.adobe.com/flex/3/html/help.html?content=basic_as_2.html
+        // "If you define the constructor, but omit the call to super(), Flex automatically 
+        // calls super() at the beginning of your constructor."
+        if (isCtor)
+        {
+            if (function_body.indexOf(JSSharedData.m_superCalledMarker) >= 0)
+                function_body = function_body.replaceAll(JSSharedData.m_superCalledMarker, "");
+            else if (!function_body.contains("goog.base(this")) // we're only looking for super(), so ignore adobe.base() case
+            {
+                String derivedFrom = getCurrentSuperClassName();
+                if (derivedFrom != null && !isDataType(derivedFrom) && !derivedFrom.equals("Globals"))
+                {
+                    String superCall = indent();
+                    if (JSSharedData.m_useClosureLib)
+                    {
+                        // superCall += "goog.base(" + JSSharedData.ROOT_NAME + getCurrentFullClassName() + " /*generateFunctionBody*/";
+                        // superCall += ""goog.base(this"" + JSSharedData.THIS + " /*generateFunctionBody isCtor*/";
+                        superCall += "goog.base(this";
+                    }
+                    else
+                    {
+                        if (m_convertToStatic)
+                        {
+                            String fullClassName = createFullClassName(false);
+                            if (m_sharedData.hasClass(makeName(fullClassName)))
+                            {
+                                fullClassName = getCurrentSuperClassFullName();
+                                superCall += createFullName(fullClassName, true) + ".init(";
+                            }
+                            else
+                                superCall += createFullClassName(true) + "." + JSSharedData._SUPER + ".init(";
+                        }
+                        else
+                            superCall += JSSharedData.THIS + "." + JSSharedData._SUPER + "(";
+                        if (JSSharedData.m_useSelfParameter)
+                            superCall += JSSharedData.THIS;
+                    }
+                    superCall += "); /* Call to super() was missing in ctor! */" + endl();
+                    function_body = superCall + function_body;
+
+                    // workaround for Falcon bug.
+                    // The checker throws NoDefaultConstructorInBaseClassProblem if the ctor signatures
+                    // of base class and extended class don't match.
+                    // currentScope.getMethodBodySemanticChecker().checkDefaultSuperCall(iNode);
+                }
+            }
+        }
+
+        result += indentBlock(function_body, 1);
+
+        if (isCtor)
+        {
+            if (!result.contains(JSSharedData.THIS))
+            {
+                result += indentBlock("/** @type {" + createFullClassName(true) + "} */" + endl(), 1);
+                result += indentBlock("var " + JSSharedData.THIS + " = this;" + endl(), 1);
+            }
+            result += indentBlock("return " + JSSharedData.THIS + ";" + endl(), 1);
+        }
+
+        // popIndent();
+        // result += indent() + "}";
+        return result;
+    }
+
+    private IFunctionNode getFunctionNodeFromNode(IASNode iNode)
+    {
+        IFunctionNode fn = null;
+        if (iNode instanceof FunctionObjectNode)
+        {
+            FunctionObjectNode afn = (FunctionObjectNode)iNode;
+            fn = afn.getFunctionNode();
+        }
+        else if (iNode instanceof IFunctionNode)
+        {
+            fn = (IFunctionNode)iNode;
+        }
+
+        if (fn == null)
+            currentScope.addProblem(new JSInternalCompilerProblem(iNode, "cannot extract function node"));
+
+        return fn;
+    }
+
+    private IFunctionDefinition getFunctionDefinitionFromNode(IASNode iNode)
+    {
+        final IFunctionNode fn = getFunctionNodeFromNode(iNode);
+        return fn.getDefinition();
+    }
+
+    /**
+     * Generate a named nested function.
+     * 
+     * @param func_name - the function's name.
+     * @param return_type - the function's return type.
+     * @param function_body - the body of the function.
+     * @pre the function's lexical scope must be at the top of the lexical scope
+     * stack, with the declaring function's lexical scope under it.
+     * @post the nested function's MethodInfo is filled in, the function body is
+     * attached to its MethodBodyInfo, and the declaring function's
+     * initialization sequence gets code to declare the function.
+     */
+    private String generateNestedFunction(IASNode iNode, Binding func_name, Name return_type, String function_body)
+    {
+        final Boolean isAnonymousFunction = func_name == null && iNode instanceof FunctionObjectNode;
+
+        // only the outer function of a nested function should be converted to 
+        final Boolean convertLocalVarsToMembers = !isAnonymousFunction && convertLocalVarsToMembers(iNode);
+
+        String result = "";
+        if (!isAnonymousFunction)
+        {
+            currentScope.setFunctionName(getBasenameFromBinding(func_name));
+            result = generateFunctionBody(iNode, function_body, new Binding(iNode, return_type, null));
+        }
+
+        currentScope.generateNestedFunction(null);
+        //  Pull the nested function's MethodInfo out of its scope before we pop it.
+        MethodInfo nested_method_info = currentScope.getMethodInfo();
+
+        currentScope = currentScope.popFrame();
+
+        //  Intiialize the nested function; add a variable 
+        //  to the containing function scope and add 
+        //  newfunction/setproperty logic to the containing
+        //  function's hoisted initialization instructions.
+        if (!isAnonymousFunction && !convertLocalVarsToMembers)
+            currentScope.makeVariable(func_name);
+
+        /*
+         * String init_insns = currentScope.getHoistedInitInstructions();
+         * init_insns.addInstruction(OP_findproperty, func_name); //
+         * Optimization: declare the function at global scope // (in a utility
+         * namespace) and only new it once.
+         * init_insns.addInstruction(OP_newfunction, nested_method_info);
+         * init_insns.addInstruction(OP_setproperty, func_name);
+         */
+
+        {
+            final FunctionNode fn = (FunctionNode)getFunctionNodeFromNode(iNode);
+
+            // Workaround for Falcon bug.
+            // In theory, just using 
+            //     MethodInfo mi = currentScope.methodInfo;
+            // should work. But in 307387 the parameter names and types are empty.
+            // currentScope.methodInfo does contain the default values, because
+            // reduce_optionalParameter got called
+            if (!nested_method_info.hasParamNames())
+            {
+                MethodInfo miRepaired = JSGenerator.createMethodInfo(this, getEmitter(), currentScope, fn);
+                final Vector<PooledValue> defaultValues = nested_method_info.getDefaultValues();
+                for (PooledValue pv : defaultValues)
+                {
+                    miRepaired.addDefaultValue(pv);
+                }
+                nested_method_info = miRepaired;
+            }
+
+            String[] chunk = null;
+            try
+            {
+                // chunk = emitParameters(currentScope.getProject(), fn.getDefinition());
+                chunk = emitParameters(nested_method_info);
+            }
+            catch (Exception e)
+            {
+
+            }
+
+            final String a_priori_insns = chunk[0];
+            final String params = chunk[1];
+            final String baseName = getBasenameFromBinding(func_name);
+
+            // String result = generateFunction((IFunctionNode)__p, null, n, block, return_type );
+            result = "";
+
+            /*
+             * internal compiler error generated with optimize enabled compiling
+             * as3_enumerate.fla and fails to release the JS file
+             * http://watsonexp.corp.adobe.com/#bug=3047880 We have to emit
+             * something, otherwise you'd get:
+             * @type {function(, , )} as that happened in as3_enumerate
+             * MainTimeline. In the original MainTimeline.as change() is a local
+             * function with untyped parameters: function change(identifier,
+             * object, correct) which gets promoted to a method via
+             * [ConvertLocalVarsToMembers] of frame0(). It seems that there are
+             * two bugs: 1. JSDoc comments for functions with untyped parameters
+             * should use "*" instead:
+             * @type {function(*, *, *)} 2. JSDoc comments for promoted local
+             * functions should be omitted. The change below addresses #2.
+             */
+
+            // JSDoc
+            if (!convertLocalVarsToMembers)
+                result += getJSDocForFunction(nested_method_info);
+
+            /*
+             * @@@ if( !isAnonymousFunction && convertLocalVarsToMembers ) {
+             * result += getCurrentFullClassName() + ".prototype." + baseName +
+             * " = "; }
+             */
+
+            // support for [ConvertLocalVarsToMembers]
+            if (convertLocalVarsToMembers)
+            {
+                result += "\n";
+                if (a_priori_insns != null && !a_priori_insns.isEmpty())
+                    result += a_priori_insns + "\n";
+
+                if (!JSSharedData.m_useSelfParameter &&
+                        /*
+                         * TODO: !needsSelfParameter(createFullClassName(false))
+                         * &&
+                         */function_body.contains(JSSharedData.THIS) &&
+                        !function_body.contains("var " + JSSharedData.THIS))
+                {
+                    // final Binding fullClassName = makeBinding(createFullClassName(false));
+                    // this.registerLocalVariable(currentScope, makeBinding("self"), fullClassName, fullClassName);
+
+                    final Binding fullClassName = new Binding(iNode, makeName(createFullClassName(false)), null);
+                    this.registerLocalVariable(currentScope, new Binding(iNode, makeName("self"), null), fullClassName, fullClassName);
+                    result += indentBlock("/** @type {" + createFullClassName(true) + "} */" + endl(), 1);
+                    result += indentBlock("var " + JSSharedData.THIS + " = this;" + endl(), 1);
+                }
+
+                result += function_body;
+
+                final JSEmitter emitter = getEmitter();
+                final FunctionNode func = (FunctionNode)iNode;
+                final ITraitsVisitor itraits = emitter.getCurrentClassVisitor().visitInstanceTraits();
+                itraits.visitMethodTrait(DirectiveProcessor.functionTraitKind(func, TRAIT_Method), getNameFromBinding(func_name), 0, nested_method_info);
+
+                IMethodVisitor mv = emitter.visitMethod(nested_method_info);
+                mv.visit();
+
+                MethodBodyInfo mbi = new MethodBodyInfo();
+                mbi.setMethodInfo(nested_method_info);
+
+                IMethodBodyVisitor mbv = mv.visitBody(mbi);
+                mbv.visit();
+
+                InstructionList insns = new InstructionList();
+                insns.addInstruction(JSSharedData.OP_JS, result);
+
+                mbv.visitInstructionList(insns);
+
+                mbv.visitEnd();
+                mv.visitEnd();
+
+                result = "";
+
+                /*
+                 * internal compiler error generated with optimize enabled
+                 * compiling as3_enumerate.fla and fails to release the JS file
+                 * We have to emit something, otherwise you'd get:
+                 * @type {function(, , )} as that happened in as3_enumerate
+                 * MainTimeline. In the original MainTimeline.as change() is a
+                 * local function with untyped parameters: function
+                 * change(identifier, object, correct) which gets promoted to a
+                 * method via [ConvertLocalVarsToMembers] of frame0(). It seems
+                 * that there are two bugs: 1. JSDoc comments for functions with
+                 * untyped parameters should use "*" instead:
+                 * @type {function(*, *, *)} 2. JSDoc comments for promoted
+                 * local functions should be omitted. The change below addresses
+                 * #2.
+                 */
+                // result += getJSDocForFunction(nested_method_info);
+
+                this.registerConvertedMember(baseName);
+
+                // result += "\nvar " + baseName + " /* : Function */ = " + JSSharedData.THIS + "." + baseName + ";\n";
+            }
+            else
+            {
+                if (isAnonymousFunction)
+                    result += "function";
+                else
+                    result += "\nfunction " + baseName;
+
+                result += "(" + params + ")";
+
+                final Name retType = nested_method_info.getReturnType();
+                if (retType != null)
+                    result += " /* : " + getBasenameFromName(retType) + " */";
+                else
+                    result += " /* : void */";
+
+                result += indent() + "\n";
+                result += indent() + "{\n";
+                if (a_priori_insns != null && !a_priori_insns.isEmpty())
+                    result += indentBlock(a_priori_insns, 1) + "\n";
+                result += indentBlock(function_body, 1);
+                result += indent() + "}";
+                if (!isAnonymousFunction)
+                    result += "\n";
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * Generate a try/catch/finally (or try/finally) compound statement.
+     * 
+     * @param try_stmt - the body of the try block.
+     * @param catch_blocks - associated catch blocks. May be null if no catch
+     * blocks are present.
+     * @param finally_stmt - the body of the finally block.
+     */
+    String generateTryCatchFinally(IASNode iNode, String try_stmt, Vector<CatchPrototype> catch_blocks, String finally_stmt)
+    {
+        /*
+         * // TODO: Optimize these String sizes. String normal_flow_fixup = new
+         * String(); String catch_insns = new String(); String final_catch = new
+         * String(); String finally_insns = new String(); String final_throw =
+         * new String(); ExceptionHandlingContext finally_context =
+         * currentScope.getFlowManager().getFinallyContext(); Label
+         * final_catch_target = final_catch.getLabel(); // We need a local to
+         * store the caught exception. Binding exception_storage =
+         * finally_context.getExceptionStorage(); Collection<Label>
+         * pending_normal_control_flow = try_stmt.stripPendingLabels(); if (
+         * try_stmt.canFallThrough() || pending_normal_control_flow != null ) {
+         * normal_flow_fixup.addInstruction(OP_jump,
+         * finally_context.finallyBlock); } else { // Extend the region past a
+         * terminating // throw statement to give the AVM a // little buffer to
+         * figure out its // exception-handling regions.
+         * normal_flow_fixup.addInstruction(OP_nop); } Label try_start =
+         * try_stmt.getLabel(); Label try_end =
+         * normal_flow_fixup.getLastLabel(); Label finally_region_end = null; if
+         * ( null == catch_blocks ) { finally_region_end = try_end; } else { for
+         * ( CatchPrototype catch_proto: catch_blocks ) { String catch_body =
+         * generateCatchBlock(try_start, try_end, catch_proto); boolean
+         * is_last_catch = catch_proto.equals(catch_blocks.lastElement()); if (
+         * catch_body.canFallThrough() ) { // Signal the finally block that this
+         * execution succeeded. catch_body.addInstruction(OP_pushbyte, 0);
+         * catch_body.addInstruction(OP_coerce_a);
+         * catch_body.addInstruction(finally_context
+         * .finallyReturnStorage.setlocal()); catch_body.addInstruction(OP_jump,
+         * finally_context.finallyBlock); } else if ( is_last_catch ) { //
+         * Extend the region past a terminating throw // insn to give the AVM a
+         * little buffer. catch_body.addInstruction(OP_nop); } if (
+         * is_last_catch ) finally_region_end = catch_body.getLastLabel();
+         * catch_insns.addAll(catch_body); } } // Set up the exception handler
+         * for the finally block.
+         * currentScope.getMethodBodyVisitor().visitException(try_start,
+         * finally_region_end, final_catch_target, null, null); // The final
+         * catch block only needs to save the // caught exception for a rethrow.
+         * final_catch.addInstruction(OP_getlocal0);
+         * final_catch.addInstruction(OP_pushscope); if(
+         * currentScope.needsActivation() ) { // Restore the activation object
+         * final_catch
+         * .addInstruction(currentScope.getActivationStorage().getlocal());
+         * final_catch.addInstruction(OP_pushscope); }
+         * final_catch.addAll(currentScope
+         * .getFlowManager().getScopeStackReinit());
+         * final_catch.addInstruction(exception_storage.setlocal()); // Signal
+         * the finally epilog that this execution failed // and should rethrow.
+         * final_catch.addInstruction(OP_pushbyte,
+         * currentScope.getFlowManager().getFinallyAlternativesSize() + 1);
+         * final_catch.addInstruction(OP_coerce_a);
+         * final_catch.addInstruction(finally_context
+         * .finallyReturnStorage.setlocal()); // falls through //
+         * final_catch.addInstruction(OP_jump, finally_head);
+         * finally_insns.addInstruction
+         * (finally_context.finallyReturnStorage.getlocal());
+         * finally_insns.addInstruction(OP_convert_i);
+         * finally_insns.addInstruction
+         * (finally_context.finallyReturnStorage.kill());
+         * finally_insns.addAll(currentScope
+         * .getFlowManager().getFinallySwitch()); // Label the start of the
+         * final set of Strings. if (!finally_stmt.isEmpty()) {
+         * finally_stmt.labelFirst(finally_context.finallyBlock); } else // This
+         * is just an expedient for this degenerate finally.
+         * finally_insns.labelFirst(finally_context.finallyBlock);
+         * final_throw.addInstruction(exception_storage.getlocal());
+         * final_throw.labelCurrent(finally_context.finallyDoRethrow);
+         * final_throw.addInstruction(OP_throw); // Assemble the statement.
+         * String result = new String(); // Initialize the finally return
+         * storage location to appease // legacy verifiers. // TODO: This could
+         * travel on the value stack. // See:
+         * http://bugs.adobe.com/jira/browse/CMP-104
+         * result.addInstruction(OP_pushbyte, 0);
+         * result.addInstruction(OP_coerce_a);
+         * result.addInstruction(finally_context
+         * .finallyReturnStorage.setlocal()); result.addAll(try_stmt); // Send
+         * all "next statement" type control flow into the finally block.
+         * result.addAllPendingLabels(pending_normal_control_flow);
+         * result.addAll(normal_flow_fixup); result.addAll(catch_insns);
+         * result.addAll(final_catch); result.addAll(finally_stmt);
+         * result.addAll(finally_insns); result.addAll(final_throw); for (
+         * ExceptionHandlingContext.FinallyReturn retblock:
+         * finally_context.finallyReturns )
+         * result.addAll(retblock.getStrings()); // TODO: Need more analysis of
+         * how this temp travels through // the system before it can be safely
+         * released. For now // just leak it.
+         * //result.addAll(currentScope.releaseTemp(exception_storage)); //
+         * TODO: Removing a hanging kill exposed a latent bug // in
+         * hasPendingLabels() and end-of-routine processing. // Give the CG a
+         * harmless String that will generate // a returnvoid if this is the
+         * last statement in the routine. result.addInstruction(OP_nop); //
+         * Fallthrough out of the finally block.
+         * result.labelNext(finally_context.finallyDoFallthrough);
+         */
+
+        // statement = Pattern tryCatchFinallyStmt
+        String result = "";
+
+        //  Do nothing if the try statement's empty.
+        if (try_stmt.length() == 0)
+            return result;
+
+        result = indent() + "try" + endl();
+        result += indent() + "{" + endl();
+        result += indentBlock(try_stmt, 1);
+        result += indent() + "}" + endl();
+
+        if (catch_blocks != null)
+        {
+            for (CatchPrototype catch_proto : (Vector<CatchPrototype>)catch_blocks)
+            {
+                final Binding nameBinding = new Binding(iNode, catch_proto.catchVarName, null);
+                Binding typeBinding;
+                if (catch_proto.catchType == null)
+                    typeBinding = new Binding(iNode, makeName("*"), null);
+                else
+                    typeBinding = new Binding(iNode, catch_proto.catchType, null);
+
+                registerLocalVariable(currentScope, nameBinding, typeBinding, typeBinding);
+
+                result += indent() + "catch(";
+                if (catch_proto.catchType != null)
+                {
+                    final StringBuilder sb = new StringBuilder();
+                    if (!nameToJSDocType(iNode, typeBinding.getName(), sb))
+                        m_needsSecondPass = true;
+                    result += "/** @type {" + sb.toString() + "}*/ ";
+                }
+                result += getBasenameFromName(catch_proto.catchVarName);
+                if (catch_proto.catchType != null)
+                    result += " /* : " + getBasenameFromBinding(typeBinding) + "*/";
+                result += ")" + endl();
+                result += indent() + "{" + endl();
+
+                if (catch_proto.catchBody.length() > 0)
+                    result += indentBlock(catch_proto.catchBody, 1);
+
+                // boolean is_last_catch = catch_proto.equals(catch_blocks.lastElement());
+                //if( !is_last_catch && canFallThrough(catch_body) )
+                //    catch_body.addInstruction(OP_jump, catch_tail);
+
+                result += indent() + "}" + endl();
+            }
+        }
+
+        if (finally_stmt != null && finally_stmt.length() != 0)
+        {
+            result += indent() + "finally" + endl();
+            result += indent() + "{" + endl();
+            result += indentBlock(finally_stmt, 1);
+            result += indent() + "}" + endl();
+        }
+
+        return result;
+    }
+
+    public String reduce_typeNameParameter(IASNode iNode, Binding param_name)
+    {
+        StringBuilder result = new StringBuilder();
+
+        generateTypeNameParameter(iNode, param_name.getName(), result);
+
+        return result.toString();
+    }
+
+    /**
+     * Generate the String sequence that designates the parameter of a
+     * parameterized type, e.g., String in Vector.&lt;String&gt; or * in
+     * Vector.&lt;*&gt;.
+     * 
+     * @param name - the type parameter's name. May be null in the * case.
+     * @param result - the String sequence to generate into.
+     */
+    void generateTypeNameParameter(IASNode iNode, Name param_name, StringBuilder result)
+    {
+        if (param_name == null || param_name.couldBeAnyType())
+            result.append("null");
+        else
+            generateAccess(iNode, param_name, result);
+    }
+
+    /**
+     * Find the specified break target.
+     * 
+     * @param criterion - the search criterion.
+     * @throws UnknownControlFlowTargetException if the criterion is not on the
+     * control-flow stack.
+     */
+    /*
+     * private String getBreakTarget(Object criterion) throws
+     * UnknownControlFlowTargetException { return
+     * currentScope.getFlowManager().getBreakTarget(criterion); }
+     */
+
+    /**
+     * Find the specified continue label.
+     * 
+     * @param criterion - the search criterion.
+     * @throws UnknownControlFlowTargetException if the criterion is not on the
+     * control-flow stack.
+     */
+    /*
+     * private String getContinueLabel(Object criterion) throws
+     * UnknownControlFlowTargetException { return
+     * currentScope.getFlowManager().getContinueLabel(criterion); }
+     */
+
+    /**
+     * @return the double content of a numeric literal.
+     * @param iNode - the literal node.
+     */
+    Double getDoubleContent(IASNode iNode)
+    {
+        return new Double(((INumericLiteralNode)iNode).getNumericValue().toNumber());
+    }
+
+    /**
+     * @return the name of an identifier.
+     * @param iNode - the IIdentifier node.
+     */
+    String getIdentifierContent(IASNode iNode)
+    {
+        return ((IIdentifierNode)iNode).getName();
+    }
+
+    /**
+     * @return the int content of a numeric literal.
+     * @param iNode - the literal node.
+     */
+    Integer getIntegerContent(IASNode iNode)
+    {
+        return new Integer(((INumericLiteralNode)iNode).getNumericValue().toInt32());
+    }
+
+    /**
+     * @return always zero.
+     * @param iNode - the literal node.
+     */
+    Integer getIntegerZeroContent(IASNode iNode)
+    {
+        return 0;
+    }
+
+    /**
+     * @return always zero.
+     * @param iNode - the literal node.
+     */
+    Long getIntegerZeroContentAsLong(IASNode iNode)
+    {
+        return 0L;
+    }
+
+    /**
+     * @return a node cast to MXMLEventSpecifierNode type.
+     * @param iNode - the MXMLEventSpecifierNode node.
+     */
+    IMXMLEventSpecifierNode getMXMLEventSpecifierContent(IASNode iNode)
+    {
+        return (IMXMLEventSpecifierNode)iNode;
+    }
+
+    /**
+     * Find all active exception handling blocks or scopes, and set up finally
+     * return sequences and/or popscopes.
+     * 
+     * @param original - the original control-flow sequence.
+     * @param criterion - the search criterion that identifies the boundary of
+     * the region to be exited.
+     * @return a control-flow sequence that is either the original sequence or
+     * the start of a trampoline of finally blocks, popscopes, and whatever else
+     * is necessary to exit the control-flow region.
+     * @throws UnknownControlFlowTargetException if the criterion is not on the
+     * control-flow stack.
+     */
+    /*
+     * private String getNonLocalControlFlow(String original, Object criterion)
+     * throws UnknownControlFlowTargetException { return
+     * currentScope.getFlowManager().getNonLocalControlFlow(original,
+     * criterion); }
+     */
+
+    /**
+     * @return a parameter's definition.
+     * @param iNode - the parameter node.
+     */
+    IDefinition getParameterContent(IASNode iNode)
+    {
+        return (((IParameterNode)iNode).getDefinition());
+    }
+
+    /**
+     * @return the string content of a literal.
+     * @param iNode - the literal node.
+     */
+    String getStringLiteralContent(IASNode iNode)
+    {
+        // Literals.
+        // Pattern stringLiteral
+        // LiteralStringID(void);
+        String s = ((ILiteralNode)iNode).getValue();
+        if (s == null || s.length() == 0)
+            return "''";
+
+        s = s.replaceAll("\n", "__NEWLINE_PLACEHOLDER__");
+        s = s.replaceAll("\r", "__CR_PLACEHOLDER__");
+        s = s.replaceAll("\t", "__TAB_PLACEHOLDER__");
+        s = s.replaceAll("\f", "__FORMFEED_PLACEHOLDER__");
+        s = s.replaceAll("\b", "__BACKSPACE_PLACEHOLDER__");
+        s = s.replaceAll("\\\\\"", "__QUOTE_PLACEHOLDER__");
+        s = s.replaceAll("\\\\", "__ESCAPE_PLACEHOLDER__");
+        s = "\"" + s.replaceAll("\"", "\\\\\"") + "\"";
+        s = s.replaceAll("__ESCAPE_PLACEHOLDER__", "\\\\\\\\");
+        s = s.replaceAll("__QUOTE_PLACEHOLDER__", "\\\\\"");
+        s = s.replaceAll("__BACKSPACE_PLACEHOLDER__", "\\\\b");
+        s = s.replaceAll("__FORMFEED_PLACEHOLDER__", "\\\\f");
+        s = s.replaceAll("__TAB_PLACEHOLDER__", "\\\\t");
+        s = s.replaceAll("__CR_PLACEHOLDER__", "\\\\r");
+        s = s.replaceAll("__NEWLINE_PLACEHOLDER__", "\\\\n");
+
+        // Note: we don't try to preserve \ u NNNN or \ x NN escape codes, since the actual Unicode chars can appear
+        // inside the literal just fine (unless they translate to one of the above chars, e.g. CR, in which case
+        // the above substitutions will occur.
+
+        return s;
+    }
+
+    /**
+     * @return the uint content of a numeric literal.
+     * @param iNode - the literal node.
+     */
+    Long getUintContent(IASNode iNode)
+    {
+        return new Long(((INumericLiteralNode)iNode).getNumericValue().toUint32());
+    }
+
+    /**
+     * @return the Boolean content of a BOOLEAN literal.
+     * @param iNode - the literal node.
+     */
+    boolean getBooleanContent(IASNode iNode)
+    {
+        return SemanticUtils.getBooleanContent(iNode);
+    }
+
+    /**
+     * @return true if a priori Strings are present.
+     */
+    /*
+     * private boolean haveinstanceInitializers() { return instanceInitializers
+     * != null; }
+     */
+
+    /*
+     * *******************************
+     * ** Cost/Decision Functions ** *******************************
+     */
+
+    /**
+     * Explore a MemberAccessNode and decide if its stem is a reference to a
+     * package.
+     */
+    int isDottedName(IASNode n)
+    {
+        int result = Integer.MAX_VALUE;
+
+        if (n instanceof MemberAccessExpressionNode)
+        {
+            MemberAccessExpressionNode ma = (MemberAccessExpressionNode)n;
+
+            if (ma.stemIsPackage())
+                // This needs to be greater than the value returned from isPackageName,
+                // so that isPackageName wins
+                result = 2;
+        }
+
+        return result;
+    }
+
+    /**
+     * Explore a MemberAccessNode and decide if it is a reference to a package.
+     */
+    int isPackageName(IASNode n)
+    {
+        int result = Integer.MAX_VALUE;
+
+        if (n instanceof MemberAccessExpressionNode)
+        {
+            MemberAccessExpressionNode ma = (MemberAccessExpressionNode)n;
+
+            if (ma.isPackageReference())
+                // This needs to be less than the value returned from isDottedName,
+                // so that isPackageName wins
+                result = 1;
+        }
+
+        return result;
+    }
+
+    /**
+     * Check if the given AST (the root AST of a looping construct) is in the
+     * set of active labeled control-flow contexts. If it is, then its
+     * control-flow context is being managed by the labeledStatement production
+     * that's reducing the loop's LabeledStatementNode, and the loop should use
+     * that context so that the labeled context's continue label is resolved to
+     * the correct top-of-loop location.
+     * 
+     * @param loop_node - the AST at the root of the loop.
+     * @return true if loop_node is known to be the substatment of a labeled
+     * statement.
+     */
+    private boolean isLabeledSubstatement(IASNode loop_node)
+    {
+        return labeledNodes.contains(loop_node);
+    }
+
+    /**
+     * Get the definition associated with a node's qualifier and decide if the
+     * qualifier is a compile-time constant.
+     * 
+     * @param iNode - the node to check.
+     * @pre - the node has an IdentifierNode 0th child.
+     * @return an attractive cost if the child has a known namespace, i.e., it's
+     * a compile-time constant qualifier.
+     */
+    int qualifierIsCompileTimeConstant(IASNode iNode)
+    {
+        IdentifierNode qualifier = (IdentifierNode)SemanticUtils.getNthChild(iNode, 0);
+        IDefinition def = qualifier.resolve(currentScope.getProject());
+
+        int result = def instanceof NamespaceDefinition ? 1 : Integer.MAX_VALUE;
+        return result;
+    }
+
+    /**
+     * Get the definition associated with a node's qualifier and decide if the
+     * qualifier is an interface name.
+     * 
+     * @param iNode - the node to check.
+     * @pre - the node has an IdentifierNode 0th child.
+     * @return an attractive cost if the child is an interface.
+     */
+    int qualifierIsInterface(IASNode iNode)
+    {
+        IdentifierNode qualifier = (IdentifierNode)SemanticUtils.getNthChild(iNode, 0);
+        IDefinition def = qualifier.resolve(currentScope.getProject());
+
+        int result = def instanceof InterfaceDefinition ? 1 : Integer.MAX_VALUE;
+        return result;
+
+    }
+
+    /**
+     * @return a feasible cost if a node has a compile-time constant defintion.
+     */
+    int isCompileTimeConstant(IASNode iNode)
+    {
+        if (SemanticUtils.transformNameToConstantValue(iNode, currentScope.getProject()) != null)
+            return 1;
+        else
+            return Integer.MAX_VALUE;
+    }
+
+    /**
+     * @return a feasible cost if the function call node is a call to a constant
+     * function.
+     */
+    int isCompileTimeConstantFunction(IASNode iNode)
+    {
+        //if ( SemanticUtils.isConstantFunction(currentScope.getProject(), iNode)  )
+        //    return 1;
+        // else
+        return Integer.MAX_VALUE;
+    }
+
+    /**
+     * @return a feasible cost if a parameterized type's base and parameter
+     * types are resolved types, ERROR_TRAP if not.
+     */
+    int parameterTypeIsConstant(IASNode iNode)
+    {
+        return Math.max(
+                isKnownType(SemanticUtils.getNthChild(iNode, 0)),
+                isKnownType(SemanticUtils.getNthChild(iNode, 1))
+                );

[... 9544 lines stripped ...]


Mime
View raw message