Implement implicit conversions of function-call arguments (both in and out) as explic...
authorJohn Kessenich <cepheus@frii.com>
Sun, 16 Mar 2014 23:03:07 +0000 (23:03 +0000)
committerJohn Kessenich <cepheus@frii.com>
Sun, 16 Mar 2014 23:03:07 +0000 (23:03 +0000)
Also
 - uniformly handle EvqConstReadOnly as an input argument in a function, with
   isParamInput() and isParamOutput() queries in TQualifier.
 - provide a makeTemporary() in TQualifier, for erasing original qualification when making a temp
 - provide a makeInternalVariable() call to make a shader variable not seen in the shader source

git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@25912 e7fa87d3-cd2b-0410-9028-fcbf551c1848

Test/120.vert
Test/baseResults/120.vert.out
Test/baseResults/functionSemantics.frag.out
glslang/Include/BaseTypes.h
glslang/Include/Types.h
glslang/Include/intermediate.h
glslang/MachineIndependent/Intermediate.cpp
glslang/MachineIndependent/ParseHelper.cpp
glslang/MachineIndependent/ParseHelper.h
glslang/MachineIndependent/SymbolTable.h
glslang/MachineIndependent/localintermediate.h

index 3981b2c..8790980 100644 (file)
@@ -58,15 +58,15 @@ float overloadA(float);            // ERROR, different return value for same sig
 float overloadA(out float f, int);
 float overloadA(int i);
 
-vec2 overloadB(float, float);
+void overloadB(float, const in float) { }
 
 vec2 overloadC(int, int);
-vec2 overloadC(int, float);
+vec2 overloadC(const in int, float);
 vec2 overloadC(float, int);
 vec2 overloadC(vec2, vec2);
 
 vec3 overloadD(int, float);
-vec3 overloadD(float, int);
+vec3 overloadD(float, in int);
 
 vec3 overloadE(float[2]);
 vec3 overloadE(mat2 m);
@@ -119,3 +119,21 @@ void foo()
 }
 
 varying vec4 gl_TexCoord[35]; // ERROR, size too big
+
+// tests for output conversions
+void outFun(in float, out ivec2, in int, out float);
+int outFunRet(in float, out int, const in int, out ivec4);
+ivec2 outFunRet(in float, out ivec4, in int, out ivec4);
+
+void foo2()
+{
+    vec2 v2;
+    vec4 v4;
+    float f;
+    int i;
+
+    outFun(i, v2, i, f);
+    outFunRet(i, f, i, v4);
+    float ret = outFunRet(i, f, i, v4);
+    vec2 ret2 = outFunRet(i, v4, i, v4);
+}
index a2063a0..df74e19 100644 (file)
@@ -94,20 +94,25 @@ ERROR: node is still EOpNull!
 0:43        'gl_PointSize' (invariant gl_PointSize float)\r
 0:43        Constant:\r
 0:43          3.800000\r
+0:61  Function Definition: overloadB(f1;f1; (void)\r
+0:61    Function Parameters: \r
+0:61      '' (in float)\r
+0:61      '' (const (read only) float)\r
 0:78  Function Definition: foo( (void)\r
 0:78    Function Parameters: \r
 0:?     Sequence\r
-0:83      Function Call: overloadB(f1;f1; (2-component vector of float)\r
+0:83      Function Call: overloadB(f1;f1; (void)\r
 0:83        'f' (float)\r
 0:83        'f' (float)\r
-0:84      Function Call: overloadB(f1;f1; (2-component vector of float)\r
+0:84      Function Call: overloadB(f1;f1; (void)\r
 0:84        'f' (float)\r
 0:84        Constant:\r
-0:84          2 (const int)\r
-0:85      Function Call: overloadB(f1;f1; (2-component vector of float)\r
+0:84          2.000000\r
+0:85      Function Call: overloadB(f1;f1; (void)\r
 0:85        Constant:\r
-0:85          1 (const int)\r
-0:85        'i' (int)\r
+0:85          1.000000\r
+0:85        Convert int to float (float)\r
+0:85          'i' (int)\r
 0:87      Constant:\r
 0:87        0.000000\r
 0:88      Function Call: overloadC(i1;i1; (2-component vector of float)\r
@@ -125,8 +130,8 @@ ERROR: node is still EOpNull!
 0:90        0.000000\r
 0:91      Function Call: overloadC(vf2;vf2; (2-component vector of float)\r
 0:91        Constant:\r
-0:91          1 (const int)\r
-0:91          1 (const int)\r
+0:91          1.000000\r
+0:91          1.000000\r
 0:91        Constant:\r
 0:91          2.000000\r
 0:91          2.000000\r
@@ -137,7 +142,8 @@ ERROR: node is still EOpNull!
 0:94        'f' (float)\r
 0:94        'i' (int)\r
 0:95      Function Call: overloadD(f1;i1; (3-component vector of float)\r
-0:95        'i' (int)\r
+0:95        Convert int to float (float)\r
+0:95          'i' (int)\r
 0:95        'i' (int)\r
 0:98      Constant:\r
 0:98        0.000000\r
@@ -146,8 +152,8 @@ ERROR: node is still EOpNull!
 0:101      Function Call: texture2D(s21;vf2; (4-component vector of float)\r
 0:101        's2D' (uniform sampler2D)\r
 0:101        Constant:\r
-0:101          0 (const int)\r
-0:101          0 (const int)\r
+0:101          0.000000\r
+0:101          0.000000\r
 0:102      clamp (4-component vector of float)\r
 0:102        'attv4' (in 4-component vector of float)\r
 0:102        Constant:\r
@@ -181,8 +187,8 @@ ERROR: node is still EOpNull!
 0:111        0.000000\r
 0:112      Function Call: overloadE(vf2; (3-component vector of float)\r
 0:112        Constant:\r
-0:112          1 (const int)\r
-0:112          1 (const int)\r
+0:112          1.000000\r
+0:112          1.000000\r
 0:115      Function Call: overloadE(f1[2]; (3-component vector of float)\r
 0:115        'b' (2-element array of float)\r
 0:117      Constant:\r
@@ -190,6 +196,82 @@ ERROR: node is still EOpNull!
 0:118      Function Call: overloadF(i1; (3-component vector of float)\r
 0:118        Constant:\r
 0:118          1 (const int)\r
+0:128  Function Definition: foo2( (void)\r
+0:128    Function Parameters: \r
+0:?     Sequence\r
+0:135      Comma (void)\r
+0:135        Function Call: outFun(f1;vi2;i1;f1; (void)\r
+0:135          Convert int to float (float)\r
+0:135            'i' (int)\r
+0:135          'tempArg' (out 2-component vector of int)\r
+0:135          'i' (int)\r
+0:135          'f' (float)\r
+0:135        move second child to first child (2-component vector of float)\r
+0:135          'v2' (2-component vector of float)\r
+0:135          Convert int to float (2-component vector of float)\r
+0:135            'tempArg' (out 2-component vector of int)\r
+0:136      Comma (int)\r
+0:136        move second child to first child (int)\r
+0:136          'tempReturn' (int)\r
+0:136          Function Call: outFunRet(f1;i1;i1;vi4; (int)\r
+0:136            Convert int to float (float)\r
+0:136              'i' (int)\r
+0:136            'tempArg' (out int)\r
+0:136            'i' (int)\r
+0:136            'tempArg' (out 4-component vector of int)\r
+0:136        move second child to first child (float)\r
+0:136          'f' (float)\r
+0:136          Convert int to float (float)\r
+0:136            'tempArg' (out int)\r
+0:136        move second child to first child (4-component vector of float)\r
+0:136          'v4' (4-component vector of float)\r
+0:136          Convert int to float (4-component vector of float)\r
+0:136            'tempArg' (out 4-component vector of int)\r
+0:136        'tempReturn' (int)\r
+0:137      Sequence\r
+0:137        move second child to first child (float)\r
+0:137          'ret' (float)\r
+0:137          Convert int to float (float)\r
+0:137            Comma (int)\r
+0:137              move second child to first child (int)\r
+0:137                'tempReturn' (int)\r
+0:137                Function Call: outFunRet(f1;i1;i1;vi4; (int)\r
+0:137                  Convert int to float (float)\r
+0:137                    'i' (int)\r
+0:137                  'tempArg' (out int)\r
+0:137                  'i' (int)\r
+0:137                  'tempArg' (out 4-component vector of int)\r
+0:137              move second child to first child (float)\r
+0:137                'f' (float)\r
+0:137                Convert int to float (float)\r
+0:137                  'tempArg' (out int)\r
+0:137              move second child to first child (4-component vector of float)\r
+0:137                'v4' (4-component vector of float)\r
+0:137                Convert int to float (4-component vector of float)\r
+0:137                  'tempArg' (out 4-component vector of int)\r
+0:137              'tempReturn' (int)\r
+0:138      Sequence\r
+0:138        move second child to first child (2-component vector of float)\r
+0:138          'ret2' (2-component vector of float)\r
+0:138          Convert int to float (2-component vector of float)\r
+0:138            Comma (2-component vector of int)\r
+0:138              move second child to first child (2-component vector of int)\r
+0:138                'tempReturn' (2-component vector of int)\r
+0:138                Function Call: outFunRet(f1;vi4;i1;vi4; (2-component vector of int)\r
+0:138                  Convert int to float (float)\r
+0:138                    'i' (int)\r
+0:138                  'tempArg' (out 4-component vector of int)\r
+0:138                  'i' (int)\r
+0:138                  'tempArg' (out 4-component vector of int)\r
+0:138              move second child to first child (4-component vector of float)\r
+0:138                'v4' (4-component vector of float)\r
+0:138                Convert int to float (4-component vector of float)\r
+0:138                  'tempArg' (out 4-component vector of int)\r
+0:138              move second child to first child (4-component vector of float)\r
+0:138                'v4' (4-component vector of float)\r
+0:138                Convert int to float (4-component vector of float)\r
+0:138                  'tempArg' (out 4-component vector of int)\r
+0:138              'tempReturn' (2-component vector of int)\r
 0:?   Linker Objects\r
 0:?     'i' (in 4-component vector of float)\r
 0:?     'o' (smooth out 4-component vector of float)\r
index f164916..5ce38cb 100644 (file)
 ../../LunarGLASS/test/functionSemantics.frag\r
+Warning, version 400 is not yet complete; some version-specific features are present, but many are missing.\r
 \r
 0:? Sequence\r
-0:3  Function Definition: foo(i1;i1;i1;i1;i1;i1; (mediump int)\r
+0:3  Function Definition: foo(i1;i1;i1;i1;i1;i1; (int)\r
 0:3    Function Parameters: \r
-0:3      'a' (in mediump int)\r
-0:3      'b' (const (read only) mediump int)\r
-0:3      'c' (in mediump int)\r
-0:3      'd' (const (read only) mediump int)\r
-0:3      'e' (out mediump int)\r
-0:3      'f' (inout mediump int)\r
+0:3      'a' (in int)\r
+0:3      'b' (const (read only) int)\r
+0:3      'c' (in int)\r
+0:3      'd' (const (read only) int)\r
+0:3      'e' (out int)\r
+0:3      'f' (inout int)\r
 0:5    Sequence\r
 0:5      Sequence\r
-0:5        move second child to first child (mediump int)\r
-0:5          'sum' (mediump int)\r
-0:5          add (mediump int)\r
-0:5            add (mediump int)\r
-0:5              add (mediump int)\r
-0:5                add (mediump int)\r
-0:5                  'a' (in mediump int)\r
-0:5                  'b' (const (read only) mediump int)\r
-0:5                'c' (in mediump int)\r
-0:5              'd' (const (read only) mediump int)\r
-0:5            'f' (inout mediump int)\r
-0:8      multiply second child into first child (mediump int)\r
-0:8        'a' (in mediump int)\r
+0:5        move second child to first child (int)\r
+0:5          'sum' (int)\r
+0:5          add (int)\r
+0:5            add (int)\r
+0:5              add (int)\r
+0:5                add (int)\r
+0:5                  'a' (in int)\r
+0:5                  'b' (const (read only) int)\r
+0:5                'c' (in int)\r
+0:5              'd' (const (read only) int)\r
+0:5            'f' (inout int)\r
+0:8      multiply second child into first child (int)\r
+0:8        'a' (in int)\r
 0:8        Constant:\r
 0:8          64 (const int)\r
-0:10      multiply second child into first child (mediump int)\r
-0:10        'c' (in mediump int)\r
+0:10      multiply second child into first child (int)\r
+0:10        'c' (in int)\r
 0:10        Constant:\r
 0:10          64 (const int)\r
-0:12      move second child to first child (mediump int)\r
-0:12        'e' (out mediump int)\r
+0:12      move second child to first child (int)\r
+0:12        'e' (out int)\r
 0:12        Constant:\r
 0:12          1024 (const int)\r
-0:13      multiply second child into first child (mediump int)\r
-0:13        'f' (inout mediump int)\r
+0:13      multiply second child into first child (int)\r
+0:13        'f' (inout int)\r
 0:13        Constant:\r
 0:13          64 (const int)\r
-0:15      add second child into first child (mediump int)\r
-0:15        'sum' (mediump int)\r
-0:15        add (mediump int)\r
-0:15          add (mediump int)\r
-0:15            add (mediump int)\r
-0:15              add (mediump int)\r
-0:15                add (mediump int)\r
-0:15                  'a' (in mediump int)\r
-0:15                  component-wise multiply (mediump int)\r
+0:15      add second child into first child (int)\r
+0:15        'sum' (int)\r
+0:15        add (int)\r
+0:15          add (int)\r
+0:15            add (int)\r
+0:15              add (int)\r
+0:15                add (int)\r
+0:15                  'a' (in int)\r
+0:15                  component-wise multiply (int)\r
 0:15                    Constant:\r
 0:15                      64 (const int)\r
-0:15                    'b' (const (read only) mediump int)\r
-0:15                'c' (in mediump int)\r
-0:15              component-wise multiply (mediump int)\r
+0:15                    'b' (const (read only) int)\r
+0:15                'c' (in int)\r
+0:15              component-wise multiply (int)\r
 0:15                Constant:\r
 0:15                  64 (const int)\r
-0:15                'd' (const (read only) mediump int)\r
-0:15            'e' (out mediump int)\r
-0:15          'f' (inout mediump int)\r
+0:15                'd' (const (read only) int)\r
+0:15            'e' (out int)\r
+0:15          'f' (inout int)\r
 0:18      Branch: Return with expression\r
-0:18        'sum' (mediump int)\r
-0:21  Function Definition: main( (void)\r
+0:18        'sum' (int)\r
+0:21  Function Definition: foo2(f1;vf3;i1; (int)\r
 0:21    Function Parameters: \r
+0:21      'a' (in float)\r
+0:21      'b' (in 3-component vector of float)\r
+0:21      'r' (out int)\r
+0:23    Sequence\r
+0:23      move second child to first child (int)\r
+0:23        'r' (out int)\r
+0:23        Convert float to int (int)\r
+0:23          component-wise multiply (float)\r
+0:23            Constant:\r
+0:23              3.000000\r
+0:23            'a' (in float)\r
+0:24      Branch: Return with expression\r
+0:24        Convert float to int (int)\r
+0:24          component-wise multiply (float)\r
+0:24            Constant:\r
+0:24              5.000000\r
+0:24            direct index (float)\r
+0:24              'b' (in 3-component vector of float)\r
+0:24              Constant:\r
+0:24                1 (const int)\r
+0:27  Function Definition: main( (void)\r
+0:27    Function Parameters: \r
 0:?     Sequence\r
-0:24      Sequence\r
-0:24        move second child to first child (mediump int)\r
-0:24          't' (mediump int)\r
-0:24          Constant:\r
-0:24            2 (const int)\r
-0:28      move second child to first child (mediump int)\r
-0:28        direct index (mediump int)\r
-0:28          t: direct index for structure (mediump 4-component vector of int)\r
-0:28            'f' (structure{mediump 4-component vector of int t})\r
-0:28            Constant:\r
-0:28              0 (const int)\r
-0:28          Constant:\r
-0:28            1 (const int)\r
-0:28        Constant:\r
-0:28          32 (const int)\r
 0:30      Sequence\r
-0:30        move second child to first child (mediump int)\r
-0:30          'color' (mediump int)\r
-0:30          Function Call: foo(i1;i1;i1;i1;i1;i1; (mediump int)\r
-0:30            Constant:\r
-0:30              1 (const int)\r
-0:30            Constant:\r
-0:30              2 (const int)\r
-0:30            add (mediump int)\r
-0:30              't' (mediump int)\r
-0:30              't' (mediump int)\r
-0:30            Constant:\r
-0:30              8 (const int)\r
-0:30            'e' (mediump int)\r
-0:30            direct index (mediump int)\r
-0:30              t: direct index for structure (mediump 4-component vector of int)\r
-0:30                'f' (structure{mediump 4-component vector of int t})\r
-0:30                Constant:\r
-0:30                  0 (const int)\r
-0:30              Constant:\r
-0:30                1 (const int)\r
-0:32      add second child into first child (mediump int)\r
-0:32        'color' (mediump int)\r
-0:32        component-wise multiply (mediump int)\r
-0:32          Constant:\r
-0:32            128 (const int)\r
-0:32          add (mediump int)\r
-0:32            'e' (mediump int)\r
-0:32            direct index (mediump int)\r
-0:32              t: direct index for structure (mediump 4-component vector of int)\r
-0:32                'f' (structure{mediump 4-component vector of int t})\r
-0:32                Constant:\r
-0:32                  0 (const int)\r
-0:32              Constant:\r
-0:32                1 (const int)\r
-0:35      move second child to first child (mediump 4-component vector of float)\r
-0:35        'gl_FragColor' (fragColor mediump 4-component vector of float)\r
-0:35        Construct vec4 (mediump 4-component vector of float)\r
-0:35          Convert int to float (mediump float)\r
-0:35            'color' (mediump int)\r
+0:30        move second child to first child (int)\r
+0:30          't' (int)\r
+0:30          Constant:\r
+0:30            2 (const int)\r
+0:34      move second child to first child (int)\r
+0:34        direct index (int)\r
+0:34          t: direct index for structure (4-component vector of int)\r
+0:34            'f' (structure{4-component vector of int t})\r
+0:34            Constant:\r
+0:34              0 (const int)\r
+0:34          Constant:\r
+0:34            1 (const int)\r
+0:34        Constant:\r
+0:34          32 (const int)\r
+0:37      Sequence\r
+0:37        move second child to first child (int)\r
+0:37          'color' (int)\r
+0:37          Function Call: foo(i1;i1;i1;i1;i1;i1; (int)\r
+0:37            Constant:\r
+0:37              1 (const int)\r
+0:37            Constant:\r
+0:37              2 (const int)\r
+0:37            add (int)\r
+0:37              't' (int)\r
+0:37              't' (int)\r
+0:37            Constant:\r
+0:37              8 (const int)\r
+0:37            'e' (int)\r
+0:37            direct index (int)\r
+0:37              t: direct index for structure (4-component vector of int)\r
+0:37                'f' (structure{4-component vector of int t})\r
+0:37                Constant:\r
+0:37                  0 (const int)\r
+0:37              Constant:\r
+0:37                1 (const int)\r
+0:39      add second child into first child (int)\r
+0:39        'color' (int)\r
+0:39        component-wise multiply (int)\r
+0:39          Constant:\r
+0:39            128 (const int)\r
+0:39          add (int)\r
+0:39            'e' (int)\r
+0:39            direct index (int)\r
+0:39              t: direct index for structure (4-component vector of int)\r
+0:39                'f' (structure{4-component vector of int t})\r
+0:39                Constant:\r
+0:39                  0 (const int)\r
+0:39              Constant:\r
+0:39                1 (const int)\r
+0:45      move second child to first child (float)\r
+0:45        'ret' (float)\r
+0:45        Convert int to float (float)\r
+0:45          Comma (int)\r
+0:45            move second child to first child (int)\r
+0:45              'tempReturn' (int)\r
+0:45              Function Call: foo2(f1;vf3;i1; (int)\r
+0:45                Constant:\r
+0:45                  4.000000\r
+0:45                Constant:\r
+0:45                  1.000000\r
+0:45                  2.000000\r
+0:45                  3.000000\r
+0:45                'tempArg' (out int)\r
+0:45            move second child to first child (float)\r
+0:45              'arg' (float)\r
+0:45              Convert int to float (float)\r
+0:45                'tempArg' (out int)\r
+0:45            'tempReturn' (int)\r
+0:46      add second child into first child (int)\r
+0:46        'color' (int)\r
+0:46        Convert float to int (int)\r
+0:46          add (float)\r
+0:46            'ret' (float)\r
+0:46            'arg' (float)\r
+0:48      move second child to first child (4-component vector of float)\r
+0:48        'gl_FragColor' (fragColor 4-component vector of float)\r
+0:48        Construct vec4 (4-component vector of float)\r
+0:48          Convert int to float (float)\r
+0:48            'color' (int)\r
 0:?   Linker Objects\r
 \r
 \r
index 93fa11a..1690df8 100644 (file)
@@ -74,8 +74,7 @@ enum TStorageQualifier {
     EvqIn,            // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter
     EvqOut,           // also, for 'out' in the grammar before we know if it's a pipeline output or an 'out' parameter
     EvqInOut,
-
-    EvqConstReadOnly, // read-only types, not having a constant value or constant-value semantics
+    EvqConstReadOnly, // input; also other read-only types having neither a constant value nor constant-value semantics
 
     // built-ins read by vertex shader
     EvqVertexId,
index ff9267c..b6caf50 100644 (file)
@@ -238,9 +238,15 @@ class TQualifier {
 public:
     void clear()
     {
-        storage   = EvqTemporary;
         precision = EpqNone;
         invariant = false;
+        makeTemporary();
+    }
+
+    // drop qualifiers that don't belong in a temporary variable
+    void makeTemporary()
+    {
+        storage   = EvqTemporary;
         centroid  = false;
         smooth    = false;
         flat      = false;
@@ -255,6 +261,7 @@ public:
         writeonly = false;
         clearLayout();
     }
+
     TStorageQualifier   storage   : 6;
     TPrecisionQualifier precision : 3;
     bool invariant : 1;
@@ -314,6 +321,29 @@ public:
         }
     }
 
+    bool isParamInput() const
+    {
+        switch (storage) {
+        case EvqIn:
+        case EvqInOut:
+        case EvqConstReadOnly:
+            return true;
+        default:
+            return false;
+        }
+    }
+
+    bool isParamOutput() const
+    {
+        switch (storage) {
+        case EvqOut:
+        case EvqInOut:
+            return true;
+        default:
+            return false;
+        }
+    }
+
     bool isUniform() const
     {
         switch (storage) {
index 51a9144..66f8891 100644 (file)
@@ -247,7 +247,7 @@ enum TOperator {
     //
 
     EOpConstructGuardStart,
-    EOpConstructInt,
+    EOpConstructInt,          // these first scalar forms also identify what implicit conversion is needed
     EOpConstructUint,
     EOpConstructBool,
     EOpConstructFloat,
index 80c98f1..4224efd 100644 (file)
@@ -67,6 +67,11 @@ TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType
     return node;
 }
 
+TIntermSymbol* TIntermediate::addSymbol(const TVariable& variable, TSourceLoc loc)
+{
+    return addSymbol(variable.getUniqueId(), variable.getName(), variable.getType(), loc);
+}
+
 //
 // Connect two nodes with a new parent that does a binary operation on the nodes.
 //
@@ -363,14 +368,16 @@ TIntermTyped* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator o
 }
 
 //
-// Convert one type to another.
+// Convert the node's type to the given type, as allowed by the operation involved 'op'.
+// For implicit conversions, 'op' is not the requested conversion, it is the explicit 
+// operation requiring the implicit conversion.
 //
 // Returns the node representing the conversion, which could be the same
 // node passed in if no conversion was needed.
 //
 // Return 0 if a conversion can't be done.
 //
-TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node)
+TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) const
 {
     //
     // Does the base type allow operation?
@@ -490,88 +497,86 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt
             return 0;
     }
     
-    if (node->getAsConstantUnion()) {
-
+    if (node->getAsConstantUnion())
         return promoteConstantUnion(promoteTo, node->getAsConstantUnion());
-    } else {    
-        //
-        // Add a new newNode for the conversion.
-        //
-        TIntermUnary* newNode = 0;
 
-        TOperator newOp = EOpNull;
+    //
+    // Add a new newNode for the conversion.
+    //
+    TIntermUnary* newNode = 0;
 
-        // This is 'mechanism' here, it does any conversion told.  The policy comes
-        // from the shader or the above code.
-        switch (promoteTo) {
-        case EbtDouble:
-            //switch (node->getBasicType()) {
-            //case EbtInt:   newOp = EOpConvIntToDouble;   break;
-            //case EbtUint:  newOp = EOpConvUintToDouble;  break;
-            //case EbtBool:  newOp = EOpConvBoolToDouble;  break;
-            //case EbtFloat: newOp = EOpConvFloatToDouble; break;
-            //default:
-                return 0;
-            //}
-            break;
-        case EbtFloat:
-            switch (node->getBasicType()) {
-            case EbtInt:    newOp = EOpConvIntToFloat;  break;
-            case EbtUint:   newOp = EOpConvUintToFloat; break;
-            case EbtBool:   newOp = EOpConvBoolToFloat; break;
-            case EbtDouble: newOp = EOpConvDoubleToFloat; break;
-            default:
-                return 0;
-            }
-            break;
-        case EbtBool:
-            switch (node->getBasicType()) {
-            case EbtInt:    newOp = EOpConvIntToBool;   break;
-            case EbtUint:   newOp = EOpConvUintToBool; break;
-            case EbtFloat:  newOp = EOpConvFloatToBool; break;
-            case EbtDouble: newOp = EOpConvDoubleToBool; break;
-            default:
-                return 0;
-            }
-            break;
-        case EbtInt:
-            switch (node->getBasicType()) {
-            case EbtUint:   newOp = EOpConvUintToInt;  break;
-            case EbtBool:   newOp = EOpConvBoolToInt;  break;
-            case EbtFloat:  newOp = EOpConvFloatToInt; break;
-            case EbtDouble: newOp = EOpConvDoubleToInt; break;
-            default:
-                return 0;
-            }
-            break;
-        case EbtUint:
-            switch (node->getBasicType()) {
-            case EbtInt:    newOp = EOpConvIntToUint;   break;
-            case EbtBool:   newOp = EOpConvBoolToUint;  break;
-            case EbtFloat:  newOp = EOpConvFloatToUint; break;
-            case EbtDouble: newOp = EOpConvDoubleToUint; break;
-            default:
-                return 0;
-            }
-            break;
-        default: 
+    TOperator newOp = EOpNull;
+
+    // This is 'mechanism' here, it does any conversion told.  The policy comes
+    // from the shader or the above code.
+    switch (promoteTo) {
+    case EbtDouble:
+        //switch (node->getBasicType()) {
+        //case EbtInt:   newOp = EOpConvIntToDouble;   break;
+        //case EbtUint:  newOp = EOpConvUintToDouble;  break;
+        //case EbtBool:  newOp = EOpConvBoolToDouble;  break;
+        //case EbtFloat: newOp = EOpConvFloatToDouble; break;
+        //default:
+            return 0;
+        //}
+        break;
+    case EbtFloat:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToFloat;    break;
+        case EbtUint:   newOp = EOpConvUintToFloat;   break;
+        case EbtBool:   newOp = EOpConvBoolToFloat;   break;
+        case EbtDouble: newOp = EOpConvDoubleToFloat; break;
+        default:
+            return 0;
+        }
+        break;
+    case EbtBool:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToBool;    break;
+        case EbtUint:   newOp = EOpConvUintToBool;   break;
+        case EbtFloat:  newOp = EOpConvFloatToBool;  break;
+        case EbtDouble: newOp = EOpConvDoubleToBool; break;
+        default:
+            return 0;
+        }
+        break;
+    case EbtInt:
+        switch (node->getBasicType()) {
+        case EbtUint:   newOp = EOpConvUintToInt;   break;
+        case EbtBool:   newOp = EOpConvBoolToInt;   break;
+        case EbtFloat:  newOp = EOpConvFloatToInt;  break;
+        case EbtDouble: newOp = EOpConvDoubleToInt; break;
+        default:
+            return 0;
+        }
+        break;
+    case EbtUint:
+        switch (node->getBasicType()) {
+        case EbtInt:    newOp = EOpConvIntToUint;    break;
+        case EbtBool:   newOp = EOpConvBoolToUint;   break;
+        case EbtFloat:  newOp = EOpConvFloatToUint;  break;
+        case EbtDouble: newOp = EOpConvDoubleToUint; break;
+        default:
             return 0;
         }
+        break;
+    default: 
+        return 0;
+    }
 
-        TType type(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
-        newNode = new TIntermUnary(newOp, type);
-        newNode->setLoc(node->getLoc());
-        newNode->setOperand(node);
+    TType newType(promoteTo, EvqTemporary, node->getVectorSize(), node->getMatrixCols(), node->getMatrixRows());
+    newNode = new TIntermUnary(newOp, newType);
+    newNode->setLoc(node->getLoc());
+    newNode->setOperand(node);
 
-        return newNode;
-    }
+    return newNode;
 }
 
 //
 // See if the 'from' type is allowed to be implicitly converted to the 
 // 'to' type.  This is not about vector/array/struct, only about basic type.
 //
-bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to)
+bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to) const
 {
     if (profile == EEsProfile || version == 110)
         return false;
@@ -713,8 +718,7 @@ TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, T
         TIntermTyped *commaAggregate = growAggregate(left, right, loc);
         commaAggregate->getAsAggregate()->setOperator(EOpComma);
         commaAggregate->setType(right->getType());
-        commaAggregate->getWritableType().getQualifier().storage = EvqTemporary;
-        commaAggregate->getWritableType().getQualifier().precision = right->getType().getQualifier().precision;
+        commaAggregate->getWritableType().getQualifier().makeTemporary();
 
         return commaAggregate;
     }
@@ -782,7 +786,7 @@ TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* true
 // Returns the constant union node created.
 //
 
-TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, TSourceLoc loc, bool literal)
+TIntermConstantUnion* TIntermediate::addConstantUnion(const TConstUnionArray& unionArray, const TType& t, TSourceLoc loc, bool literal) const
 {
     TIntermConstantUnion* node = new TIntermConstantUnion(unionArray, t);
     node->setLoc(loc);
@@ -1028,7 +1032,7 @@ bool TIntermUnary::promote()
     }
 
     setType(operand->getType());
-    getWritableType().getQualifier().storage = EvqTemporary;
+    getWritableType().getQualifier().makeTemporary();
 
     return true;
 }
@@ -1412,7 +1416,7 @@ void TIntermTyped::propagatePrecision(TPrecisionQualifier newPrecision)
     }
 }
 
-TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) 
+TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) const
 {
     const TConstUnionArray& rightUnionArray = node->getConstArray();
     int size = node->getType().computeNumComponents();
index aff1e62..35a126c 100644 (file)
@@ -381,7 +381,7 @@ TIntermTyped* TParseContext::handleVariable(TSourceLoc loc, TSymbol* symbol, TSt
     if (anon) {
         // it was a member of an anonymous container, have to insert its dereference
         const TVariable* variable = anon->getAnonContainer().getAsVariable();
-        TIntermTyped* container = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
+        TIntermTyped* container = intermediate.addSymbol(*variable, loc);
         TConstUnionArray unionArray(1);
         unionArray[0].setUConst(anon->getMemberNumber());
         TIntermTyped* constNode = intermediate.addConstantUnion(unionArray, TType(EbtUint, EvqConst), loc);
@@ -892,9 +892,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct
 
                 // Add the parameter to the HIL
                 paramNodes = intermediate.growAggregate(paramNodes,
-                                                        intermediate.addSymbol(variable->getUniqueId(),
-                                                                               variable->getName(),
-                                                                               variable->getType(), loc),
+                                                        intermediate.addSymbol(*variable, loc),
                                                         loc);
             }
         } else
@@ -916,13 +914,13 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(TSourceLoc loc, TFunct
 //  - user function
 //  - subroutine call (not implemented yet)
 //
-TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode)
+TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* function, TIntermNode* intermNode)
 {
     TIntermTyped* result = 0;
 
-    TOperator op = fnCall->getBuiltInOp();
+    TOperator op = function->getBuiltInOp();
     if (op == EOpArrayLength)
-        result = handleLengthMethod(loc, fnCall, intermNode);
+        result = handleLengthMethod(loc, function, intermNode);
     else if (op != EOpNull) {
         //
         // Then this should be a constructor.
@@ -930,7 +928,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
         // Their parameters will be verified algorithmically.
         //
         TType type(EbtVoid);  // use this to get the type back
-        if (! constructorError(loc, intermNode, *fnCall, op, type)) {
+        if (! constructorError(loc, intermNode, *function, op, type)) {
             //
             // It's a constructor, of type 'type'.
             //
@@ -944,7 +942,7 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
         //
         const TFunction* fnCandidate;
         bool builtIn;
-        fnCandidate = findFunction(loc, *fnCall, builtIn);
+        fnCandidate = findFunction(loc, *function, builtIn);
         if (fnCandidate) {
             // Error check for function requiring specific extensions present.
             if (builtIn && fnCandidate->getNumExtensions())
@@ -966,30 +964,33 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
             } else {
                 // This is a function call not mapped to built-in operation
                 result = intermediate.setAggregateOperator(intermNode, EOpFunctionCall, fnCandidate->getType(), loc);
-                result->getAsAggregate()->setName(fnCandidate->getMangledName());
+                TIntermAggregate* call = result->getAsAggregate();
+                call->setName(fnCandidate->getMangledName());
 
                 // this is how we know whether the given function is a built-in function or a user-defined function
                 // if builtIn == false, it's a userDefined -> could be an overloaded built-in function also
                 // if builtIn == true, it's definitely a built-in function with EOpNull
                 if (! builtIn) {
-                    result->getAsAggregate()->setUserDefined();
+                    call->setUserDefined();
                     intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName());
                 }
 
                 // Make sure storage qualifications work for these arguments.
                 TStorageQualifier qual;
-                TQualifierList& qualifierList = result->getAsAggregate()->getQualifierList();
+                TQualifierList& qualifierList = call->getQualifierList();
                 for (int i = 0; i < fnCandidate->getParamCount(); ++i) {
                     qual = (*fnCandidate)[i].type->getQualifier().storage;
                     if (qual == EvqOut || qual == EvqInOut) {
-                        if (lValueErrorCheck(result->getLoc(), "assign", result->getAsAggregate()->getSequence()[i]->getAsTyped()))
+                        if (lValueErrorCheck(call->getLoc(), "assign", call->getSequence()[i]->getAsTyped()))
                             error(intermNode->getLoc(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", "");
                     }
                     qualifierList.push_back(qual);
                 }
 
+                result = handleArgumentConversions(*fnCandidate, *call);
+
                 if (builtIn)
-                    nonOpBuiltInCheck(loc, *fnCandidate, *result->getAsAggregate());
+                    nonOpBuiltInCheck(loc, *fnCandidate, *call);
             }
         }
     }
@@ -1007,14 +1008,14 @@ TIntermTyped* TParseContext::handleFunctionCall(TSourceLoc loc, TFunction* fnCal
 
 // Do all processing handling object.length().
 // Return resulting tree node.
-TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* fnCall, TIntermNode* intermNode)
+TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* function, TIntermNode* intermNode)
 {
     int length = 0;
 
-    if (fnCall->getParamCount() > 0)
-        error(loc, "method does not accept any arguments", fnCall->getName().c_str(), "");
+    if (function->getParamCount() > 0)
+        error(loc, "method does not accept any arguments", function->getName().c_str(), "");
     if (intermNode->getAsTyped() == 0 || ! intermNode->getAsTyped()->getType().isArray())
-        error(loc, "", fnCall->getName().c_str(), "can only be applied to an array");
+        error(loc, "", function->getName().c_str(), "can only be applied to an array");
     else if (intermNode->getAsTyped()->getType().getArraySize() == 0) {
         bool implicitlySized = false;
         if (intermNode->getAsSymbolNode() && isIoResizeArray(intermNode->getAsTyped()->getType())) {
@@ -1028,9 +1029,9 @@ TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* fnCal
         }
         if (length == 0) {
             if (intermNode->getAsSymbolNode() && isIoResizeArray(intermNode->getAsTyped()->getType()))
-                error(loc, "", fnCall->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
+                error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier");
             else
-                error(loc, "", fnCall->getName().c_str(), "array must be declared with a size before using this method");
+                error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method");
         }
     } else
         length = intermNode->getAsTyped()->getType().getArraySize();
@@ -1042,6 +1043,86 @@ TIntermTyped* TParseContext::handleLengthMethod(TSourceLoc loc, TFunction* fnCal
 
     return intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), loc);
 }
+
+//
+// Add any needed implicit conversions for function-call arguments.  This is 
+// straightforward for input parameters, but output parameters need to 
+// a different tree topology, complicated further by whether the function
+// has a return value.  Create the new subtree, as neeeded.
+//
+// Returns a node of a subtree that evaluates to the return value of the function.
+//
+TIntermTyped* TParseContext::handleArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const
+{
+    TIntermSequence& arguments = intermNode.getSequence();
+
+    // Will there be any output conversions?
+    bool outputConversions = false;
+    for (int i = 0; i < function.getParamCount(); ++i) {
+        if (*function[i].type != arguments[i]->getAsTyped()->getType() && function[i].type->getQualifier().storage == EvqOut) {
+            outputConversions = true;
+            break;
+        }
+    }
+
+    // Setup for the new tree, if needed:
+    //
+    // Output conversions need a different tree topology.
+    // Out-qualified arguments need a temporary of the correct type, with the call
+    // followed by an assignment of the temporary to the original argument:
+    //     void: function(arg, ...)  ->        (          function(tempArg, ...), arg = tempArg, ...)
+    //     ret = function(arg, ...)  ->  ret = (tempRet = function(tempArg, ...), arg = tempArg, ..., tempRet)
+    // Where the "tempArg" type needs no conversion as an argument, but will convert on assignment.
+    TIntermTyped* conversionTree = 0;
+    TVariable* tempRet = 0;
+    if (outputConversions) {
+        if (intermNode.getBasicType() != EbtVoid) {
+            // do the "tempRet = function(...), " bit from above
+            tempRet = makeInternalVariable("tempReturn", intermNode.getType());
+            TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
+            conversionTree = intermediate.addAssign(EOpAssign, tempRetNode, &intermNode, intermNode.getLoc());
+        } else
+            conversionTree = &intermNode;
+
+        conversionTree = intermediate.makeAggregate(conversionTree);
+    }
+
+    // Process each argument's conversion
+    for (int i = 0; i < function.getParamCount(); ++i) {
+        if (*function[i].type != arguments[i]->getAsTyped()->getType()) {
+            if (function[i].type->getQualifier().isParamInput()) {
+                // In-qualified arguments just need an extra node added above the argument to
+                // convert to the correct type.
+                arguments[i] = intermediate.addConversion(EOpAssign, *function[i].type, arguments[i]->getAsTyped());
+            } else if (function[i].type->getQualifier().isParamOutput()) {
+                // Out-qualified arguments need to use the topology set up above.
+                // do the " ...(tempArg, ...), arg = tempArg" bit from above
+                TVariable* tempArg = makeInternalVariable("tempArg", *function[i].type);
+                tempArg->getWritableType().getQualifier().makeTemporary();
+                TIntermSymbol* tempArgNode = intermediate.addSymbol(*tempArg, intermNode.getLoc());
+                TIntermTyped* tempAssign = intermediate.addAssign(EOpAssign, arguments[i]->getAsTyped(), tempArgNode, arguments[i]->getLoc());
+                conversionTree = intermediate.growAggregate(conversionTree, tempAssign, arguments[i]->getLoc());
+                // replace the argument with another node for the same tempArg variable
+                arguments[i] = intermediate.addSymbol(*tempArg, intermNode.getLoc());
+            }
+        }
+    }
+
+    // Done if no output conversions
+    if (! outputConversions)
+        return &intermNode;
+
+    // Otherwise, finalize the tree topology (see bigger comment above).
+    if (tempRet) {
+        // do the "..., tempRet" bit from above
+        TIntermSymbol* tempRetNode = intermediate.addSymbol(*tempRet, intermNode.getLoc());
+        conversionTree = intermediate.growAggregate(conversionTree, tempRetNode, intermNode.getLoc());
+    }
+    conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc());
+
+    return conversionTree;
+}
+
 //
 // Do additional checking of built-in function calls that were not mapped
 // to built-in operations (e.g., texturing functions).
@@ -1136,12 +1217,12 @@ void TParseContext::nonOpBuiltInCheck(TSourceLoc loc, const TFunction& fnCandida
 }
 
 //
-// Handle seeing a built-in-type constructor call in the grammar.
+// Handle seeing a built-in constructor in a grammar production.
 //
-TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, TPublicType& publicType)
+TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, const TPublicType& publicType)
 {
-    publicType.qualifier.precision = EpqNone;
     TType type(publicType);
+    type.getQualifier().precision = EpqNone;
 
     if (type.isArray()) {
         profileRequires(loc, ENoProfile, 120, GL_3DL_array_objects, "arrayed constructor");
@@ -1151,10 +1232,9 @@ TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, TPublicType& pub
     TOperator op = mapTypeToConstructorOp(type);
 
     if (op == EOpNull) {
-        error(loc, "cannot construct this type", TType::getBasicString(publicType.basicType), "");
+        error(loc, "cannot construct this type", type.getBasicString(), "");
         op = EOpConstructFloat;
-        publicType.basicType = EbtFloat;
-        TType errorType(publicType);
+        TType errorType(EbtFloat);
         type.shallowCopy(errorType);
     }
 
@@ -1164,9 +1244,9 @@ TFunction* TParseContext::handleConstructorCall(TSourceLoc loc, TPublicType& pub
 }
 
 //
-// Given a type, find what operation would construct it.
+// Given a type, find what operation would fully construct it.
 //
-TOperator TParseContext::mapTypeToConstructorOp(const TType& type)
+TOperator TParseContext::mapTypeToConstructorOp(const TType& type) const
 {
     if (type.isStruct())
         return EOpConstructStruct;
@@ -1335,9 +1415,7 @@ void TParseContext::variableCheck(TIntermTyped*& nodePtr)
         symbolTable.insert(*fakeVariable);
 
         // substitute a symbol node for this new variable
-        nodePtr = intermediate.addSymbol(fakeVariable->getUniqueId(),
-                                         fakeVariable->getName(),
-                                         fakeVariable->getType(), symbol->getLoc());
+        nodePtr = intermediate.addSymbol(*fakeVariable, symbol->getLoc());
     } else {
         switch (symbol->getQualifier().storage) {
         case EvqPointCoord:
@@ -3340,12 +3418,11 @@ const TFunction* TParseContext::findFunction120(TSourceLoc loc, const TFunction&
                 possibleMatch = false;
             else {
                 // do direction-specific checks for conversion of basic type
-                TStorageQualifier qualifier = function[i].type->getQualifier().storage;
-                if (qualifier == EvqIn || qualifier == EvqInOut) {
+                if (function[i].type->getQualifier().isParamInput()) {
                     if (! intermediate.canImplicitlyPromote(call[i].type->getBasicType(), function[i].type->getBasicType()))
                         possibleMatch = false;
                 }
-                if (qualifier == EvqOut || qualifier == EvqInOut) {
+                if (function[i].type->getQualifier().isParamOutput()) {
                     if (! intermediate.canImplicitlyPromote(function[i].type->getBasicType(), call[i].type->getBasicType()))
                         possibleMatch = false;
                 }
@@ -3472,6 +3549,22 @@ void TParseContext::inheritGlobalDefaults(TQualifier& dst) const
 }
 
 //
+// Make an internal-only variable whose name is for debug purposes only
+// and won't be searched for.  Callers will only use the return value to use
+// the variable, not the name to look it up.  It is okay if the name
+// is the same as other names; there won't be any conflict.
+//
+TVariable* TParseContext::makeInternalVariable(const char* name, const TType& type) const
+{
+    TString* nameString = new TString(name);
+    TSourceLoc loc = {0, 0};
+    TVariable* variable = new TVariable(nameString, type);
+    symbolTable.makeInternalVariable(*variable);
+
+    return variable;
+}
+
+//
 // Declare a non-array variable, the main point being there is no redeclaration
 // for resizing allowed.
 //
@@ -3569,7 +3662,7 @@ TIntermNode* TParseContext::executeInitializer(TSourceLoc loc, TString& identifi
         variable->setConstArray(initializer->getAsConstantUnion()->getConstArray());
     } else {
         // normal assigning of a value to a variable...
-        TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), loc);
+        TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc);
         TIntermNode* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc);
         if (! initNode)
             assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString());
index 71338a5..f4a89ae 100644 (file)
@@ -98,8 +98,9 @@ public:
     TIntermAggregate* handleFunctionDefinition(TSourceLoc, TFunction&);
     TIntermTyped* handleFunctionCall(TSourceLoc, TFunction*, TIntermNode*);
     TIntermTyped* handleLengthMethod(TSourceLoc, TFunction*, TIntermNode*);
+    TIntermTyped* handleArgumentConversions(const TFunction&, TIntermAggregate&) const;
     void nonOpBuiltInCheck(TSourceLoc, const TFunction&, TIntermAggregate&);
-    TFunction* handleConstructorCall(TSourceLoc, TPublicType&);
+    TFunction* handleConstructorCall(TSourceLoc, const TPublicType&);
 
     bool parseVectorFields(TSourceLoc, const TString&, int vecSize, TVectorFields&);
     void assignError(TSourceLoc, const char* op, TString left, TString right);
@@ -205,11 +206,12 @@ public:
 protected:
     void nonInitConstCheck(TSourceLoc, TString& identifier, TType& type);
        void inheritGlobalDefaults(TQualifier& dst) const;
+    TVariable* makeInternalVariable(const char* name, const TType&) const;
     TVariable* declareNonArray(TSourceLoc, TString& identifier, TType&, bool& newDeclaration);
     void declareArray(TSourceLoc, TString& identifier, const TType&, TSymbol*&, bool& newDeclaration);
     TIntermNode* executeInitializer(TSourceLoc, TString& identifier, TIntermTyped* initializer, TVariable* variable);
     TIntermTyped* convertInitializerList(TSourceLoc, const TType&, TIntermTyped* initializer);
-    TOperator mapTypeToConstructorOp(const TType&);
+    TOperator mapTypeToConstructorOp(const TType&) const;
     void finalErrorCheck();
 
 public:
index fd19c69..7d9afaf 100644 (file)
@@ -502,6 +502,12 @@ public:
         table.pop_back();
     }
 
+    //
+    // Insert a visible symbol into the symbol table so it can
+    // be found later by name.
+    //
+    // Returns false if the was a name collision.
+    //
     bool insert(TSymbol& symbol)
     {
         symbol.setUniqueId(++uniqueId);
@@ -524,6 +530,17 @@ public:
     }
 
     //
+    // To allocate an internal temporary, which will need to be uniquely
+    // identified by the consumer of the AST, but never need to 
+    // found by doing a symbol table search by name, hence allowed an
+    // arbitrary name in the symbol with no worry of collision.
+    //
+    void makeInternalVariable(TSymbol& symbol)
+    {
+        symbol.setUniqueId(++uniqueId);
+    }
+
+    //
     // Copy a variable or anonymous member's structure from a shared level up 
     // to the current level, so it can be modified without impacting other users 
     // of the shared table.
index 9bb1709..7c91686 100644 (file)
@@ -102,6 +102,7 @@ struct TXfbBuffer {
 
 class TSymbolTable;
 class TSymbol;
+class TVariable;
 
 //
 // Set of helper functions to help parse and build the tree.
@@ -133,13 +134,14 @@ public:
     bool isRecursive() const { return recursive; }
     
     TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc);
-    TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*);
+    TIntermSymbol* addSymbol(const TVariable&, TSourceLoc);
+    TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*) const;
     TIntermTyped* addBinaryMath(TOperator, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
     TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc);
     TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc);
     TIntermTyped* addUnaryMath(TOperator, TIntermNode* child, TSourceLoc);
     TIntermTyped* addBuiltInFunctionCall(TSourceLoc line, TOperator, bool unary, TIntermNode*, const TType& returnType);
-    bool canImplicitlyPromote(TBasicType from, TBasicType to);
+    bool canImplicitlyPromote(TBasicType from, TBasicType to) const;
     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right);
     TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc);
     TIntermAggregate* makeAggregate(TIntermNode* node);
@@ -150,8 +152,8 @@ public:
     TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc);
     TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc);
     TIntermTyped* addMethod(TIntermTyped*, const TType&, const TString*, TSourceLoc);
-    TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, TSourceLoc, bool literal = false);
-    TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ;
+    TIntermConstantUnion* addConstantUnion(const TConstUnionArray&, const TType&, TSourceLoc, bool literal = false) const;
+    TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) const;
     bool parseConstTree(TIntermNode*, TConstUnionArray, TOperator, const TType&, bool singleConstantParam = false);
     TIntermLoop* addLoop(TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc);
     TIntermBranch* addBranch(TOperator, TSourceLoc);