Add a new TIntermRaw node type to translator.

This raw node stores text strings that we directly copy to the
output. This allows for more tricky substitutions that don't fit
in to the HLSL/GLSL shared parsing model.

BUG=346463
BUG=391697

Change-Id: Ibbde6db4fc98ef6d892f219631ca1a258a902a86
Reviewed-on: https://chromium-review.googlesource.com/206823
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Nicolas Capens <capn@chromium.org>
Reviewed-by: Shannon Woods <shannonwoods@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/207833
diff --git a/src/compiler/translator/IntermTraverse.cpp b/src/compiler/translator/IntermTraverse.cpp
index a579488..69f87c3 100644
--- a/src/compiler/translator/IntermTraverse.cpp
+++ b/src/compiler/translator/IntermTraverse.cpp
@@ -257,3 +257,7 @@
         it->visitBranch(PostVisit, this);
 }
 
+void TIntermRaw::traverse(TIntermTraverser *it)
+{
+    it->visitRaw(this);
+}
diff --git a/src/compiler/translator/OutputHLSL.cpp b/src/compiler/translator/OutputHLSL.cpp
index ea0045f..5520c86 100644
--- a/src/compiler/translator/OutputHLSL.cpp
+++ b/src/compiler/translator/OutputHLSL.cpp
@@ -1850,6 +1850,11 @@
     }
 }
 
+void OutputHLSL::visitRaw(TIntermRaw *node)
+{
+    mBody << node->getRawText();
+}
+
 bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node)
 {
     TInfoSinkBase &out = mBody;
diff --git a/src/compiler/translator/OutputHLSL.h b/src/compiler/translator/OutputHLSL.h
index f681b71..ab5a90b 100644
--- a/src/compiler/translator/OutputHLSL.h
+++ b/src/compiler/translator/OutputHLSL.h
@@ -55,6 +55,7 @@
 
     // Visit AST nodes and output their code to the body stream
     void visitSymbol(TIntermSymbol*);
+    void visitRaw(TIntermRaw*);
     void visitConstantUnion(TIntermConstantUnion*);
     bool visitBinary(Visit visit, TIntermBinary*);
     bool visitUnary(Visit visit, TIntermUnary*);
diff --git a/src/compiler/translator/intermediate.h b/src/compiler/translator/intermediate.h
index 7c72099..2fdde02 100644
--- a/src/compiler/translator/intermediate.h
+++ b/src/compiler/translator/intermediate.h
@@ -211,6 +211,7 @@
 class TIntermSymbol;
 class TIntermLoop;
 class TInfoSink;
+class TIntermRaw;
 
 //
 // Base class for the tree nodes
@@ -238,6 +239,7 @@
     virtual TIntermSelection* getAsSelectionNode() { return 0; }
     virtual TIntermSymbol* getAsSymbolNode() { return 0; }
     virtual TIntermLoop* getAsLoopNode() { return 0; }
+    virtual TIntermRaw* getAsRawNode() { return 0; }
 
     // Replace a child node. Return true if |original| is a child
     // node and it is replaced; otherwise, return false.
@@ -397,6 +399,29 @@
     TString symbol;
 };
 
+// A Raw node stores raw code, that the translator will insert verbatim
+// into the output stream. Useful for transformation operations that make
+// complex code that might not fit naturally into the GLSL model.
+class TIntermRaw : public TIntermTyped {
+public:
+    TIntermRaw(const TType &t, const TString &rawTextIn)
+        : TIntermTyped(t), rawText(rawTextIn)
+    {}
+
+    virtual bool hasSideEffects() const { return false; }
+
+    TString getRawText() const { return rawText; }
+
+    virtual void traverse(TIntermTraverser*);
+
+    virtual TIntermRaw* getAsRawNode() { return this; }
+    virtual bool replaceChildNode(TIntermNode *, TIntermNode *) { return false; }
+    virtual void enqueueChildren(std::queue<TIntermNode*> *nodeQueue) const {}
+
+protected:
+    TString rawText;
+};
+
 class TIntermConstantUnion : public TIntermTyped {
 public:
     TIntermConstantUnion(ConstantUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { }
@@ -619,6 +644,7 @@
     virtual ~TIntermTraverser() {}
 
     virtual void visitSymbol(TIntermSymbol*) {}
+    virtual void visitRaw(TIntermRaw*) {}
     virtual void visitConstantUnion(TIntermConstantUnion*) {}
     virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;}
     virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;}