Reorganize AST traversal utility code

Define TIntermTraverser and TIntermLValueTrackingTraverser in a
separate header file. hash() function is moved out from
TIntermTraverser as it is not related to the core functionality
of traversing and transforming ASTs.

Also reorganize some traversers to follow common conventions:

- Intermediate output is now in OutputTree.h/.cpp
- Max tree depth check is now in IsASTDepthBelowLimit.h/.cpp

BUG=angleproject:1490
TEST=angle_unittests

Change-Id: Id4968aa9d4e24d0c5bac90dc147fc9f310de0184
Reviewed-on: https://chromium-review.googlesource.com/559531
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ASTMetadataHLSL.cpp b/src/compiler/translator/ASTMetadataHLSL.cpp
index 80a8ab6..b04fc28 100644
--- a/src/compiler/translator/ASTMetadataHLSL.cpp
+++ b/src/compiler/translator/ASTMetadataHLSL.cpp
@@ -9,6 +9,7 @@
 #include "compiler/translator/ASTMetadataHLSL.h"
 
 #include "compiler/translator/CallDAG.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
diff --git a/src/compiler/translator/AddAndTrueToLoopCondition.cpp b/src/compiler/translator/AddAndTrueToLoopCondition.cpp
index 0177fea..6a05104 100644
--- a/src/compiler/translator/AddAndTrueToLoopCondition.cpp
+++ b/src/compiler/translator/AddAndTrueToLoopCondition.cpp
@@ -6,7 +6,7 @@
 
 #include "compiler/translator/AddAndTrueToLoopCondition.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
index 5fc885f..8d1594b 100644
--- a/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
+++ b/src/compiler/translator/ArrayReturnValueToOutParameter.cpp
@@ -9,7 +9,7 @@
 
 #include "compiler/translator/ArrayReturnValueToOutParameter.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp b/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
index 018e72c..ff78de8 100644
--- a/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
+++ b/src/compiler/translator/BreakVariableAliasingInInnerLoops.cpp
@@ -10,7 +10,7 @@
 
 #include "BreakVariableAliasingInInnerLoops.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 // A HLSL compiler developer gave us more details on the root cause and the workaround needed:
 //     The root problem is that if the HLSL compiler is applying aliasing information even on
diff --git a/src/compiler/translator/BuiltInFunctionEmulator.cpp b/src/compiler/translator/BuiltInFunctionEmulator.cpp
index eece151..07508d3 100644
--- a/src/compiler/translator/BuiltInFunctionEmulator.cpp
+++ b/src/compiler/translator/BuiltInFunctionEmulator.cpp
@@ -4,10 +4,11 @@
 // found in the LICENSE file.
 //
 
-#include "angle_gl.h"
 #include "compiler/translator/BuiltInFunctionEmulator.h"
-#include "compiler/translator/SymbolTable.h"
+#include "angle_gl.h"
 #include "compiler/translator/Cache.h"
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/SymbolTable.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/CallDAG.cpp b/src/compiler/translator/CallDAG.cpp
index 8557fdf..5f54e80 100644
--- a/src/compiler/translator/CallDAG.cpp
+++ b/src/compiler/translator/CallDAG.cpp
@@ -11,6 +11,7 @@
 #include "compiler/translator/CallDAG.h"
 
 #include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
diff --git a/src/compiler/translator/Compiler.cpp b/src/compiler/translator/Compiler.cpp
index eebc7c8..90bb7f7 100644
--- a/src/compiler/translator/Compiler.cpp
+++ b/src/compiler/translator/Compiler.cpp
@@ -20,6 +20,8 @@
 #include "compiler/translator/Initialize.h"
 #include "compiler/translator/InitializeVariables.h"
 #include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IsASTDepthBelowLimit.h"
+#include "compiler/translator/OutputTree.h"
 #include "compiler/translator/ParseContext.h"
 #include "compiler/translator/PruneEmptyDeclarations.h"
 #include "compiler/translator/RegenerateStructNames.h"
@@ -578,7 +580,7 @@
     if (root)
     {
         if (compileOptions & SH_INTERMEDIATE_TREE)
-            TIntermediate::outputTree(root, infoSink.info);
+            OutputTree(root, infoSink.info);
 
         if (compileOptions & SH_OBJECT_CODE)
             translate(root, compileOptions);
@@ -910,10 +912,7 @@
 
 bool TCompiler::limitExpressionComplexity(TIntermBlock *root)
 {
-    TMaxDepthTraverser traverser(maxExpressionComplexity + 1);
-    root->traverse(&traverser);
-
-    if (traverser.getMaxDepth() > maxExpressionComplexity)
+    if (!IsASTDepthBelowLimit(root, maxExpressionComplexity))
     {
         mDiagnostics.globalError("Expression too complex.");
         return false;
diff --git a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
index 9e053c7..eacd289 100644
--- a/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
+++ b/src/compiler/translator/DeclareAndInitBuiltinsForInstancedMultiview.cpp
@@ -11,7 +11,7 @@
 
 #include "compiler/translator/FindMain.h"
 #include "compiler/translator/InitializeVariables.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
diff --git a/src/compiler/translator/EmulateGLFragColorBroadcast.cpp b/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
index b14438a..17ce886 100644
--- a/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
+++ b/src/compiler/translator/EmulateGLFragColorBroadcast.cpp
@@ -14,7 +14,7 @@
 #include "compiler/translator/EmulateGLFragColorBroadcast.h"
 
 #include "compiler/translator/FindMain.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/EmulatePrecision.h b/src/compiler/translator/EmulatePrecision.h
index ed15395..ac7b327 100644
--- a/src/compiler/translator/EmulatePrecision.h
+++ b/src/compiler/translator/EmulatePrecision.h
@@ -7,11 +7,11 @@
 #ifndef COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
 #define COMPILER_TRANSLATOR_EMULATE_PRECISION_H_
 
+#include "GLSLANG/ShaderLang.h"
 #include "common/angleutils.h"
 #include "compiler/translator/Compiler.h"
 #include "compiler/translator/InfoSink.h"
-#include "compiler/translator/IntermNode.h"
-#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/IntermTraverse.h"
 
 // This class gathers all compound assignments from the AST and can then write
 // the functions required for their precision emulation. This way there is no
diff --git a/src/compiler/translator/ExpandIntegerPowExpressions.cpp b/src/compiler/translator/ExpandIntegerPowExpressions.cpp
index 8261e86..bad554a 100644
--- a/src/compiler/translator/ExpandIntegerPowExpressions.cpp
+++ b/src/compiler/translator/ExpandIntegerPowExpressions.cpp
@@ -11,7 +11,7 @@
 #include <cmath>
 #include <cstdlib>
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/ExtensionGLSL.h b/src/compiler/translator/ExtensionGLSL.h
index 3c2dbe0..a1b9cb2 100644
--- a/src/compiler/translator/ExtensionGLSL.h
+++ b/src/compiler/translator/ExtensionGLSL.h
@@ -12,7 +12,7 @@
 #include <set>
 #include <string>
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/FindSymbolNode.cpp b/src/compiler/translator/FindSymbolNode.cpp
index 87fb9d5..a2a10f1 100644
--- a/src/compiler/translator/FindSymbolNode.cpp
+++ b/src/compiler/translator/FindSymbolNode.cpp
@@ -8,7 +8,7 @@
 
 #include "compiler/translator/FindSymbolNode.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/FlagStd140Structs.h b/src/compiler/translator/FlagStd140Structs.h
index 672b20d..ab904c2 100644
--- a/src/compiler/translator/FlagStd140Structs.h
+++ b/src/compiler/translator/FlagStd140Structs.h
@@ -7,7 +7,7 @@
 #ifndef COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
 #define COMPILER_TRANSLATOR_FLAGSTD140STRUCTS_H_
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/HashNames.cpp b/src/compiler/translator/HashNames.cpp
new file mode 100644
index 0000000..369ef13
--- /dev/null
+++ b/src/compiler/translator/HashNames.cpp
@@ -0,0 +1,23 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/HashNames.h"
+
+namespace sh
+{
+
+TString HashName(const TString &name, ShHashFunction64 hashFunction)
+{
+    if (hashFunction == nullptr || name.empty())
+        return name;
+    khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
+    TStringStream stream;
+    stream << HASHED_NAME_PREFIX << std::hex << number;
+    TString hashedName = stream.str();
+    return hashedName;
+}
+
+}  // namespace sh
diff --git a/src/compiler/translator/HashNames.h b/src/compiler/translator/HashNames.h
index 09c959f..b1cb195 100644
--- a/src/compiler/translator/HashNames.h
+++ b/src/compiler/translator/HashNames.h
@@ -9,10 +9,20 @@
 
 #include <map>
 
-#include "compiler/translator/IntermNode.h"
+#include "GLSLANG/ShaderLang.h"
+#include "compiler/translator/Common.h"
 
 #define HASHED_NAME_PREFIX "webgl_"
 
+namespace sh
+{
+
 typedef std::map<TPersistString, TPersistString> NameMap;
 
+// Return the original name if hash function pointer is NULL;
+// otherwise return the hashed name.
+TString HashName(const TString &name, ShHashFunction64 hashFunction);
+
+}  // namespace sh
+
 #endif  // COMPILER_TRANSLATOR_HASHNAMES_H_
diff --git a/src/compiler/translator/InitializeVariables.cpp b/src/compiler/translator/InitializeVariables.cpp
index 0cd3d7c..988427c 100644
--- a/src/compiler/translator/InitializeVariables.cpp
+++ b/src/compiler/translator/InitializeVariables.cpp
@@ -9,7 +9,7 @@
 #include "angle_gl.h"
 #include "common/debug.h"
 #include "compiler/translator/FindMain.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/util.h"
 
diff --git a/src/compiler/translator/IntermNode.cpp b/src/compiler/translator/IntermNode.cpp
index 0e3722c..4c6db97 100644
--- a/src/compiler/translator/IntermNode.cpp
+++ b/src/compiler/translator/IntermNode.cpp
@@ -18,7 +18,6 @@
 #include "common/mathutil.h"
 #include "common/matrix_utils.h"
 #include "compiler/translator/Diagnostics.h"
-#include "compiler/translator/HashNames.h"
 #include "compiler/translator/IntermNode.h"
 #include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/util.h"
@@ -3306,149 +3305,4 @@
     return resultArray;
 }
 
-// static
-TString TIntermTraverser::hash(const TString &name, ShHashFunction64 hashFunction)
-{
-    if (hashFunction == nullptr || name.empty())
-        return name;
-    khronos_uint64_t number = (*hashFunction)(name.c_str(), name.length());
-    TStringStream stream;
-    stream << HASHED_NAME_PREFIX << std::hex << number;
-    TString hashedName = stream.str();
-    return hashedName;
-}
-
-bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
-                                        const NodeInsertMultipleEntry &b)
-{
-    if (a.parent != b.parent)
-    {
-        return a.parent > b.parent;
-    }
-    return a.position > b.position;
-}
-
-void TIntermTraverser::updateTree()
-{
-    // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
-    // the same parent node are handled correctly.
-    std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
-    for (size_t ii = 0; ii < mInsertions.size(); ++ii)
-    {
-        // We can't know here what the intended ordering of two insertions to the same position is,
-        // so it is not supported.
-        ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
-               mInsertions[ii].parent != mInsertions[ii - 1].parent);
-        const NodeInsertMultipleEntry &insertion = mInsertions[ii];
-        ASSERT(insertion.parent);
-        if (!insertion.insertionsAfter.empty())
-        {
-            bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
-                                                               insertion.insertionsAfter);
-            ASSERT(inserted);
-        }
-        if (!insertion.insertionsBefore.empty())
-        {
-            bool inserted =
-                insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
-            ASSERT(inserted);
-        }
-    }
-    for (size_t ii = 0; ii < mReplacements.size(); ++ii)
-    {
-        const NodeUpdateEntry &replacement = mReplacements[ii];
-        ASSERT(replacement.parent);
-        bool replaced =
-            replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
-        ASSERT(replaced);
-
-        if (!replacement.originalBecomesChildOfReplacement)
-        {
-            // In AST traversing, a parent is visited before its children.
-            // After we replace a node, if its immediate child is to
-            // be replaced, we need to make sure we don't update the replaced
-            // node; instead, we update the replacement node.
-            for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
-            {
-                NodeUpdateEntry &replacement2 = mReplacements[jj];
-                if (replacement2.parent == replacement.original)
-                    replacement2.parent = replacement.replacement;
-            }
-        }
-    }
-    for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
-    {
-        const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
-        ASSERT(replacement.parent);
-        bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
-                                                                         replacement.replacements);
-        ASSERT(replaced);
-    }
-
-    clearReplacementQueue();
-}
-
-void TIntermTraverser::clearReplacementQueue()
-{
-    mReplacements.clear();
-    mMultiReplacements.clear();
-    mInsertions.clear();
-}
-
-void TIntermTraverser::queueReplacement(TIntermNode *original,
-                                        TIntermNode *replacement,
-                                        OriginalNode originalStatus)
-{
-    queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
-}
-
-void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
-                                                  TIntermNode *original,
-                                                  TIntermNode *replacement,
-                                                  OriginalNode originalStatus)
-{
-    bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
-    mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
-}
-
-TName TIntermTraverser::GetInternalFunctionName(const char *name)
-{
-    TString nameStr(name);
-    TName nameObj(nameStr);
-    nameObj.setInternal(true);
-    return nameObj;
-}
-
-TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
-    const TType &returnType,
-    const char *name,
-    const TSymbolUniqueId &functionId)
-{
-    TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
-    functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
-    return functionNode;
-}
-
-TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
-    const TType &returnType,
-    const char *name,
-    TIntermBlock *functionBody,
-    const TSymbolUniqueId &functionId)
-{
-    TIntermFunctionPrototype *prototypeNode =
-        CreateInternalFunctionPrototypeNode(returnType, name, functionId);
-    return new TIntermFunctionDefinition(prototypeNode, functionBody);
-}
-
-TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
-    const TType &returnType,
-    const char *name,
-    const TSymbolUniqueId &functionId,
-    TIntermSequence *arguments)
-{
-    TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
-        returnType, functionId, GetInternalFunctionName(name), arguments);
-    return functionNode;
-}
-
 }  // namespace sh
diff --git a/src/compiler/translator/IntermNode.h b/src/compiler/translator/IntermNode.h
index 9770428..e48d683 100644
--- a/src/compiler/translator/IntermNode.h
+++ b/src/compiler/translator/IntermNode.h
@@ -910,391 +910,6 @@
     TIntermTyped *mCondition;
 };
 
-enum Visit
-{
-    PreVisit,
-    InVisit,
-    PostVisit
-};
-
-//
-// For traversing the tree.  User should derive from this class overriding the visit functions,
-// and then pass an object of the subclass to a traverse method of a node.
-//
-// The traverse*() functions may also be overridden do other bookkeeping on the tree to provide
-// contextual information to the visit functions, such as whether the node is the target of an
-// assignment.
-//
-// When using this, just fill in the methods for nodes you want visited.
-// Return false from a pre-visit to skip visiting that node's subtree.
-//
-class TIntermTraverser : angle::NonCopyable
-{
-  public:
-    POOL_ALLOCATOR_NEW_DELETE();
-    TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
-    virtual ~TIntermTraverser();
-
-    virtual void visitSymbol(TIntermSymbol *node) {}
-    virtual void visitRaw(TIntermRaw *node) {}
-    virtual void visitConstantUnion(TIntermConstantUnion *node) {}
-    virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
-    virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
-    virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
-    virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
-    virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
-    virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
-    virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
-    virtual bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
-    {
-        return true;
-    }
-    virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
-    {
-        return true;
-    }
-    virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
-    virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
-    virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
-    {
-        return true;
-    }
-    virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
-    virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
-    virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
-
-    // The traverse functions contain logic for iterating over the children of the node
-    // and calling the visit functions in the appropriate places. They also track some
-    // context that may be used by the visit functions.
-    virtual void traverseSymbol(TIntermSymbol *node);
-    virtual void traverseRaw(TIntermRaw *node);
-    virtual void traverseConstantUnion(TIntermConstantUnion *node);
-    virtual void traverseSwizzle(TIntermSwizzle *node);
-    virtual void traverseBinary(TIntermBinary *node);
-    virtual void traverseUnary(TIntermUnary *node);
-    virtual void traverseTernary(TIntermTernary *node);
-    virtual void traverseIfElse(TIntermIfElse *node);
-    virtual void traverseSwitch(TIntermSwitch *node);
-    virtual void traverseCase(TIntermCase *node);
-    virtual void traverseFunctionPrototype(TIntermFunctionPrototype *node);
-    virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
-    virtual void traverseAggregate(TIntermAggregate *node);
-    virtual void traverseBlock(TIntermBlock *node);
-    virtual void traverseInvariantDeclaration(TIntermInvariantDeclaration *node);
-    virtual void traverseDeclaration(TIntermDeclaration *node);
-    virtual void traverseLoop(TIntermLoop *node);
-    virtual void traverseBranch(TIntermBranch *node);
-
-    int getMaxDepth() const { return mMaxDepth; }
-
-    // Return the original name if hash function pointer is NULL;
-    // otherwise return the hashed name.
-    static TString hash(const TString &name, ShHashFunction64 hashFunction);
-
-    // If traversers need to replace nodes, they can add the replacements in
-    // mReplacements/mMultiReplacements during traversal and the user of the traverser should call
-    // this function after traversal to perform them.
-    void updateTree();
-
-    // Start creating temporary symbols from the given temporary symbol index + 1.
-    void useTemporaryId(TSymbolUniqueId *temporaryId);
-
-    static TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(
-        const TType &returnType,
-        const char *name,
-        const TSymbolUniqueId &functionId);
-    static TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(
-        const TType &returnType,
-        const char *name,
-        TIntermBlock *functionBody,
-        const TSymbolUniqueId &functionId);
-    static TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType,
-                                                            const char *name,
-                                                            const TSymbolUniqueId &functionId,
-                                                            TIntermSequence *arguments);
-
-  protected:
-    // Should only be called from traverse*() functions
-    void incrementDepth(TIntermNode *current)
-    {
-        mDepth++;
-        mMaxDepth = std::max(mMaxDepth, mDepth);
-        mPath.push_back(current);
-    }
-
-    // Should only be called from traverse*() functions
-    void decrementDepth()
-    {
-        mDepth--;
-        mPath.pop_back();
-    }
-
-    // RAII helper for incrementDepth/decrementDepth
-    class ScopedNodeInTraversalPath
-    {
-      public:
-        ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current)
-            : mTraverser(traverser)
-        {
-            mTraverser->incrementDepth(current);
-        }
-        ~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); }
-      private:
-        TIntermTraverser *mTraverser;
-    };
-
-    TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; }
-
-    // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
-    TIntermNode *getAncestorNode(unsigned int n)
-    {
-        if (mPath.size() > n + 1u)
-        {
-            return mPath[mPath.size() - n - 2u];
-        }
-        return nullptr;
-    }
-
-    void pushParentBlock(TIntermBlock *node);
-    void incrementParentBlockPos();
-    void popParentBlock();
-
-    // To replace a single node with multiple nodes on the parent aggregate node
-    struct NodeReplaceWithMultipleEntry
-    {
-        NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
-                                     TIntermNode *_original,
-                                     TIntermSequence _replacements)
-            : parent(_parent), original(_original), replacements(_replacements)
-        {
-        }
-
-        TIntermAggregateBase *parent;
-        TIntermNode *original;
-        TIntermSequence replacements;
-    };
-
-    // To insert multiple nodes on the parent aggregate node
-    struct NodeInsertMultipleEntry
-    {
-        NodeInsertMultipleEntry(TIntermBlock *_parent,
-                                TIntermSequence::size_type _position,
-                                TIntermSequence _insertionsBefore,
-                                TIntermSequence _insertionsAfter)
-            : parent(_parent),
-              position(_position),
-              insertionsBefore(_insertionsBefore),
-              insertionsAfter(_insertionsAfter)
-        {
-        }
-
-        TIntermBlock *parent;
-        TIntermSequence::size_type position;
-        TIntermSequence insertionsBefore;
-        TIntermSequence insertionsAfter;
-    };
-
-    // Helper to insert statements in the parent block (sequence) of the node currently being
-    // traversed.
-    // The statements will be inserted before the node being traversed once updateTree is called.
-    // Should only be called during PreVisit or PostVisit from sequence nodes.
-    // Note that two insertions to the same position in the same block are not supported.
-    void insertStatementsInParentBlock(const TIntermSequence &insertions);
-
-    // Same as above, but supports simultaneous insertion of statements before and after the node
-    // currently being traversed.
-    void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
-                                       const TIntermSequence &insertionsAfter);
-
-    // Helper to insert a single statement.
-    void insertStatementInParentBlock(TIntermNode *statement);
-
-    // Helper to create a temporary symbol node with the given qualifier.
-    TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
-    // Helper to create a temporary symbol node.
-    TIntermSymbol *createTempSymbol(const TType &type);
-    // Create a node that declares but doesn't initialize a temporary symbol.
-    TIntermDeclaration *createTempDeclaration(const TType &type);
-    // Create a node that initializes the current temporary symbol with initializer having the given
-    // qualifier.
-    TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
-    // Create a node that initializes the current temporary symbol with initializer.
-    TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer);
-    // Create a node that assigns rightNode to the current temporary symbol.
-    TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
-    // Increment temporary symbol index.
-    void nextTemporaryId();
-
-    enum class OriginalNode
-    {
-        BECOMES_CHILD,
-        IS_DROPPED
-    };
-
-    void clearReplacementQueue();
-    void queueReplacement(TIntermNode *original,
-                          TIntermNode *replacement,
-                          OriginalNode originalStatus);
-    void queueReplacementWithParent(TIntermNode *parent,
-                                    TIntermNode *original,
-                                    TIntermNode *replacement,
-                                    OriginalNode originalStatus);
-
-    const bool preVisit;
-    const bool inVisit;
-    const bool postVisit;
-
-    int mDepth;
-    int mMaxDepth;
-
-    bool mInGlobalScope;
-
-    // During traversing, save all the changes that need to happen into
-    // mReplacements/mMultiReplacements, then do them by calling updateTree().
-    // Multi replacements are processed after single replacements.
-    std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
-    std::vector<NodeInsertMultipleEntry> mInsertions;
-
-  private:
-    static TName GetInternalFunctionName(const char *name);
-
-    static bool CompareInsertion(const NodeInsertMultipleEntry &a,
-                                 const NodeInsertMultipleEntry &b);
-
-    // To replace a single node with another on the parent node
-    struct NodeUpdateEntry
-    {
-        NodeUpdateEntry(TIntermNode *_parent,
-                        TIntermNode *_original,
-                        TIntermNode *_replacement,
-                        bool _originalBecomesChildOfReplacement)
-            : parent(_parent),
-              original(_original),
-              replacement(_replacement),
-              originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
-        {
-        }
-
-        TIntermNode *parent;
-        TIntermNode *original;
-        TIntermNode *replacement;
-        bool originalBecomesChildOfReplacement;
-    };
-
-    struct ParentBlock
-    {
-        ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
-            : node(nodeIn), pos(posIn)
-        {
-        }
-
-        TIntermBlock *node;
-        TIntermSequence::size_type pos;
-    };
-
-    std::vector<NodeUpdateEntry> mReplacements;
-
-    // All the nodes from root to the current node during traversing.
-    TVector<TIntermNode *> mPath;
-
-    // All the code blocks from the root to the current node's parent during traversal.
-    std::vector<ParentBlock> mParentBlockStack;
-
-    TSymbolUniqueId *mTemporaryId;
-};
-
-// Traverser parent class that tracks where a node is a destination of a write operation and so is
-// required to be an l-value.
-class TLValueTrackingTraverser : public TIntermTraverser
-{
-  public:
-    TLValueTrackingTraverser(bool preVisit,
-                             bool inVisit,
-                             bool postVisit,
-                             const TSymbolTable &symbolTable,
-                             int shaderVersion)
-        : TIntermTraverser(preVisit, inVisit, postVisit),
-          mOperatorRequiresLValue(false),
-          mInFunctionCallOutParameter(false),
-          mSymbolTable(symbolTable),
-          mShaderVersion(shaderVersion)
-    {
-    }
-    virtual ~TLValueTrackingTraverser() {}
-
-    void traverseBinary(TIntermBinary *node) final;
-    void traverseUnary(TIntermUnary *node) final;
-    void traverseFunctionPrototype(TIntermFunctionPrototype *node) final;
-    void traverseAggregate(TIntermAggregate *node) final;
-
-  protected:
-    bool isLValueRequiredHere() const
-    {
-        return mOperatorRequiresLValue || mInFunctionCallOutParameter;
-    }
-
-  private:
-    // Track whether an l-value is required in the node that is currently being traversed by the
-    // surrounding operator.
-    // Use isLValueRequiredHere to check all conditions which require an l-value.
-    void setOperatorRequiresLValue(bool lValueRequired)
-    {
-        mOperatorRequiresLValue = lValueRequired;
-    }
-    bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
-
-    // Add a function encountered during traversal to the function map.
-    void addToFunctionMap(const TSymbolUniqueId &id, TIntermSequence *paramSequence);
-
-    // Return true if the prototype or definition of the function being called has been encountered
-    // during traversal.
-    bool isInFunctionMap(const TIntermAggregate *callNode) const;
-
-    // Return the parameters sequence from the function definition or prototype.
-    TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
-
-    // Track whether an l-value is required inside a function call.
-    void setInFunctionCallOutParameter(bool inOutParameter);
-    bool isInFunctionCallOutParameter() const;
-
-    bool mOperatorRequiresLValue;
-    bool mInFunctionCallOutParameter;
-
-    // Map from function symbol id values to their parameter sequences
-    TMap<int, TIntermSequence *> mFunctionMap;
-
-    const TSymbolTable &mSymbolTable;
-    const int mShaderVersion;
-};
-
-//
-// For traversing the tree, and computing max depth.
-// Takes a maximum depth limit to prevent stack overflow.
-//
-class TMaxDepthTraverser : public TIntermTraverser
-{
-  public:
-    POOL_ALLOCATOR_NEW_DELETE();
-    TMaxDepthTraverser(int depthLimit)
-        : TIntermTraverser(true, true, false), mDepthLimit(depthLimit)
-    {
-    }
-
-    bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
-    bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
-    bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
-    bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
-    bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
-    bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
-    bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
-    bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
-
-  protected:
-    bool depthCheck() const { return mMaxDepth < mDepthLimit; }
-
-    int mDepthLimit;
-};
-
 }  // namespace sh
 
 #endif  // COMPILER_TRANSLATOR_INTERMNODE_H_
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index 2b0e4b2..37fb6f1 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -4,7 +4,8 @@
 // found in the LICENSE file.
 //
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
+
 #include "compiler/translator/InfoSink.h"
 #include "compiler/translator/SymbolTable.h"
 
@@ -621,6 +622,152 @@
         visitAggregate(PostVisit, node);
 }
 
+bool TIntermTraverser::CompareInsertion(const NodeInsertMultipleEntry &a,
+                                        const NodeInsertMultipleEntry &b)
+{
+    if (a.parent != b.parent)
+    {
+        return a.parent > b.parent;
+    }
+    return a.position > b.position;
+}
+
+void TIntermTraverser::updateTree()
+{
+    // Sort the insertions so that insertion position is decreasing. This way multiple insertions to
+    // the same parent node are handled correctly.
+    std::sort(mInsertions.begin(), mInsertions.end(), CompareInsertion);
+    for (size_t ii = 0; ii < mInsertions.size(); ++ii)
+    {
+        // We can't know here what the intended ordering of two insertions to the same position is,
+        // so it is not supported.
+        ASSERT(ii == 0 || mInsertions[ii].position != mInsertions[ii - 1].position ||
+               mInsertions[ii].parent != mInsertions[ii - 1].parent);
+        const NodeInsertMultipleEntry &insertion = mInsertions[ii];
+        ASSERT(insertion.parent);
+        if (!insertion.insertionsAfter.empty())
+        {
+            bool inserted = insertion.parent->insertChildNodes(insertion.position + 1,
+                                                               insertion.insertionsAfter);
+            ASSERT(inserted);
+        }
+        if (!insertion.insertionsBefore.empty())
+        {
+            bool inserted =
+                insertion.parent->insertChildNodes(insertion.position, insertion.insertionsBefore);
+            ASSERT(inserted);
+        }
+    }
+    for (size_t ii = 0; ii < mReplacements.size(); ++ii)
+    {
+        const NodeUpdateEntry &replacement = mReplacements[ii];
+        ASSERT(replacement.parent);
+        bool replaced =
+            replacement.parent->replaceChildNode(replacement.original, replacement.replacement);
+        ASSERT(replaced);
+
+        if (!replacement.originalBecomesChildOfReplacement)
+        {
+            // In AST traversing, a parent is visited before its children.
+            // After we replace a node, if its immediate child is to
+            // be replaced, we need to make sure we don't update the replaced
+            // node; instead, we update the replacement node.
+            for (size_t jj = ii + 1; jj < mReplacements.size(); ++jj)
+            {
+                NodeUpdateEntry &replacement2 = mReplacements[jj];
+                if (replacement2.parent == replacement.original)
+                    replacement2.parent = replacement.replacement;
+            }
+        }
+    }
+    for (size_t ii = 0; ii < mMultiReplacements.size(); ++ii)
+    {
+        const NodeReplaceWithMultipleEntry &replacement = mMultiReplacements[ii];
+        ASSERT(replacement.parent);
+        bool replaced = replacement.parent->replaceChildNodeWithMultiple(replacement.original,
+                                                                         replacement.replacements);
+        ASSERT(replaced);
+    }
+
+    clearReplacementQueue();
+}
+
+void TIntermTraverser::clearReplacementQueue()
+{
+    mReplacements.clear();
+    mMultiReplacements.clear();
+    mInsertions.clear();
+}
+
+void TIntermTraverser::queueReplacement(TIntermNode *original,
+                                        TIntermNode *replacement,
+                                        OriginalNode originalStatus)
+{
+    queueReplacementWithParent(getParentNode(), original, replacement, originalStatus);
+}
+
+void TIntermTraverser::queueReplacementWithParent(TIntermNode *parent,
+                                                  TIntermNode *original,
+                                                  TIntermNode *replacement,
+                                                  OriginalNode originalStatus)
+{
+    bool originalBecomesChild = (originalStatus == OriginalNode::BECOMES_CHILD);
+    mReplacements.push_back(NodeUpdateEntry(parent, original, replacement, originalBecomesChild));
+}
+
+TName TIntermTraverser::GetInternalFunctionName(const char *name)
+{
+    TString nameStr(name);
+    TName nameObj(nameStr);
+    nameObj.setInternal(true);
+    return nameObj;
+}
+
+TIntermFunctionPrototype *TIntermTraverser::CreateInternalFunctionPrototypeNode(
+    const TType &returnType,
+    const char *name,
+    const TSymbolUniqueId &functionId)
+{
+    TIntermFunctionPrototype *functionNode = new TIntermFunctionPrototype(returnType, functionId);
+    functionNode->getFunctionSymbolInfo()->setNameObj(GetInternalFunctionName(name));
+    return functionNode;
+}
+
+TIntermFunctionDefinition *TIntermTraverser::CreateInternalFunctionDefinitionNode(
+    const TType &returnType,
+    const char *name,
+    TIntermBlock *functionBody,
+    const TSymbolUniqueId &functionId)
+{
+    TIntermFunctionPrototype *prototypeNode =
+        CreateInternalFunctionPrototypeNode(returnType, name, functionId);
+    return new TIntermFunctionDefinition(prototypeNode, functionBody);
+}
+
+TIntermAggregate *TIntermTraverser::CreateInternalFunctionCallNode(
+    const TType &returnType,
+    const char *name,
+    const TSymbolUniqueId &functionId,
+    TIntermSequence *arguments)
+{
+    TIntermAggregate *functionNode = TIntermAggregate::CreateFunctionCall(
+        returnType, functionId, GetInternalFunctionName(name), arguments);
+    return functionNode;
+}
+
+TLValueTrackingTraverser::TLValueTrackingTraverser(bool preVisit,
+                                                   bool inVisit,
+                                                   bool postVisit,
+                                                   const TSymbolTable &symbolTable,
+                                                   int shaderVersion)
+    : TIntermTraverser(preVisit, inVisit, postVisit),
+      mOperatorRequiresLValue(false),
+      mInFunctionCallOutParameter(false),
+      mSymbolTable(symbolTable),
+      mShaderVersion(shaderVersion)
+{
+}
+
 void TLValueTrackingTraverser::traverseFunctionPrototype(TIntermFunctionPrototype *node)
 {
     TIntermSequence *sequence = node->getSequence();
diff --git a/src/compiler/translator/IntermTraverse.h b/src/compiler/translator/IntermTraverse.h
new file mode 100644
index 0000000..0dda15e
--- /dev/null
+++ b/src/compiler/translator/IntermTraverse.h
@@ -0,0 +1,369 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IntermTraverse.h : base classes for AST traversers that walk the AST and
+//   also have the ability to transform it by replacing nodes.
+
+#ifndef COMPILER_TRANSLATOR_INTERMTRAVERSE_H_
+#define COMPILER_TRANSLATOR_INTERMTRAVERSE_H_
+
+#include "compiler/translator/IntermNode.h"
+
+namespace sh
+{
+
+class TSymbolTable;
+class TSymbolUniqueId;
+
+enum Visit
+{
+    PreVisit,
+    InVisit,
+    PostVisit
+};
+
+//
+// For traversing the tree.  User should derive from this class overriding the visit functions,
+// and then pass an object of the subclass to a traverse method of a node.
+//
+// The traverse*() functions may also be overridden do other bookkeeping on the tree to provide
+// contextual information to the visit functions, such as whether the node is the target of an
+// assignment.
+//
+// When using this, just fill in the methods for nodes you want visited.
+// Return false from a pre-visit to skip visiting that node's subtree.
+//
+class TIntermTraverser : angle::NonCopyable
+{
+  public:
+    POOL_ALLOCATOR_NEW_DELETE();
+    TIntermTraverser(bool preVisit, bool inVisit, bool postVisit);
+    virtual ~TIntermTraverser();
+
+    virtual void visitSymbol(TIntermSymbol *node) {}
+    virtual void visitRaw(TIntermRaw *node) {}
+    virtual void visitConstantUnion(TIntermConstantUnion *node) {}
+    virtual bool visitSwizzle(Visit visit, TIntermSwizzle *node) { return true; }
+    virtual bool visitBinary(Visit visit, TIntermBinary *node) { return true; }
+    virtual bool visitUnary(Visit visit, TIntermUnary *node) { return true; }
+    virtual bool visitTernary(Visit visit, TIntermTernary *node) { return true; }
+    virtual bool visitIfElse(Visit visit, TIntermIfElse *node) { return true; }
+    virtual bool visitSwitch(Visit visit, TIntermSwitch *node) { return true; }
+    virtual bool visitCase(Visit visit, TIntermCase *node) { return true; }
+    virtual bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+    {
+        return true;
+    }
+    virtual bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+    {
+        return true;
+    }
+    virtual bool visitAggregate(Visit visit, TIntermAggregate *node) { return true; }
+    virtual bool visitBlock(Visit visit, TIntermBlock *node) { return true; }
+    virtual bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+    {
+        return true;
+    }
+    virtual bool visitDeclaration(Visit visit, TIntermDeclaration *node) { return true; }
+    virtual bool visitLoop(Visit visit, TIntermLoop *node) { return true; }
+    virtual bool visitBranch(Visit visit, TIntermBranch *node) { return true; }
+
+    // The traverse functions contain logic for iterating over the children of the node
+    // and calling the visit functions in the appropriate places. They also track some
+    // context that may be used by the visit functions.
+    virtual void traverseSymbol(TIntermSymbol *node);
+    virtual void traverseRaw(TIntermRaw *node);
+    virtual void traverseConstantUnion(TIntermConstantUnion *node);
+    virtual void traverseSwizzle(TIntermSwizzle *node);
+    virtual void traverseBinary(TIntermBinary *node);
+    virtual void traverseUnary(TIntermUnary *node);
+    virtual void traverseTernary(TIntermTernary *node);
+    virtual void traverseIfElse(TIntermIfElse *node);
+    virtual void traverseSwitch(TIntermSwitch *node);
+    virtual void traverseCase(TIntermCase *node);
+    virtual void traverseFunctionPrototype(TIntermFunctionPrototype *node);
+    virtual void traverseFunctionDefinition(TIntermFunctionDefinition *node);
+    virtual void traverseAggregate(TIntermAggregate *node);
+    virtual void traverseBlock(TIntermBlock *node);
+    virtual void traverseInvariantDeclaration(TIntermInvariantDeclaration *node);
+    virtual void traverseDeclaration(TIntermDeclaration *node);
+    virtual void traverseLoop(TIntermLoop *node);
+    virtual void traverseBranch(TIntermBranch *node);
+
+    int getMaxDepth() const { return mMaxDepth; }
+
+    // If traversers need to replace nodes, they can add the replacements in
+    // mReplacements/mMultiReplacements during traversal and the user of the traverser should call
+    // this function after traversal to perform them.
+    void updateTree();
+
+    // Start creating temporary symbols from the given temporary symbol index + 1.
+    void useTemporaryId(TSymbolUniqueId *temporaryId);
+
+    static TIntermFunctionPrototype *CreateInternalFunctionPrototypeNode(
+        const TType &returnType,
+        const char *name,
+        const TSymbolUniqueId &functionId);
+    static TIntermFunctionDefinition *CreateInternalFunctionDefinitionNode(
+        const TType &returnType,
+        const char *name,
+        TIntermBlock *functionBody,
+        const TSymbolUniqueId &functionId);
+    static TIntermAggregate *CreateInternalFunctionCallNode(const TType &returnType,
+                                                            const char *name,
+                                                            const TSymbolUniqueId &functionId,
+                                                            TIntermSequence *arguments);
+
+  protected:
+    // Should only be called from traverse*() functions
+    void incrementDepth(TIntermNode *current)
+    {
+        mDepth++;
+        mMaxDepth = std::max(mMaxDepth, mDepth);
+        mPath.push_back(current);
+    }
+
+    // Should only be called from traverse*() functions
+    void decrementDepth()
+    {
+        mDepth--;
+        mPath.pop_back();
+    }
+
+    // RAII helper for incrementDepth/decrementDepth
+    class ScopedNodeInTraversalPath
+    {
+      public:
+        ScopedNodeInTraversalPath(TIntermTraverser *traverser, TIntermNode *current)
+            : mTraverser(traverser)
+        {
+            mTraverser->incrementDepth(current);
+        }
+        ~ScopedNodeInTraversalPath() { mTraverser->decrementDepth(); }
+
+      private:
+        TIntermTraverser *mTraverser;
+    };
+
+    TIntermNode *getParentNode() { return mPath.size() <= 1 ? nullptr : mPath[mPath.size() - 2u]; }
+
+    // Return the nth ancestor of the node being traversed. getAncestorNode(0) == getParentNode()
+    TIntermNode *getAncestorNode(unsigned int n)
+    {
+        if (mPath.size() > n + 1u)
+        {
+            return mPath[mPath.size() - n - 2u];
+        }
+        return nullptr;
+    }
+
+    void pushParentBlock(TIntermBlock *node);
+    void incrementParentBlockPos();
+    void popParentBlock();
+
+    // To replace a single node with multiple nodes on the parent aggregate node
+    struct NodeReplaceWithMultipleEntry
+    {
+        NodeReplaceWithMultipleEntry(TIntermAggregateBase *_parent,
+                                     TIntermNode *_original,
+                                     TIntermSequence _replacements)
+            : parent(_parent), original(_original), replacements(_replacements)
+        {
+        }
+
+        TIntermAggregateBase *parent;
+        TIntermNode *original;
+        TIntermSequence replacements;
+    };
+
+    // To insert multiple nodes on the parent aggregate node
+    struct NodeInsertMultipleEntry
+    {
+        NodeInsertMultipleEntry(TIntermBlock *_parent,
+                                TIntermSequence::size_type _position,
+                                TIntermSequence _insertionsBefore,
+                                TIntermSequence _insertionsAfter)
+            : parent(_parent),
+              position(_position),
+              insertionsBefore(_insertionsBefore),
+              insertionsAfter(_insertionsAfter)
+        {
+        }
+
+        TIntermBlock *parent;
+        TIntermSequence::size_type position;
+        TIntermSequence insertionsBefore;
+        TIntermSequence insertionsAfter;
+    };
+
+    // Helper to insert statements in the parent block (sequence) of the node currently being
+    // traversed.
+    // The statements will be inserted before the node being traversed once updateTree is called.
+    // Should only be called during PreVisit or PostVisit from sequence nodes.
+    // Note that two insertions to the same position in the same block are not supported.
+    void insertStatementsInParentBlock(const TIntermSequence &insertions);
+
+    // Same as above, but supports simultaneous insertion of statements before and after the node
+    // currently being traversed.
+    void insertStatementsInParentBlock(const TIntermSequence &insertionsBefore,
+                                       const TIntermSequence &insertionsAfter);
+
+    // Helper to insert a single statement.
+    void insertStatementInParentBlock(TIntermNode *statement);
+
+    // Helper to create a temporary symbol node with the given qualifier.
+    TIntermSymbol *createTempSymbol(const TType &type, TQualifier qualifier);
+    // Helper to create a temporary symbol node.
+    TIntermSymbol *createTempSymbol(const TType &type);
+    // Create a node that declares but doesn't initialize a temporary symbol.
+    TIntermDeclaration *createTempDeclaration(const TType &type);
+    // Create a node that initializes the current temporary symbol with initializer having the given
+    // qualifier.
+    TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer, TQualifier qualifier);
+    // Create a node that initializes the current temporary symbol with initializer.
+    TIntermDeclaration *createTempInitDeclaration(TIntermTyped *initializer);
+    // Create a node that assigns rightNode to the current temporary symbol.
+    TIntermBinary *createTempAssignment(TIntermTyped *rightNode);
+    // Increment temporary symbol index.
+    void nextTemporaryId();
+
+    enum class OriginalNode
+    {
+        BECOMES_CHILD,
+        IS_DROPPED
+    };
+
+    void clearReplacementQueue();
+    void queueReplacement(TIntermNode *original,
+                          TIntermNode *replacement,
+                          OriginalNode originalStatus);
+    void queueReplacementWithParent(TIntermNode *parent,
+                                    TIntermNode *original,
+                                    TIntermNode *replacement,
+                                    OriginalNode originalStatus);
+
+    const bool preVisit;
+    const bool inVisit;
+    const bool postVisit;
+
+    int mDepth;
+    int mMaxDepth;
+
+    bool mInGlobalScope;
+
+    // During traversing, save all the changes that need to happen into
+    // mReplacements/mMultiReplacements, then do them by calling updateTree().
+    // Multi replacements are processed after single replacements.
+    std::vector<NodeReplaceWithMultipleEntry> mMultiReplacements;
+    std::vector<NodeInsertMultipleEntry> mInsertions;
+
+  private:
+    static TName GetInternalFunctionName(const char *name);
+
+    static bool CompareInsertion(const NodeInsertMultipleEntry &a,
+                                 const NodeInsertMultipleEntry &b);
+
+    // To replace a single node with another on the parent node
+    struct NodeUpdateEntry
+    {
+        NodeUpdateEntry(TIntermNode *_parent,
+                        TIntermNode *_original,
+                        TIntermNode *_replacement,
+                        bool _originalBecomesChildOfReplacement)
+            : parent(_parent),
+              original(_original),
+              replacement(_replacement),
+              originalBecomesChildOfReplacement(_originalBecomesChildOfReplacement)
+        {
+        }
+
+        TIntermNode *parent;
+        TIntermNode *original;
+        TIntermNode *replacement;
+        bool originalBecomesChildOfReplacement;
+    };
+
+    struct ParentBlock
+    {
+        ParentBlock(TIntermBlock *nodeIn, TIntermSequence::size_type posIn)
+            : node(nodeIn), pos(posIn)
+        {
+        }
+
+        TIntermBlock *node;
+        TIntermSequence::size_type pos;
+    };
+
+    std::vector<NodeUpdateEntry> mReplacements;
+
+    // All the nodes from root to the current node during traversing.
+    TVector<TIntermNode *> mPath;
+
+    // All the code blocks from the root to the current node's parent during traversal.
+    std::vector<ParentBlock> mParentBlockStack;
+
+    TSymbolUniqueId *mTemporaryId;
+};
+
+// Traverser parent class that tracks where a node is a destination of a write operation and so is
+// required to be an l-value.
+class TLValueTrackingTraverser : public TIntermTraverser
+{
+  public:
+    TLValueTrackingTraverser(bool preVisit,
+                             bool inVisit,
+                             bool postVisit,
+                             const TSymbolTable &symbolTable,
+                             int shaderVersion);
+    virtual ~TLValueTrackingTraverser() {}
+
+    void traverseBinary(TIntermBinary *node) final;
+    void traverseUnary(TIntermUnary *node) final;
+    void traverseFunctionPrototype(TIntermFunctionPrototype *node) final;
+    void traverseAggregate(TIntermAggregate *node) final;
+
+  protected:
+    bool isLValueRequiredHere() const
+    {
+        return mOperatorRequiresLValue || mInFunctionCallOutParameter;
+    }
+
+  private:
+    // Track whether an l-value is required in the node that is currently being traversed by the
+    // surrounding operator.
+    // Use isLValueRequiredHere to check all conditions which require an l-value.
+    void setOperatorRequiresLValue(bool lValueRequired)
+    {
+        mOperatorRequiresLValue = lValueRequired;
+    }
+    bool operatorRequiresLValue() const { return mOperatorRequiresLValue; }
+
+    // Add a function encountered during traversal to the function map.
+    void addToFunctionMap(const TSymbolUniqueId &id, TIntermSequence *paramSequence);
+
+    // Return true if the prototype or definition of the function being called has been encountered
+    // during traversal.
+    bool isInFunctionMap(const TIntermAggregate *callNode) const;
+
+    // Return the parameters sequence from the function definition or prototype.
+    TIntermSequence *getFunctionParameters(const TIntermAggregate *callNode);
+
+    // Track whether an l-value is required inside a function call.
+    void setInFunctionCallOutParameter(bool inOutParameter);
+    bool isInFunctionCallOutParameter() const;
+
+    bool mOperatorRequiresLValue;
+    bool mInFunctionCallOutParameter;
+
+    // Map from function symbol id values to their parameter sequences
+    TMap<int, TIntermSequence *> mFunctionMap;
+
+    const TSymbolTable &mSymbolTable;
+    const int mShaderVersion;
+};
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_INTERMTRAVERSE_H_
diff --git a/src/compiler/translator/Intermediate.h b/src/compiler/translator/Intermediate.h
index 0496100..d2c4390 100644
--- a/src/compiler/translator/Intermediate.h
+++ b/src/compiler/translator/Intermediate.h
@@ -54,8 +54,6 @@
                                     const TVectorFields &fields,
                                     const TSourceLoc &dotLocation);
 
-    static void outputTree(TIntermNode *, TInfoSinkBase &);
-
     TIntermTyped *foldAggregateBuiltIn(TIntermAggregate *aggregate, TDiagnostics *diagnostics);
 
   private:
diff --git a/src/compiler/translator/IsASTDepthBelowLimit.cpp b/src/compiler/translator/IsASTDepthBelowLimit.cpp
new file mode 100644
index 0000000..aaad4f3
--- /dev/null
+++ b/src/compiler/translator/IsASTDepthBelowLimit.cpp
@@ -0,0 +1,51 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/IsASTDepthBelowLimit.h"
+
+#include "compiler/translator/IntermTraverse.h"
+
+namespace sh
+{
+
+namespace
+{
+
+// Traverse the tree and compute max depth. Takes a maximum depth limit to prevent stack overflow.
+class MaxDepthTraverser : public TIntermTraverser
+{
+  public:
+    MaxDepthTraverser(int depthLimit) : TIntermTraverser(true, true, false), mDepthLimit(depthLimit)
+    {
+    }
+
+    bool visitBinary(Visit, TIntermBinary *) override { return depthCheck(); }
+    bool visitUnary(Visit, TIntermUnary *) override { return depthCheck(); }
+    bool visitTernary(Visit, TIntermTernary *) override { return depthCheck(); }
+    bool visitSwizzle(Visit, TIntermSwizzle *) override { return depthCheck(); }
+    bool visitIfElse(Visit, TIntermIfElse *) override { return depthCheck(); }
+    bool visitAggregate(Visit, TIntermAggregate *) override { return depthCheck(); }
+    bool visitBlock(Visit, TIntermBlock *) override { return depthCheck(); }
+    bool visitLoop(Visit, TIntermLoop *) override { return depthCheck(); }
+    bool visitBranch(Visit, TIntermBranch *) override { return depthCheck(); }
+
+  protected:
+    bool depthCheck() const { return mMaxDepth < mDepthLimit; }
+
+    int mDepthLimit;
+};
+
+}  // anonymous namespace
+
+bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth)
+{
+    MaxDepthTraverser traverser(maxDepth + 1);
+    root->traverse(&traverser);
+
+    return traverser.getMaxDepth() <= maxDepth;
+}
+
+}  // namespace sh
diff --git a/src/compiler/translator/IsASTDepthBelowLimit.h b/src/compiler/translator/IsASTDepthBelowLimit.h
new file mode 100644
index 0000000..ef2f02c
--- /dev/null
+++ b/src/compiler/translator/IsASTDepthBelowLimit.h
@@ -0,0 +1,20 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// IsASTDepthBelowLimit: Check whether AST depth is below a specific limit.
+
+#ifndef COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
+#define COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
+
+namespace sh
+{
+
+class TIntermNode;
+
+bool IsASTDepthBelowLimit(TIntermNode *root, int maxDepth);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_ISASTDEPTHBELOWLIMIT_H_
diff --git a/src/compiler/translator/NodeSearch.h b/src/compiler/translator/NodeSearch.h
index 96b0b33..af86b8b 100644
--- a/src/compiler/translator/NodeSearch.h
+++ b/src/compiler/translator/NodeSearch.h
@@ -9,7 +9,7 @@
 #ifndef COMPILER_TRANSLATOR_NODESEARCH_H_
 #define COMPILER_TRANSLATOR_NODESEARCH_H_
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/OutputGLSL.cpp b/src/compiler/translator/OutputGLSL.cpp
index 5a7de93..ae9b6e8 100644
--- a/src/compiler/translator/OutputGLSL.cpp
+++ b/src/compiler/translator/OutputGLSL.cpp
@@ -6,6 +6,8 @@
 
 #include "compiler/translator/OutputGLSL.h"
 
+#include "compiler/translator/Compiler.h"
+
 namespace sh
 {
 
diff --git a/src/compiler/translator/OutputGLSLBase.cpp b/src/compiler/translator/OutputGLSLBase.cpp
index ed6b342..7d4a9ae 100644
--- a/src/compiler/translator/OutputGLSLBase.cpp
+++ b/src/compiler/translator/OutputGLSLBase.cpp
@@ -8,6 +8,7 @@
 
 #include "common/debug.h"
 #include "common/mathutil.h"
+#include "compiler/translator/Compiler.h"
 
 #include <cfloat>
 
@@ -1160,7 +1161,7 @@
     NameMap::const_iterator it = mNameMap.find(name.getString().c_str());
     if (it != mNameMap.end())
         return it->second.c_str();
-    TString hashedName                 = TIntermTraverser::hash(name.getString(), mHashFunction);
+    TString hashedName                 = HashName(name.getString(), mHashFunction);
     mNameMap[name.getString().c_str()] = hashedName.c_str();
     return hashedName;
 }
diff --git a/src/compiler/translator/OutputGLSLBase.h b/src/compiler/translator/OutputGLSLBase.h
index af3019c..bfbb14d 100644
--- a/src/compiler/translator/OutputGLSLBase.h
+++ b/src/compiler/translator/OutputGLSLBase.h
@@ -9,8 +9,9 @@
 
 #include <set>
 
-#include "compiler/translator/IntermNode.h"
-#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/InfoSink.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index b1ccbc5..987d128 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -13,8 +13,8 @@
 
 #include "angle_gl.h"
 #include "compiler/translator/ASTMetadataHLSL.h"
-#include "compiler/translator/IntermNode.h"
-#include "compiler/translator/ParseContext.h"
+#include "compiler/translator/Compiler.h"
+#include "compiler/translator/IntermTraverse.h"
 
 class BuiltInFunctionEmulator;
 
diff --git a/src/compiler/translator/OutputTree.cpp b/src/compiler/translator/OutputTree.cpp
new file mode 100644
index 0000000..f87a063
--- /dev/null
+++ b/src/compiler/translator/OutputTree.cpp
@@ -0,0 +1,678 @@
+//
+// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+#include "compiler/translator/IntermTraverse.h"
+#include "compiler/translator/SymbolTable.h"
+
+namespace sh
+{
+
+namespace
+{
+
+void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
+{
+    const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
+    out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
+        << info->getId().get() << ")";
+}
+
+// Two purposes:
+// 1.  Show an example of how to iterate tree.  Functions can also directly call traverse() on
+//     children themselves to have finer grained control over the process than shown here, though
+//     that's not recommended if it can be avoided.
+// 2.  Print out a text based description of the tree.
+
+// The traverser subclass is used to carry along data from node to node in the traversal.
+class TOutputTraverser : public TIntermTraverser
+{
+  public:
+    TOutputTraverser(TInfoSinkBase &out) : TIntermTraverser(true, false, false), mOut(out) {}
+
+  protected:
+    void visitSymbol(TIntermSymbol *) override;
+    void visitConstantUnion(TIntermConstantUnion *) override;
+    bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
+    bool visitBinary(Visit visit, TIntermBinary *) override;
+    bool visitUnary(Visit visit, TIntermUnary *) override;
+    bool visitTernary(Visit visit, TIntermTernary *node) override;
+    bool visitIfElse(Visit visit, TIntermIfElse *node) override;
+    bool visitSwitch(Visit visit, TIntermSwitch *node) override;
+    bool visitCase(Visit visit, TIntermCase *node) override;
+    bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
+    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
+    bool visitAggregate(Visit visit, TIntermAggregate *) override;
+    bool visitBlock(Visit visit, TIntermBlock *) override;
+    bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
+    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
+    bool visitLoop(Visit visit, TIntermLoop *) override;
+    bool visitBranch(Visit visit, TIntermBranch *) override;
+
+    TInfoSinkBase &mOut;
+};
+
+//
+// Helper functions for printing, not part of traversing.
+//
+void OutputTreeText(TInfoSinkBase &out, TIntermNode *node, const int depth)
+{
+    int i;
+
+    out.location(node->getLine().first_file, node->getLine().first_line);
+
+    for (i = 0; i < depth; ++i)
+        out << "  ";
+}
+
+//
+// The rest of the file are the traversal functions.  The last one
+// is the one that starts the traversal.
+//
+// Return true from interior nodes to have the external traversal
+// continue on to children.  If you process children yourself,
+// return false.
+//
+
+void TOutputTraverser::visitSymbol(TIntermSymbol *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    mOut << "'" << node->getSymbol() << "' ";
+    mOut << "(symbol id " << node->getId() << ") ";
+    mOut << "(" << node->getCompleteString() << ")";
+    mOut << "\n";
+}
+
+bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "vector swizzle (";
+    node->writeOffsetsAsXYZW(&mOut);
+    mOut << ")";
+
+    mOut << " (" << node->getCompleteString() << ")";
+    mOut << "\n";
+    return true;
+}
+
+bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    switch (node->getOp())
+    {
+        case EOpComma:
+            mOut << "comma";
+            break;
+        case EOpAssign:
+            mOut << "move second child to first child";
+            break;
+        case EOpInitialize:
+            mOut << "initialize first child with second child";
+            break;
+        case EOpAddAssign:
+            mOut << "add second child into first child";
+            break;
+        case EOpSubAssign:
+            mOut << "subtract second child into first child";
+            break;
+        case EOpMulAssign:
+            mOut << "multiply second child into first child";
+            break;
+        case EOpVectorTimesMatrixAssign:
+            mOut << "matrix mult second child into first child";
+            break;
+        case EOpVectorTimesScalarAssign:
+            mOut << "vector scale second child into first child";
+            break;
+        case EOpMatrixTimesScalarAssign:
+            mOut << "matrix scale second child into first child";
+            break;
+        case EOpMatrixTimesMatrixAssign:
+            mOut << "matrix mult second child into first child";
+            break;
+        case EOpDivAssign:
+            mOut << "divide second child into first child";
+            break;
+        case EOpIModAssign:
+            mOut << "modulo second child into first child";
+            break;
+        case EOpBitShiftLeftAssign:
+            mOut << "bit-wise shift first child left by second child";
+            break;
+        case EOpBitShiftRightAssign:
+            mOut << "bit-wise shift first child right by second child";
+            break;
+        case EOpBitwiseAndAssign:
+            mOut << "bit-wise and second child into first child";
+            break;
+        case EOpBitwiseXorAssign:
+            mOut << "bit-wise xor second child into first child";
+            break;
+        case EOpBitwiseOrAssign:
+            mOut << "bit-wise or second child into first child";
+            break;
+
+        case EOpIndexDirect:
+            mOut << "direct index";
+            break;
+        case EOpIndexIndirect:
+            mOut << "indirect index";
+            break;
+        case EOpIndexDirectStruct:
+            mOut << "direct index for structure";
+            break;
+        case EOpIndexDirectInterfaceBlock:
+            mOut << "direct index for interface block";
+            break;
+
+        case EOpAdd:
+            mOut << "add";
+            break;
+        case EOpSub:
+            mOut << "subtract";
+            break;
+        case EOpMul:
+            mOut << "component-wise multiply";
+            break;
+        case EOpDiv:
+            mOut << "divide";
+            break;
+        case EOpIMod:
+            mOut << "modulo";
+            break;
+        case EOpBitShiftLeft:
+            mOut << "bit-wise shift left";
+            break;
+        case EOpBitShiftRight:
+            mOut << "bit-wise shift right";
+            break;
+        case EOpBitwiseAnd:
+            mOut << "bit-wise and";
+            break;
+        case EOpBitwiseXor:
+            mOut << "bit-wise xor";
+            break;
+        case EOpBitwiseOr:
+            mOut << "bit-wise or";
+            break;
+
+        case EOpEqual:
+            mOut << "Compare Equal";
+            break;
+        case EOpNotEqual:
+            mOut << "Compare Not Equal";
+            break;
+        case EOpLessThan:
+            mOut << "Compare Less Than";
+            break;
+        case EOpGreaterThan:
+            mOut << "Compare Greater Than";
+            break;
+        case EOpLessThanEqual:
+            mOut << "Compare Less Than or Equal";
+            break;
+        case EOpGreaterThanEqual:
+            mOut << "Compare Greater Than or Equal";
+            break;
+
+        case EOpVectorTimesScalar:
+            mOut << "vector-scale";
+            break;
+        case EOpVectorTimesMatrix:
+            mOut << "vector-times-matrix";
+            break;
+        case EOpMatrixTimesVector:
+            mOut << "matrix-times-vector";
+            break;
+        case EOpMatrixTimesScalar:
+            mOut << "matrix-scale";
+            break;
+        case EOpMatrixTimesMatrix:
+            mOut << "matrix-multiply";
+            break;
+
+        case EOpLogicalOr:
+            mOut << "logical-or";
+            break;
+        case EOpLogicalXor:
+            mOut << "logical-xor";
+            break;
+        case EOpLogicalAnd:
+            mOut << "logical-and";
+            break;
+        default:
+            mOut << "<unknown op>";
+    }
+
+    mOut << " (" << node->getCompleteString() << ")";
+
+    mOut << "\n";
+
+    // Special handling for direct indexes. Because constant
+    // unions are not aware they are struct indexes, treat them
+    // here where we have that contextual knowledge.
+    if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
+    {
+        node->getLeft()->traverse(this);
+
+        TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
+        ASSERT(intermConstantUnion);
+
+        OutputTreeText(mOut, intermConstantUnion, mDepth + 1);
+
+        // The following code finds the field name from the constant union
+        const TConstantUnion *constantUnion   = intermConstantUnion->getUnionArrayPointer();
+        const TStructure *structure           = node->getLeft()->getType().getStruct();
+        const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
+        ASSERT(structure || interfaceBlock);
+
+        const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
+
+        const TField *field = fields[constantUnion->getIConst()];
+
+        mOut << constantUnion->getIConst() << " (field '" << field->name() << "')";
+
+        mOut << "\n";
+
+        return false;
+    }
+
+    return true;
+}
+
+bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    switch (node->getOp())
+    {
+        // Give verbose names for ops that have special syntax and some built-in functions that are
+        // easy to confuse with others, but mostly use GLSL names for functions.
+        case EOpNegative:
+            mOut << "Negate value";
+            break;
+        case EOpPositive:
+            mOut << "Positive sign";
+            break;
+        case EOpLogicalNot:
+            mOut << "negation";
+            break;
+        case EOpBitwiseNot:
+            mOut << "bit-wise not";
+            break;
+
+        case EOpPostIncrement:
+            mOut << "Post-Increment";
+            break;
+        case EOpPostDecrement:
+            mOut << "Post-Decrement";
+            break;
+        case EOpPreIncrement:
+            mOut << "Pre-Increment";
+            break;
+        case EOpPreDecrement:
+            mOut << "Pre-Decrement";
+            break;
+
+        case EOpLogicalNotComponentWise:
+            mOut << "component-wise not";
+            break;
+
+        default:
+            mOut << GetOperatorString(node->getOp());
+            break;
+    }
+
+    mOut << " (" << node->getCompleteString() << ")";
+
+    mOut << "\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "Function Definition:\n";
+    mOut << "\n";
+    return true;
+}
+
+bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "Invariant Declaration:\n";
+    return true;
+}
+
+bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+    OutputFunction(mOut, "Function Prototype", node->getFunctionSymbolInfo());
+    mOut << " (" << node->getCompleteString() << ")";
+    mOut << "\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    if (node->getOp() == EOpNull)
+    {
+        mOut.prefix(SH_ERROR);
+        mOut << "node is still EOpNull!\n";
+        return true;
+    }
+
+    // Give verbose names for some built-in functions that are easy to confuse with others, but
+    // mostly use GLSL names for functions.
+    switch (node->getOp())
+    {
+        case EOpCallFunctionInAST:
+            OutputFunction(mOut, "Call an user-defined function", node->getFunctionSymbolInfo());
+            break;
+        case EOpCallInternalRawFunction:
+            OutputFunction(mOut, "Call an internal function with raw implementation",
+                           node->getFunctionSymbolInfo());
+            break;
+        case EOpCallBuiltInFunction:
+            OutputFunction(mOut, "Call a built-in function", node->getFunctionSymbolInfo());
+            break;
+
+        case EOpConstruct:
+            // The type of the constructor will be printed below.
+            mOut << "Construct";
+            break;
+
+        case EOpEqualComponentWise:
+            mOut << "component-wise equal";
+            break;
+        case EOpNotEqualComponentWise:
+            mOut << "component-wise not equal";
+            break;
+        case EOpLessThanComponentWise:
+            mOut << "component-wise less than";
+            break;
+        case EOpGreaterThanComponentWise:
+            mOut << "component-wise greater than";
+            break;
+        case EOpLessThanEqualComponentWise:
+            mOut << "component-wise less than or equal";
+            break;
+        case EOpGreaterThanEqualComponentWise:
+            mOut << "component-wise greater than or equal";
+            break;
+
+        case EOpDot:
+            mOut << "dot product";
+            break;
+        case EOpCross:
+            mOut << "cross product";
+            break;
+        case EOpMulMatrixComponentWise:
+            mOut << "component-wise multiply";
+            break;
+
+        default:
+            mOut << GetOperatorString(node->getOp());
+            break;
+    }
+
+    mOut << " (" << node->getCompleteString() << ")";
+
+    mOut << "\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "Code block\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "Declaration\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    mOut << "Ternary selection";
+    mOut << " (" << node->getCompleteString() << ")\n";
+
+    ++mDepth;
+
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "Condition\n";
+    node->getCondition()->traverse(this);
+
+    OutputTreeText(mOut, node, mDepth);
+    if (node->getTrueExpression())
+    {
+        mOut << "true case\n";
+        node->getTrueExpression()->traverse(this);
+    }
+    if (node->getFalseExpression())
+    {
+        OutputTreeText(mOut, node, mDepth);
+        mOut << "false case\n";
+        node->getFalseExpression()->traverse(this);
+    }
+
+    --mDepth;
+
+    return false;
+}
+
+bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    mOut << "If test\n";
+
+    ++mDepth;
+
+    OutputTreeText(mOut, node, mDepth);
+    mOut << "Condition\n";
+    node->getCondition()->traverse(this);
+
+    OutputTreeText(mOut, node, mDepth);
+    if (node->getTrueBlock())
+    {
+        mOut << "true case\n";
+        node->getTrueBlock()->traverse(this);
+    }
+    else
+    {
+        mOut << "true case is null\n";
+    }
+
+    if (node->getFalseBlock())
+    {
+        OutputTreeText(mOut, node, mDepth);
+        mOut << "false case\n";
+        node->getFalseBlock()->traverse(this);
+    }
+
+    --mDepth;
+
+    return false;
+}
+
+bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    mOut << "Switch\n";
+
+    return true;
+}
+
+bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    if (node->getCondition() == nullptr)
+    {
+        mOut << "Default\n";
+    }
+    else
+    {
+        mOut << "Case\n";
+    }
+
+    return true;
+}
+
+void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
+{
+    size_t size = node->getType().getObjectSize();
+
+    for (size_t i = 0; i < size; i++)
+    {
+        OutputTreeText(mOut, node, mDepth);
+        switch (node->getUnionArrayPointer()[i].getType())
+        {
+            case EbtBool:
+                if (node->getUnionArrayPointer()[i].getBConst())
+                    mOut << "true";
+                else
+                    mOut << "false";
+
+                mOut << " ("
+                     << "const bool"
+                     << ")";
+                mOut << "\n";
+                break;
+            case EbtFloat:
+                mOut << node->getUnionArrayPointer()[i].getFConst();
+                mOut << " (const float)\n";
+                break;
+            case EbtInt:
+                mOut << node->getUnionArrayPointer()[i].getIConst();
+                mOut << " (const int)\n";
+                break;
+            case EbtUInt:
+                mOut << node->getUnionArrayPointer()[i].getUConst();
+                mOut << " (const uint)\n";
+                break;
+            case EbtYuvCscStandardEXT:
+                mOut << getYuvCscStandardEXTString(
+                    node->getUnionArrayPointer()[i].getYuvCscStandardEXTConst());
+                mOut << " (const yuvCscStandardEXT)\n";
+                break;
+            default:
+                mOut.prefix(SH_ERROR);
+                mOut << "Unknown constant\n";
+                break;
+        }
+    }
+}
+
+bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    mOut << "Loop with condition ";
+    if (node->getType() == ELoopDoWhile)
+        mOut << "not ";
+    mOut << "tested first\n";
+
+    ++mDepth;
+
+    OutputTreeText(mOut, node, mDepth);
+    if (node->getCondition())
+    {
+        mOut << "Loop Condition\n";
+        node->getCondition()->traverse(this);
+    }
+    else
+    {
+        mOut << "No loop condition\n";
+    }
+
+    OutputTreeText(mOut, node, mDepth);
+    if (node->getBody())
+    {
+        mOut << "Loop Body\n";
+        node->getBody()->traverse(this);
+    }
+    else
+    {
+        mOut << "No loop body\n";
+    }
+
+    if (node->getExpression())
+    {
+        OutputTreeText(mOut, node, mDepth);
+        mOut << "Loop Terminal Expression\n";
+        node->getExpression()->traverse(this);
+    }
+
+    --mDepth;
+
+    return false;
+}
+
+bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
+{
+    OutputTreeText(mOut, node, mDepth);
+
+    switch (node->getFlowOp())
+    {
+        case EOpKill:
+            mOut << "Branch: Kill";
+            break;
+        case EOpBreak:
+            mOut << "Branch: Break";
+            break;
+        case EOpContinue:
+            mOut << "Branch: Continue";
+            break;
+        case EOpReturn:
+            mOut << "Branch: Return";
+            break;
+        default:
+            mOut << "Branch: Unknown Branch";
+            break;
+    }
+
+    if (node->getExpression())
+    {
+        mOut << " with expression\n";
+        ++mDepth;
+        node->getExpression()->traverse(this);
+        --mDepth;
+    }
+    else
+    {
+        mOut << "\n";
+    }
+
+    return false;
+}
+
+}  // anonymous namespace
+
+void OutputTree(TIntermNode *root, TInfoSinkBase &out)
+{
+    TOutputTraverser it(out);
+    ASSERT(root);
+    root->traverse(&it);
+}
+
+}  // namespace sh
diff --git a/src/compiler/translator/OutputTree.h b/src/compiler/translator/OutputTree.h
new file mode 100644
index 0000000..9f11989
--- /dev/null
+++ b/src/compiler/translator/OutputTree.h
@@ -0,0 +1,22 @@
+//
+// Copyright (c) 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Output the AST intermediate representation of the GLSL code.
+
+#ifndef COMPILER_TRANSLATOR_OUTPUTTREE_H_
+#define COMPILER_TRANSLATOR_OUTPUTTREE_H_
+
+namespace sh
+{
+
+class TIntermNode;
+class TInfoSinkBase;
+
+// Output the AST along with metadata.
+void OutputTree(TIntermNode *root, TInfoSinkBase &out);
+
+}  // namespace sh
+
+#endif  // COMPILER_TRANSLATOR_OUTPUTTREE_H_
\ No newline at end of file
diff --git a/src/compiler/translator/PruneEmptyDeclarations.cpp b/src/compiler/translator/PruneEmptyDeclarations.cpp
index fd0eb41..d6ba83d 100644
--- a/src/compiler/translator/PruneEmptyDeclarations.cpp
+++ b/src/compiler/translator/PruneEmptyDeclarations.cpp
@@ -8,7 +8,7 @@
 
 #include "compiler/translator/PruneEmptyDeclarations.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/PrunePureLiteralStatements.cpp b/src/compiler/translator/PrunePureLiteralStatements.cpp
index 5def5a0..0796f13 100644
--- a/src/compiler/translator/PrunePureLiteralStatements.cpp
+++ b/src/compiler/translator/PrunePureLiteralStatements.cpp
@@ -7,7 +7,7 @@
 
 #include "compiler/translator/PrunePureLiteralStatements.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RecordConstantPrecision.cpp b/src/compiler/translator/RecordConstantPrecision.cpp
index edfd6d5..48f47c8 100644
--- a/src/compiler/translator/RecordConstantPrecision.cpp
+++ b/src/compiler/translator/RecordConstantPrecision.cpp
@@ -17,7 +17,7 @@
 #include "compiler/translator/RecordConstantPrecision.h"
 
 #include "compiler/translator/InfoSink.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RegenerateStructNames.h b/src/compiler/translator/RegenerateStructNames.h
index e4fc67e..7f38854 100644
--- a/src/compiler/translator/RegenerateStructNames.h
+++ b/src/compiler/translator/RegenerateStructNames.h
@@ -7,7 +7,7 @@
 #ifndef COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_
 #define COMPILER_TRANSLATOR_REGENERATESTRUCTNAMES_H_
 
-#include "compiler/translator/Intermediate.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 #include <set>
diff --git a/src/compiler/translator/RemoveDynamicIndexing.cpp b/src/compiler/translator/RemoveDynamicIndexing.cpp
index 9144adf..5e9abe0 100644
--- a/src/compiler/translator/RemoveDynamicIndexing.cpp
+++ b/src/compiler/translator/RemoveDynamicIndexing.cpp
@@ -10,8 +10,8 @@
 #include "compiler/translator/RemoveDynamicIndexing.h"
 
 #include "compiler/translator/InfoSink.h"
-#include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
diff --git a/src/compiler/translator/RemoveInvariantDeclaration.cpp b/src/compiler/translator/RemoveInvariantDeclaration.cpp
index d5e12ba..4b533dc 100644
--- a/src/compiler/translator/RemoveInvariantDeclaration.cpp
+++ b/src/compiler/translator/RemoveInvariantDeclaration.cpp
@@ -6,7 +6,7 @@
 
 #include "compiler/translator/RemoveInvariantDeclaration.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RemovePow.cpp b/src/compiler/translator/RemovePow.cpp
index ca7d08d..790a92f 100644
--- a/src/compiler/translator/RemovePow.cpp
+++ b/src/compiler/translator/RemovePow.cpp
@@ -11,7 +11,7 @@
 #include "compiler/translator/RemovePow.h"
 
 #include "compiler/translator/InfoSink.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RemoveSwitchFallThrough.h b/src/compiler/translator/RemoveSwitchFallThrough.h
index a19c437..6d3091e 100644
--- a/src/compiler/translator/RemoveSwitchFallThrough.h
+++ b/src/compiler/translator/RemoveSwitchFallThrough.h
@@ -7,7 +7,7 @@
 #ifndef COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
 #define COMPILER_TRANSLATOR_REMOVESWITCHFALLTHROUGH_H_
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RewriteDoWhile.cpp b/src/compiler/translator/RewriteDoWhile.cpp
index e10ec74..128ca4c 100644
--- a/src/compiler/translator/RewriteDoWhile.cpp
+++ b/src/compiler/translator/RewriteDoWhile.cpp
@@ -9,7 +9,7 @@
 
 #include "compiler/translator/RewriteDoWhile.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RewriteTexelFetchOffset.cpp b/src/compiler/translator/RewriteTexelFetchOffset.cpp
index 13f834a..f67e5ef 100644
--- a/src/compiler/translator/RewriteTexelFetchOffset.cpp
+++ b/src/compiler/translator/RewriteTexelFetchOffset.cpp
@@ -9,7 +9,7 @@
 #include "compiler/translator/RewriteTexelFetchOffset.h"
 
 #include "common/angleutils.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
diff --git a/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp b/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp
index 1350c5e..5729db4 100644
--- a/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp
+++ b/src/compiler/translator/RewriteUnaryMinusOperatorFloat.cpp
@@ -6,7 +6,7 @@
 
 #include "compiler/translator/RewriteUnaryMinusOperatorFloat.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp b/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp
index ef708cb..5c68cf4 100644
--- a/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp
+++ b/src/compiler/translator/RewriteUnaryMinusOperatorInt.cpp
@@ -8,7 +8,7 @@
 
 #include "compiler/translator/RewriteUnaryMinusOperatorInt.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp b/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
index 1553288..db8f549 100644
--- a/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
+++ b/src/compiler/translator/ScalarizeVecAndMatConstructorArgs.cpp
@@ -15,7 +15,7 @@
 
 #include "angle_gl.h"
 #include "common/angleutils.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/SearchSymbol.h b/src/compiler/translator/SearchSymbol.h
index 4fbea8c..b8379e0 100644
--- a/src/compiler/translator/SearchSymbol.h
+++ b/src/compiler/translator/SearchSymbol.h
@@ -9,7 +9,7 @@
 #ifndef COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
 #define COMPILER_TRANSLATOR_SEARCHSYMBOL_H_
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/ParseContext.h"
 
 namespace sh
diff --git a/src/compiler/translator/SeparateDeclarations.cpp b/src/compiler/translator/SeparateDeclarations.cpp
index 93c8b38..9a06607 100644
--- a/src/compiler/translator/SeparateDeclarations.cpp
+++ b/src/compiler/translator/SeparateDeclarations.cpp
@@ -15,7 +15,7 @@
 
 #include "compiler/translator/SeparateDeclarations.h"
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/SeparateExpressionsReturningArrays.cpp b/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
index 9d45915..99a8006 100644
--- a/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
+++ b/src/compiler/translator/SeparateExpressionsReturningArrays.cpp
@@ -11,8 +11,8 @@
 
 #include "compiler/translator/SeparateExpressionsReturningArrays.h"
 
-#include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/SimplifyLoopConditions.cpp b/src/compiler/translator/SimplifyLoopConditions.cpp
index 61d69e5..d8a077f 100644
--- a/src/compiler/translator/SimplifyLoopConditions.cpp
+++ b/src/compiler/translator/SimplifyLoopConditions.cpp
@@ -10,8 +10,8 @@
 
 #include "compiler/translator/SimplifyLoopConditions.h"
 
-#include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/SplitSequenceOperator.cpp b/src/compiler/translator/SplitSequenceOperator.cpp
index f42c064..2c0e289 100644
--- a/src/compiler/translator/SplitSequenceOperator.cpp
+++ b/src/compiler/translator/SplitSequenceOperator.cpp
@@ -11,8 +11,8 @@
 
 #include "compiler/translator/SplitSequenceOperator.h"
 
-#include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/UnfoldShortCircuitAST.h b/src/compiler/translator/UnfoldShortCircuitAST.h
index fe6d8fd..7f377e6f 100644
--- a/src/compiler/translator/UnfoldShortCircuitAST.h
+++ b/src/compiler/translator/UnfoldShortCircuitAST.h
@@ -11,7 +11,7 @@
 #define COMPILER_TRANSLATOR_UNFOLDSHORTCIRCUITAST_H_
 
 #include "common/angleutils.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/UnfoldShortCircuitToIf.cpp b/src/compiler/translator/UnfoldShortCircuitToIf.cpp
index 0a3f696..3144915 100644
--- a/src/compiler/translator/UnfoldShortCircuitToIf.cpp
+++ b/src/compiler/translator/UnfoldShortCircuitToIf.cpp
@@ -11,8 +11,8 @@
 
 #include "compiler/translator/UnfoldShortCircuitToIf.h"
 
-#include "compiler/translator/IntermNode.h"
 #include "compiler/translator/IntermNodePatternMatcher.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/ValidateGlobalInitializer.cpp b/src/compiler/translator/ValidateGlobalInitializer.cpp
index 10a3e51..492972b 100644
--- a/src/compiler/translator/ValidateGlobalInitializer.cpp
+++ b/src/compiler/translator/ValidateGlobalInitializer.cpp
@@ -6,6 +6,7 @@
 
 #include "compiler/translator/ValidateGlobalInitializer.h"
 
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/ParseContext.h"
 
 namespace sh
diff --git a/src/compiler/translator/ValidateLimitations.cpp b/src/compiler/translator/ValidateLimitations.cpp
index a59b1bb..10e57f5 100644
--- a/src/compiler/translator/ValidateLimitations.cpp
+++ b/src/compiler/translator/ValidateLimitations.cpp
@@ -8,6 +8,7 @@
 
 #include "angle_gl.h"
 #include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/ParseContext.h"
 
 namespace sh
diff --git a/src/compiler/translator/ValidateMultiviewWebGL.cpp b/src/compiler/translator/ValidateMultiviewWebGL.cpp
index 169a32e..56ba423 100644
--- a/src/compiler/translator/ValidateMultiviewWebGL.cpp
+++ b/src/compiler/translator/ValidateMultiviewWebGL.cpp
@@ -15,7 +15,7 @@
 #include "angle_gl.h"
 #include "compiler/translator/Diagnostics.h"
 #include "compiler/translator/FindSymbolNode.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 
 namespace sh
diff --git a/src/compiler/translator/ValidateOutputs.cpp b/src/compiler/translator/ValidateOutputs.cpp
index 36e339b..9ac9c68 100644
--- a/src/compiler/translator/ValidateOutputs.cpp
+++ b/src/compiler/translator/ValidateOutputs.cpp
@@ -12,7 +12,7 @@
 #include <set>
 
 #include "compiler/translator/InfoSink.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/ParseContext.h"
 
 namespace sh
diff --git a/src/compiler/translator/ValidateSwitch.cpp b/src/compiler/translator/ValidateSwitch.cpp
index 6091c72..2c96017 100644
--- a/src/compiler/translator/ValidateSwitch.cpp
+++ b/src/compiler/translator/ValidateSwitch.cpp
@@ -6,8 +6,8 @@
 
 #include "compiler/translator/ValidateSwitch.h"
 
-#include "compiler/translator/IntermNode.h"
 #include "compiler/translator/Diagnostics.h"
+#include "compiler/translator/IntermTraverse.h"
 
 namespace sh
 {
diff --git a/src/compiler/translator/VariableInfo.cpp b/src/compiler/translator/VariableInfo.cpp
index 2af0bc1..142b5db 100644
--- a/src/compiler/translator/VariableInfo.cpp
+++ b/src/compiler/translator/VariableInfo.cpp
@@ -8,7 +8,8 @@
 
 #include "angle_gl.h"
 #include "common/utilities.h"
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/HashNames.h"
+#include "compiler/translator/IntermTraverse.h"
 #include "compiler/translator/SymbolTable.h"
 #include "compiler/translator/util.h"
 
@@ -440,7 +441,7 @@
         }
     }
     variableOut->name       = name.c_str();
-    variableOut->mappedName = TIntermTraverser::hash(name, mHashFunction).c_str();
+    variableOut->mappedName = HashName(name, mHashFunction).c_str();
     variableOut->arraySize  = type.getArraySize();
 }
 
@@ -504,8 +505,7 @@
 
     InterfaceBlock interfaceBlock;
     interfaceBlock.name = blockType->name().c_str();
-    interfaceBlock.mappedName =
-        TIntermTraverser::hash(blockType->name().c_str(), mHashFunction).c_str();
+    interfaceBlock.mappedName = HashName(blockType->name().c_str(), mHashFunction).c_str();
     interfaceBlock.instanceName =
         (blockType->hasInstanceName() ? blockType->instanceName().c_str() : "");
     interfaceBlock.arraySize        = variable.getArraySize();
diff --git a/src/compiler/translator/VersionGLSL.h b/src/compiler/translator/VersionGLSL.h
index 9cf727c..8b82eb9 100644
--- a/src/compiler/translator/VersionGLSL.h
+++ b/src/compiler/translator/VersionGLSL.h
@@ -7,7 +7,7 @@
 #ifndef COMPILER_TRANSLATOR_VERSIONGLSL_H_
 #define COMPILER_TRANSLATOR_VERSIONGLSL_H_
 
-#include "compiler/translator/IntermNode.h"
+#include "compiler/translator/IntermTraverse.h"
 
 #include "compiler/translator/Pragma.h"
 
diff --git a/src/compiler/translator/intermOut.cpp b/src/compiler/translator/intermOut.cpp
deleted file mode 100644
index fe65249..0000000
--- a/src/compiler/translator/intermOut.cpp
+++ /dev/null
@@ -1,719 +0,0 @@
-//
-// Copyright (c) 2002-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-
-#include "compiler/translator/Intermediate.h"
-#include "compiler/translator/SymbolTable.h"
-
-namespace sh
-{
-
-namespace
-{
-
-void OutputFunction(TInfoSinkBase &out, const char *str, TFunctionSymbolInfo *info)
-{
-    const char *internal = info->getNameObj().isInternal() ? " (internal function)" : "";
-    out << str << internal << ": " << info->getNameObj().getString() << " (symbol id "
-        << info->getId().get() << ")";
-}
-
-//
-// Two purposes:
-// 1.  Show an example of how to iterate tree.  Functions can
-//     also directly call Traverse() on children themselves to
-//     have finer grained control over the process than shown here.
-//     See the last function for how to get started.
-// 2.  Print out a text based description of the tree.
-//
-
-//
-// Use this class to carry along data from node to node in
-// the traversal
-//
-class TOutputTraverser : public TIntermTraverser
-{
-  public:
-    TOutputTraverser(TInfoSinkBase &i) : TIntermTraverser(true, false, false), sink(i) {}
-    TInfoSinkBase &sink;
-
-  protected:
-    void visitSymbol(TIntermSymbol *) override;
-    void visitConstantUnion(TIntermConstantUnion *) override;
-    bool visitSwizzle(Visit visit, TIntermSwizzle *node) override;
-    bool visitBinary(Visit visit, TIntermBinary *) override;
-    bool visitUnary(Visit visit, TIntermUnary *) override;
-    bool visitTernary(Visit visit, TIntermTernary *node) override;
-    bool visitIfElse(Visit visit, TIntermIfElse *node) override;
-    bool visitSwitch(Visit visit, TIntermSwitch *node) override;
-    bool visitCase(Visit visit, TIntermCase *node) override;
-    bool visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node) override;
-    bool visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node) override;
-    bool visitAggregate(Visit visit, TIntermAggregate *) override;
-    bool visitBlock(Visit visit, TIntermBlock *) override;
-    bool visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node) override;
-    bool visitDeclaration(Visit visit, TIntermDeclaration *node) override;
-    bool visitLoop(Visit visit, TIntermLoop *) override;
-    bool visitBranch(Visit visit, TIntermBranch *) override;
-};
-
-//
-// Helper functions for printing, not part of traversing.
-//
-void OutputTreeText(TInfoSinkBase &sink, TIntermNode *node, const int depth)
-{
-    int i;
-
-    sink.location(node->getLine().first_file, node->getLine().first_line);
-
-    for (i = 0; i < depth; ++i)
-        sink << "  ";
-}
-
-}  // namespace anonymous
-
-//
-// The rest of the file are the traversal functions.  The last one
-// is the one that starts the traversal.
-//
-// Return true from interior nodes to have the external traversal
-// continue on to children.  If you process children yourself,
-// return false.
-//
-
-void TOutputTraverser::visitSymbol(TIntermSymbol *node)
-{
-    OutputTreeText(sink, node, mDepth);
-
-    sink << "'" << node->getSymbol() << "' ";
-    sink << "(symbol id " << node->getId() << ") ";
-    sink << "(" << node->getCompleteString() << ")";
-    sink << "\n";
-}
-
-bool TOutputTraverser::visitSwizzle(Visit visit, TIntermSwizzle *node)
-{
-    TInfoSinkBase &out = sink;
-    OutputTreeText(out, node, mDepth);
-    out << "vector swizzle (";
-    node->writeOffsetsAsXYZW(&out);
-    out << ")";
-
-    out << " (" << node->getCompleteString() << ")";
-    out << "\n";
-    return true;
-}
-
-bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    switch (node->getOp())
-    {
-        case EOpComma:
-            out << "comma";
-            break;
-        case EOpAssign:
-            out << "move second child to first child";
-            break;
-        case EOpInitialize:
-            out << "initialize first child with second child";
-            break;
-        case EOpAddAssign:
-            out << "add second child into first child";
-            break;
-        case EOpSubAssign:
-            out << "subtract second child into first child";
-            break;
-        case EOpMulAssign:
-            out << "multiply second child into first child";
-            break;
-        case EOpVectorTimesMatrixAssign:
-            out << "matrix mult second child into first child";
-            break;
-        case EOpVectorTimesScalarAssign:
-            out << "vector scale second child into first child";
-            break;
-        case EOpMatrixTimesScalarAssign:
-            out << "matrix scale second child into first child";
-            break;
-        case EOpMatrixTimesMatrixAssign:
-            out << "matrix mult second child into first child";
-            break;
-        case EOpDivAssign:
-            out << "divide second child into first child";
-            break;
-        case EOpIModAssign:
-            out << "modulo second child into first child";
-            break;
-        case EOpBitShiftLeftAssign:
-            out << "bit-wise shift first child left by second child";
-            break;
-        case EOpBitShiftRightAssign:
-            out << "bit-wise shift first child right by second child";
-            break;
-        case EOpBitwiseAndAssign:
-            out << "bit-wise and second child into first child";
-            break;
-        case EOpBitwiseXorAssign:
-            out << "bit-wise xor second child into first child";
-            break;
-        case EOpBitwiseOrAssign:
-            out << "bit-wise or second child into first child";
-            break;
-
-        case EOpIndexDirect:
-            out << "direct index";
-            break;
-        case EOpIndexIndirect:
-            out << "indirect index";
-            break;
-        case EOpIndexDirectStruct:
-            out << "direct index for structure";
-            break;
-        case EOpIndexDirectInterfaceBlock:
-            out << "direct index for interface block";
-            break;
-
-        case EOpAdd:
-            out << "add";
-            break;
-        case EOpSub:
-            out << "subtract";
-            break;
-        case EOpMul:
-            out << "component-wise multiply";
-            break;
-        case EOpDiv:
-            out << "divide";
-            break;
-        case EOpIMod:
-            out << "modulo";
-            break;
-        case EOpBitShiftLeft:
-            out << "bit-wise shift left";
-            break;
-        case EOpBitShiftRight:
-            out << "bit-wise shift right";
-            break;
-        case EOpBitwiseAnd:
-            out << "bit-wise and";
-            break;
-        case EOpBitwiseXor:
-            out << "bit-wise xor";
-            break;
-        case EOpBitwiseOr:
-            out << "bit-wise or";
-            break;
-
-        case EOpEqual:
-            out << "Compare Equal";
-            break;
-        case EOpNotEqual:
-            out << "Compare Not Equal";
-            break;
-        case EOpLessThan:
-            out << "Compare Less Than";
-            break;
-        case EOpGreaterThan:
-            out << "Compare Greater Than";
-            break;
-        case EOpLessThanEqual:
-            out << "Compare Less Than or Equal";
-            break;
-        case EOpGreaterThanEqual:
-            out << "Compare Greater Than or Equal";
-            break;
-
-        case EOpVectorTimesScalar:
-            out << "vector-scale";
-            break;
-        case EOpVectorTimesMatrix:
-            out << "vector-times-matrix";
-            break;
-        case EOpMatrixTimesVector:
-            out << "matrix-times-vector";
-            break;
-        case EOpMatrixTimesScalar:
-            out << "matrix-scale";
-            break;
-        case EOpMatrixTimesMatrix:
-            out << "matrix-multiply";
-            break;
-
-        case EOpLogicalOr:
-            out << "logical-or";
-            break;
-        case EOpLogicalXor:
-            out << "logical-xor";
-            break;
-        case EOpLogicalAnd:
-            out << "logical-and";
-            break;
-        default:
-            out << "<unknown op>";
-    }
-
-    out << " (" << node->getCompleteString() << ")";
-
-    out << "\n";
-
-    // Special handling for direct indexes. Because constant
-    // unions are not aware they are struct indexes, treat them
-    // here where we have that contextual knowledge.
-    if (node->getOp() == EOpIndexDirectStruct || node->getOp() == EOpIndexDirectInterfaceBlock)
-    {
-        node->getLeft()->traverse(this);
-
-        TIntermConstantUnion *intermConstantUnion = node->getRight()->getAsConstantUnion();
-        ASSERT(intermConstantUnion);
-
-        OutputTreeText(out, intermConstantUnion, mDepth + 1);
-
-        // The following code finds the field name from the constant union
-        const TConstantUnion *constantUnion   = intermConstantUnion->getUnionArrayPointer();
-        const TStructure *structure           = node->getLeft()->getType().getStruct();
-        const TInterfaceBlock *interfaceBlock = node->getLeft()->getType().getInterfaceBlock();
-        ASSERT(structure || interfaceBlock);
-
-        const TFieldList &fields = structure ? structure->fields() : interfaceBlock->fields();
-
-        const TField *field = fields[constantUnion->getIConst()];
-
-        out << constantUnion->getIConst() << " (field '" << field->name() << "')";
-
-        out << "\n";
-
-        return false;
-    }
-
-    return true;
-}
-
-bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    switch (node->getOp())
-    {
-        // Give verbose names for ops that have special syntax and some built-in functions that are
-        // easy to confuse with others, but mostly use GLSL names for functions.
-        case EOpNegative:
-            out << "Negate value";
-            break;
-        case EOpPositive:
-            out << "Positive sign";
-            break;
-        case EOpLogicalNot:
-            out << "negation";
-            break;
-        case EOpBitwiseNot:
-            out << "bit-wise not";
-            break;
-
-        case EOpPostIncrement:
-            out << "Post-Increment";
-            break;
-        case EOpPostDecrement:
-            out << "Post-Decrement";
-            break;
-        case EOpPreIncrement:
-            out << "Pre-Increment";
-            break;
-        case EOpPreDecrement:
-            out << "Pre-Decrement";
-            break;
-
-        case EOpLogicalNotComponentWise:
-            out << "component-wise not";
-            break;
-
-        default:
-            out << GetOperatorString(node->getOp());
-            break;
-    }
-
-    out << " (" << node->getCompleteString() << ")";
-
-    out << "\n";
-
-    return true;
-}
-
-bool TOutputTraverser::visitFunctionDefinition(Visit visit, TIntermFunctionDefinition *node)
-{
-    TInfoSinkBase &out = sink;
-    OutputTreeText(out, node, mDepth);
-    out << "Function Definition:\n";
-    out << "\n";
-    return true;
-}
-
-bool TOutputTraverser::visitInvariantDeclaration(Visit visit, TIntermInvariantDeclaration *node)
-{
-    TInfoSinkBase &out = sink;
-    OutputTreeText(out, node, mDepth);
-    out << "Invariant Declaration:\n";
-    return true;
-}
-
-bool TOutputTraverser::visitFunctionPrototype(Visit visit, TIntermFunctionPrototype *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-    OutputFunction(out, "Function Prototype", node->getFunctionSymbolInfo());
-    out << " (" << node->getCompleteString() << ")";
-    out << "\n";
-
-    return true;
-}
-
-bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    if (node->getOp() == EOpNull)
-    {
-        out.prefix(SH_ERROR);
-        out << "node is still EOpNull!\n";
-        return true;
-    }
-
-    // Give verbose names for some built-in functions that are easy to confuse with others, but
-    // mostly use GLSL names for functions.
-    switch (node->getOp())
-    {
-        case EOpCallFunctionInAST:
-            OutputFunction(out, "Call an user-defined function", node->getFunctionSymbolInfo());
-            break;
-        case EOpCallInternalRawFunction:
-            OutputFunction(out, "Call an internal function with raw implementation",
-                           node->getFunctionSymbolInfo());
-            break;
-        case EOpCallBuiltInFunction:
-            OutputFunction(out, "Call a built-in function", node->getFunctionSymbolInfo());
-            break;
-
-        case EOpConstruct:
-            // The type of the constructor will be printed below.
-            out << "Construct";
-            break;
-
-        case EOpEqualComponentWise:
-            out << "component-wise equal";
-            break;
-        case EOpNotEqualComponentWise:
-            out << "component-wise not equal";
-            break;
-        case EOpLessThanComponentWise:
-            out << "component-wise less than";
-            break;
-        case EOpGreaterThanComponentWise:
-            out << "component-wise greater than";
-            break;
-        case EOpLessThanEqualComponentWise:
-            out << "component-wise less than or equal";
-            break;
-        case EOpGreaterThanEqualComponentWise:
-            out << "component-wise greater than or equal";
-            break;
-
-        case EOpDot:
-            out << "dot product";
-            break;
-        case EOpCross:
-            out << "cross product";
-            break;
-        case EOpMulMatrixComponentWise:
-            out << "component-wise multiply";
-            break;
-
-        default:
-            out << GetOperatorString(node->getOp());
-            break;
-    }
-
-    out << " (" << node->getCompleteString() << ")";
-
-    out << "\n";
-
-    return true;
-}
-
-bool TOutputTraverser::visitBlock(Visit visit, TIntermBlock *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-    out << "Code block\n";
-
-    return true;
-}
-
-bool TOutputTraverser::visitDeclaration(Visit visit, TIntermDeclaration *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-    out << "Declaration\n";
-
-    return true;
-}
-
-bool TOutputTraverser::visitTernary(Visit visit, TIntermTernary *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    out << "Ternary selection";
-    out << " (" << node->getCompleteString() << ")\n";
-
-    ++mDepth;
-
-    OutputTreeText(sink, node, mDepth);
-    out << "Condition\n";
-    node->getCondition()->traverse(this);
-
-    OutputTreeText(sink, node, mDepth);
-    if (node->getTrueExpression())
-    {
-        out << "true case\n";
-        node->getTrueExpression()->traverse(this);
-    }
-    if (node->getFalseExpression())
-    {
-        OutputTreeText(sink, node, mDepth);
-        out << "false case\n";
-        node->getFalseExpression()->traverse(this);
-    }
-
-    --mDepth;
-
-    return false;
-}
-
-bool TOutputTraverser::visitIfElse(Visit visit, TIntermIfElse *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    out << "If test\n";
-
-    ++mDepth;
-
-    OutputTreeText(sink, node, mDepth);
-    out << "Condition\n";
-    node->getCondition()->traverse(this);
-
-    OutputTreeText(sink, node, mDepth);
-    if (node->getTrueBlock())
-    {
-        out << "true case\n";
-        node->getTrueBlock()->traverse(this);
-    }
-    else
-    {
-        out << "true case is null\n";
-    }
-
-    if (node->getFalseBlock())
-    {
-        OutputTreeText(sink, node, mDepth);
-        out << "false case\n";
-        node->getFalseBlock()->traverse(this);
-    }
-
-    --mDepth;
-
-    return false;
-}
-
-bool TOutputTraverser::visitSwitch(Visit visit, TIntermSwitch *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    out << "Switch\n";
-
-    return true;
-}
-
-bool TOutputTraverser::visitCase(Visit visit, TIntermCase *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    if (node->getCondition() == nullptr)
-    {
-        out << "Default\n";
-    }
-    else
-    {
-        out << "Case\n";
-    }
-
-    return true;
-}
-
-void TOutputTraverser::visitConstantUnion(TIntermConstantUnion *node)
-{
-    TInfoSinkBase &out = sink;
-
-    size_t size = node->getType().getObjectSize();
-
-    for (size_t i = 0; i < size; i++)
-    {
-        OutputTreeText(out, node, mDepth);
-        switch (node->getUnionArrayPointer()[i].getType())
-        {
-            case EbtBool:
-                if (node->getUnionArrayPointer()[i].getBConst())
-                    out << "true";
-                else
-                    out << "false";
-
-                out << " ("
-                    << "const bool"
-                    << ")";
-                out << "\n";
-                break;
-            case EbtFloat:
-                out << node->getUnionArrayPointer()[i].getFConst();
-                out << " (const float)\n";
-                break;
-            case EbtInt:
-                out << node->getUnionArrayPointer()[i].getIConst();
-                out << " (const int)\n";
-                break;
-            case EbtUInt:
-                out << node->getUnionArrayPointer()[i].getUConst();
-                out << " (const uint)\n";
-                break;
-            case EbtYuvCscStandardEXT:
-                out << getYuvCscStandardEXTString(
-                    node->getUnionArrayPointer()[i].getYuvCscStandardEXTConst());
-                out << " (const yuvCscStandardEXT)\n";
-                break;
-            default:
-                out.prefix(SH_ERROR);
-                out << "Unknown constant\n";
-                break;
-        }
-    }
-}
-
-bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    out << "Loop with condition ";
-    if (node->getType() == ELoopDoWhile)
-        out << "not ";
-    out << "tested first\n";
-
-    ++mDepth;
-
-    OutputTreeText(sink, node, mDepth);
-    if (node->getCondition())
-    {
-        out << "Loop Condition\n";
-        node->getCondition()->traverse(this);
-    }
-    else
-    {
-        out << "No loop condition\n";
-    }
-
-    OutputTreeText(sink, node, mDepth);
-    if (node->getBody())
-    {
-        out << "Loop Body\n";
-        node->getBody()->traverse(this);
-    }
-    else
-    {
-        out << "No loop body\n";
-    }
-
-    if (node->getExpression())
-    {
-        OutputTreeText(sink, node, mDepth);
-        out << "Loop Terminal Expression\n";
-        node->getExpression()->traverse(this);
-    }
-
-    --mDepth;
-
-    return false;
-}
-
-bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch *node)
-{
-    TInfoSinkBase &out = sink;
-
-    OutputTreeText(out, node, mDepth);
-
-    switch (node->getFlowOp())
-    {
-        case EOpKill:
-            out << "Branch: Kill";
-            break;
-        case EOpBreak:
-            out << "Branch: Break";
-            break;
-        case EOpContinue:
-            out << "Branch: Continue";
-            break;
-        case EOpReturn:
-            out << "Branch: Return";
-            break;
-        default:
-            out << "Branch: Unknown Branch";
-            break;
-    }
-
-    if (node->getExpression())
-    {
-        out << " with expression\n";
-        ++mDepth;
-        node->getExpression()->traverse(this);
-        --mDepth;
-    }
-    else
-    {
-        out << "\n";
-    }
-
-    return false;
-}
-
-//
-// This function is the one to call externally to start the traversal.
-// Individual functions can be initialized to 0 to skip processing of that
-// type of node. Its children will still be processed.
-//
-void TIntermediate::outputTree(TIntermNode *root, TInfoSinkBase &infoSink)
-{
-    TOutputTraverser it(infoSink);
-
-    ASSERT(root);
-
-    root->traverse(&it);
-}
-
-}  // namespace sh