glsl: Don't allow vertex shader input arrays until GLSL 1.50.
[mesa.git] / src / glsl / glsl_parser.yy
index 1851f1e202e298ad1bf7a4a8e0d1a7d7d28a28b8..78f5bf6f4f2038e318e09f2b27a9c4713136b278 100644 (file)
 #include "ast.h"
 #include "glsl_parser_extras.h"
 #include "glsl_types.h"
+#include "main/context.h"
 
 #define YYLEX_PARAM state->scanner
 
+#undef yyerror
+
+static void yyerror(YYLTYPE *loc, _mesa_glsl_parse_state *st, const char *msg)
+{
+   _mesa_glsl_error(loc, st, "%s", msg);
+}
 %}
 
 %pure-parser
@@ -52,7 +59,7 @@
 %union {
    int n;
    float real;
-   char *identifier;
+   const char *identifier;
 
    struct ast_type_qualifier type_qualifier;
 
    ast_declarator_list *declarator_list;
    ast_struct_specifier *struct_specifier;
    ast_declaration *declaration;
+   ast_switch_body *switch_body;
+   ast_case_label *case_label;
+   ast_case_label_list *case_label_list;
+   ast_case_statement *case_statement;
+   ast_case_statement_list *case_statement_list;
+   ast_interface_block *interface_block;
 
    struct {
       ast_node *cond;
 %token MAT4X2 MAT4X3 MAT4X4
 %token SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW
 %token SAMPLERCUBESHADOW SAMPLER1DARRAY SAMPLER2DARRAY SAMPLER1DARRAYSHADOW
-%token SAMPLER2DARRAYSHADOW ISAMPLER1D ISAMPLER2D ISAMPLER3D ISAMPLERCUBE
-%token ISAMPLER1DARRAY ISAMPLER2DARRAY USAMPLER1D USAMPLER2D USAMPLER3D
-%token USAMPLERCUBE USAMPLER1DARRAY USAMPLER2DARRAY
+%token SAMPLER2DARRAYSHADOW SAMPLERCUBEARRAY SAMPLERCUBEARRAYSHADOW
+%token ISAMPLER1D ISAMPLER2D ISAMPLER3D ISAMPLERCUBE
+%token ISAMPLER1DARRAY ISAMPLER2DARRAY ISAMPLERCUBEARRAY
+%token USAMPLER1D USAMPLER2D USAMPLER3D USAMPLERCUBE USAMPLER1DARRAY
+%token USAMPLER2DARRAY USAMPLERCUBEARRAY
+%token SAMPLER2DRECT ISAMPLER2DRECT USAMPLER2DRECT SAMPLER2DRECTSHADOW
+%token SAMPLERBUFFER ISAMPLERBUFFER USAMPLERBUFFER
+%token SAMPLER2DMS ISAMPLER2DMS USAMPLER2DMS
+%token SAMPLER2DMSARRAY ISAMPLER2DMSARRAY USAMPLER2DMSARRAY
+%token SAMPLEREXTERNALOES
 %token STRUCT VOID_TOK WHILE
 %token <identifier> IDENTIFIER TYPE_IDENTIFIER NEW_IDENTIFIER
 %type <identifier> any_identifier
+%type <interface_block> instance_name_opt
 %token <real> FLOATCONSTANT
 %token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
 %token <identifier> FIELD_SELECTION
 %token INVARIANT
 %token LOWP MEDIUMP HIGHP SUPERP PRECISION
 
-%token VERSION EXTENSION LINE COLON EOL INTERFACE OUTPUT
+%token VERSION_TOK EXTENSION LINE COLON EOL INTERFACE OUTPUT
 %token PRAGMA_DEBUG_ON PRAGMA_DEBUG_OFF
 %token PRAGMA_OPTIMIZE_ON PRAGMA_OPTIMIZE_OFF
 %token PRAGMA_INVARIANT_ALL
 %token INLINE_TOK NOINLINE VOLATILE PUBLIC_TOK STATIC EXTERN EXTERNAL
 %token LONG_TOK SHORT_TOK DOUBLE_TOK HALF FIXED_TOK UNSIGNED INPUT_TOK OUPTUT
 %token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4
-%token SAMPLER2DRECT SAMPLER3DRECT SAMPLER2DRECTSHADOW
+%token SAMPLER3DRECT
 %token SIZEOF CAST NAMESPACE USING
+%token COHERENT RESTRICT READONLY WRITEONLY RESOURCE ATOMIC_UINT PATCH SAMPLE
+%token SUBROUTINE
 
 %token ERROR_TOK
 
-%token COMMON PARTITION ACTIVE SAMPLERBUFFER FILTER
+%token COMMON PARTITION ACTIVE FILTER
 %token  IMAGE1D  IMAGE2D  IMAGE3D  IMAGECUBE  IMAGE1DARRAY  IMAGE2DARRAY
 %token IIMAGE1D IIMAGE2D IIMAGE3D IIMAGECUBE IIMAGE1DARRAY IIMAGE2DARRAY
 %token UIMAGE1D UIMAGE2D UIMAGE3D UIMAGECUBE UIMAGE1DARRAY UIMAGE2DARRAY
 %type <type_qualifier> interpolation_qualifier
 %type <type_qualifier> layout_qualifier
 %type <type_qualifier> layout_qualifier_id_list layout_qualifier_id
+%type <type_qualifier> interface_block_layout_qualifier
+%type <type_qualifier> interface_qualifier
 %type <type_specifier> type_specifier
 %type <type_specifier> type_specifier_no_prec
 %type <type_specifier> type_specifier_nonarray
-%type <n> basic_type_specifier_nonarray
+%type <identifier> basic_type_specifier_nonarray
 %type <fully_specified_type> fully_specified_type
 %type <function> function_prototype
 %type <function> function_header
 %type <declarator_list> init_declarator_list
 %type <declarator_list> single_declaration
 %type <expression> initializer
+%type <expression> initializer_list
 %type <node> declaration
 %type <node> declaration_statement
 %type <node> jump_statement
+%type <node> interface_block
+%type <interface_block> basic_interface_block
 %type <struct_specifier> struct_specifier
-%type <node> struct_declaration_list
+%type <declarator_list> struct_declaration_list
 %type <declarator_list> struct_declaration
 %type <declaration> struct_declarator
 %type <declaration> struct_declarator_list
+%type <declarator_list> member_list
+%type <declarator_list> member_declaration
 %type <node> selection_statement
 %type <selection_rest_statement> selection_rest_statement
+%type <node> switch_statement
+%type <switch_body> switch_body
+%type <case_label_list> case_label_list
+%type <case_label> case_label
+%type <case_statement> case_statement
+%type <case_statement_list> case_statement_list
 %type <node> iteration_statement
 %type <node> condition
 %type <node> conditionopt
 %type <node> for_init_statement
 %type <for_rest_statement> for_rest_statement
+%type <n> integer_constant
 %%
 
 translation_unit: 
@@ -228,43 +265,20 @@ translation_unit:
 
 version_statement:
        /* blank - no #version specified: defaults are already set */
-       | VERSION INTCONSTANT EOL
-       {
-          bool supported = false;
-
-          switch ($2) {
-          case 100:
-             state->es_shader = true;
-             supported = state->Const.GLSL_100ES;
-             break;
-          case 110:
-             supported = state->Const.GLSL_110;
-             break;
-          case 120:
-             supported = state->Const.GLSL_120;
-             break;
-          case 130:
-             supported = state->Const.GLSL_130;
-             break;
-          default:
-             supported = false;
-             break;
-          }
-
-          state->language_version = $2;
-          state->version_string =
-             ralloc_asprintf(state, "GLSL%s %d.%02d",
-                             state->es_shader ? " ES" : "",
-                             state->language_version / 100,
-                             state->language_version % 100);
-
-          if (!supported) {
-             _mesa_glsl_error(& @2, state, "%s is not supported. "
-                              "Supported versions are: %s\n",
-                              state->version_string,
-                              state->supported_version_string);
+       | VERSION_TOK INTCONSTANT EOL
+       {
+           state->process_version_directive(&@2, $2, NULL);
+          if (state->error) {
+             YYERROR;
           }
        }
+        | VERSION_TOK INTCONSTANT any_identifier EOL
+        {
+           state->process_version_directive(&@2, $2, $3);
+          if (state->error) {
+             YYERROR;
+          }
+        }
        ;
 
 pragma_statement:
@@ -274,10 +288,11 @@ pragma_statement:
        | PRAGMA_OPTIMIZE_OFF EOL
        | PRAGMA_INVARIANT_ALL EOL
        {
-          if (state->language_version < 120) {
+          if (!state->is_version(120, 100)) {
              _mesa_glsl_warning(& @1, state,
-                                "pragma `invariant(all)' not supported in %s",
-                                state->version_string);
+                                "pragma `invariant(all)' not supported in %s "
+                                 "(GLSL ES 1.00 or GLSL 1.20 required).",
+                                state->get_version_string());
           } else {
              state->all_invariant = true;
           }
@@ -777,6 +792,10 @@ declaration:
           $3->is_precision_statement = true;
           $$ = $3;
        }
+       | interface_block
+       {
+          $$ = $1;
+       }
        ;
 
 function_prototype:
@@ -943,6 +962,11 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
           state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+          if ($7->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, NULL);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | init_declarator_list ',' any_identifier '[' constant_expression ']' '=' initializer
        {
@@ -953,6 +977,11 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
           state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+          if ($8->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$8;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->type->specifier, true, $5);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | init_declarator_list ',' any_identifier '=' initializer
        {
@@ -963,6 +992,10 @@ init_declarator_list:
           $$ = $1;
           $$->declarations.push_tail(&decl->link);
           state->symbols->add_variable(new(state) ir_variable(NULL, $3, ir_var_auto));
+          if ($5->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$5;
+             _mesa_ast_set_aggregate_type($1->type->specifier, ai, state);
+          }
        }
        ;
 
@@ -1010,6 +1043,11 @@ single_declaration:
           $$ = new(ctx) ast_declarator_list($1);
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
+          if ($6->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$6;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, NULL);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | fully_specified_type any_identifier '[' constant_expression ']' '=' initializer
        {
@@ -1019,6 +1057,11 @@ single_declaration:
           $$ = new(ctx) ast_declarator_list($1);
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
+          if ($7->oper == ast_aggregate) {
+             ast_aggregate_initializer *ai = (ast_aggregate_initializer *)$7;
+             ast_type_specifier *type = new(ctx) ast_type_specifier($1->specifier, true, $4);
+             _mesa_ast_set_aggregate_type(type, ai, state);
+          }
        }
        | fully_specified_type any_identifier '=' initializer
        {
@@ -1028,6 +1071,9 @@ single_declaration:
           $$ = new(ctx) ast_declarator_list($1);
           $$->set_location(yylloc);
           $$->declarations.push_tail(&decl->link);
+          if ($4->oper == ast_aggregate) {
+              _mesa_ast_set_aggregate_type($1->specifier, $4, state);
+          }
        }
        | INVARIANT variable_identifier // Vertex only.
        {
@@ -1071,88 +1117,101 @@ layout_qualifier_id_list:
        layout_qualifier_id
        | layout_qualifier_id_list ',' layout_qualifier_id
        {
-          if (($1.flags.i & $3.flags.i) != 0) {
-             _mesa_glsl_error(& @3, state,
-                              "duplicate layout qualifiers used\n");
+          $$ = $1;
+          if (!$$.merge_qualifier(& @3, state, $3)) {
              YYERROR;
           }
-
-          $$.flags.i = $1.flags.i | $3.flags.i;
-
-          if ($1.flags.q.explicit_location)
-             $$.location = $1.location;
-
-          if ($3.flags.q.explicit_location)
-             $$.location = $3.location;
        }
        ;
 
+integer_constant:
+       INTCONSTANT { $$ = $1; }
+       | UINTCONSTANT { $$ = $1; }
+       ;
+
 layout_qualifier_id:
        any_identifier
        {
-          bool got_one = false;
-
           memset(& $$, 0, sizeof($$));
 
           /* Layout qualifiers for ARB_fragment_coord_conventions. */
-          if (!got_one && state->ARB_fragment_coord_conventions_enable) {
+          if (!$$.flags.i && state->ARB_fragment_coord_conventions_enable) {
              if (strcmp($1, "origin_upper_left") == 0) {
-                got_one = true;
                 $$.flags.q.origin_upper_left = 1;
              } else if (strcmp($1, "pixel_center_integer") == 0) {
-                got_one = true;
                 $$.flags.q.pixel_center_integer = 1;
              }
 
-             if (got_one && state->ARB_fragment_coord_conventions_warn) {
+             if ($$.flags.i && state->ARB_fragment_coord_conventions_warn) {
                 _mesa_glsl_warning(& @1, state,
                                    "GL_ARB_fragment_coord_conventions layout "
                                    "identifier `%s' used\n", $1);
              }
           }
 
-          /* Layout qualifiers for AMD_conservative_depth. */
-          if (!got_one && state->AMD_conservative_depth_enable) {
+          /* Layout qualifiers for AMD/ARB_conservative_depth. */
+          if (!$$.flags.i &&
+              (state->AMD_conservative_depth_enable ||
+               state->ARB_conservative_depth_enable)) {
              if (strcmp($1, "depth_any") == 0) {
-                got_one = true;
                 $$.flags.q.depth_any = 1;
              } else if (strcmp($1, "depth_greater") == 0) {
-                got_one = true;
                 $$.flags.q.depth_greater = 1;
              } else if (strcmp($1, "depth_less") == 0) {
-                got_one = true;
                 $$.flags.q.depth_less = 1;
              } else if (strcmp($1, "depth_unchanged") == 0) {
-                got_one = true;
                 $$.flags.q.depth_unchanged = 1;
              }
        
-             if (got_one && state->AMD_conservative_depth_warn) {
+             if ($$.flags.i && state->AMD_conservative_depth_warn) {
                 _mesa_glsl_warning(& @1, state,
                                    "GL_AMD_conservative_depth "
                                    "layout qualifier `%s' is used\n", $1);
              }
+             if ($$.flags.i && state->ARB_conservative_depth_warn) {
+                _mesa_glsl_warning(& @1, state,
+                                   "GL_ARB_conservative_depth "
+                                   "layout qualifier `%s' is used\n", $1);
+             }
           }
 
-          if (!got_one) {
+          /* See also interface_block_layout_qualifier. */
+          if (!$$.flags.i && state->ARB_uniform_buffer_object_enable) {
+             if (strcmp($1, "std140") == 0) {
+                $$.flags.q.std140 = 1;
+             } else if (strcmp($1, "shared") == 0) {
+                $$.flags.q.shared = 1;
+             } else if (strcmp($1, "column_major") == 0) {
+                $$.flags.q.column_major = 1;
+             /* "row_major" is a reserved word in GLSL 1.30+. Its token is parsed
+              * below in the interface_block_layout_qualifier rule.
+              *
+              * It is not a reserved word in GLSL ES 3.00, so it's handled here as
+              * an identifier.
+              */
+             } else if (strcmp($1, "row_major") == 0) {
+                $$.flags.q.row_major = 1;
+             }
+
+             if ($$.flags.i && state->ARB_uniform_buffer_object_warn) {
+                _mesa_glsl_warning(& @1, state,
+                                   "#version 140 / GL_ARB_uniform_buffer_object "
+                                   "layout qualifier `%s' is used\n", $1);
+             }
+          }
+
+          if (!$$.flags.i) {
              _mesa_glsl_error(& @1, state, "unrecognized layout identifier "
                               "`%s'\n", $1);
              YYERROR;
           }
        }
-       | any_identifier '=' INTCONSTANT
+       | any_identifier '=' integer_constant
        {
-          bool got_one = false;
-
           memset(& $$, 0, sizeof($$));
 
           if (state->ARB_explicit_attrib_location_enable) {
-             /* FINISHME: Handle 'index' once GL_ARB_blend_func_exteneded and
-              * FINISHME: GLSL 1.30 (or later) are supported.
-              */
              if (strcmp("location", $1) == 0) {
-                got_one = true;
-
                 $$.flags.q.explicit_location = 1;
 
                 if ($3 >= 0) {
@@ -1163,12 +1222,24 @@ layout_qualifier_id:
                    YYERROR;
                 }
              }
+
+             if (strcmp("index", $1) == 0) {
+                $$.flags.q.explicit_index = 1;
+
+                if ($3 >= 0) {
+                   $$.index = $3;
+                } else {
+                   _mesa_glsl_error(& @3, state,
+                                    "invalid index %d specified\n", $3);
+                    YYERROR;
+                 }
+              }
           }
 
           /* If the identifier didn't match any known layout identifiers,
            * emit an error.
            */
-          if (!got_one) {
+          if (!$$.flags.i) {
              _mesa_glsl_error(& @1, state, "unrecognized layout identifier "
                               "`%s'\n", $1);
              YYERROR;
@@ -1178,6 +1249,38 @@ layout_qualifier_id:
                                 "identifier `%s' used\n", $1);
           }
        }
+       | interface_block_layout_qualifier
+       {
+          $$ = $1;
+          /* Layout qualifiers for ARB_uniform_buffer_object. */
+          if ($$.flags.q.uniform && !state->ARB_uniform_buffer_object_enable) {
+             _mesa_glsl_error(& @1, state,
+                              "#version 140 / GL_ARB_uniform_buffer_object "
+                              "layout qualifier `%s' is used\n", $1);
+          } else if ($$.flags.q.uniform && state->ARB_uniform_buffer_object_warn) {
+             _mesa_glsl_warning(& @1, state,
+                                "#version 140 / GL_ARB_uniform_buffer_object "
+                                "layout qualifier `%s' is used\n", $1);
+          }
+       }
+       ;
+
+/* This is a separate language rule because we parse these as tokens
+ * (due to them being reserved keywords) instead of identifiers like
+ * most qualifiers.  See the any_identifier path of
+ * layout_qualifier_id for the others.
+ */
+interface_block_layout_qualifier:
+       ROW_MAJOR
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.row_major = 1;
+       }
+       | PACKED_TOK
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.packed = 1;
+       }
        ;
 
 interpolation_qualifier:
@@ -1337,87 +1440,88 @@ type_specifier_nonarray:
        ;
 
 basic_type_specifier_nonarray:
-       VOID_TOK                { $$ = ast_void; }
-       | FLOAT_TOK             { $$ = ast_float; }
-       | INT_TOK               { $$ = ast_int; }
-       | UINT_TOK              { $$ = ast_uint; }
-       | BOOL_TOK              { $$ = ast_bool; }
-       | VEC2                  { $$ = ast_vec2; }
-       | VEC3                  { $$ = ast_vec3; }
-       | VEC4                  { $$ = ast_vec4; }
-       | BVEC2                 { $$ = ast_bvec2; }
-       | BVEC3                 { $$ = ast_bvec3; }
-       | BVEC4                 { $$ = ast_bvec4; }
-       | IVEC2                 { $$ = ast_ivec2; }
-       | IVEC3                 { $$ = ast_ivec3; }
-       | IVEC4                 { $$ = ast_ivec4; }
-       | UVEC2                 { $$ = ast_uvec2; }
-       | UVEC3                 { $$ = ast_uvec3; }
-       | UVEC4                 { $$ = ast_uvec4; }
-       | MAT2X2                { $$ = ast_mat2; }
-       | MAT2X3                { $$ = ast_mat2x3; }
-       | MAT2X4                { $$ = ast_mat2x4; }
-       | MAT3X2                { $$ = ast_mat3x2; }
-       | MAT3X3                { $$ = ast_mat3; }
-       | MAT3X4                { $$ = ast_mat3x4; }
-       | MAT4X2                { $$ = ast_mat4x2; }
-       | MAT4X3                { $$ = ast_mat4x3; }
-       | MAT4X4                { $$ = ast_mat4; }
-       | SAMPLER1D             { $$ = ast_sampler1d; }
-       | SAMPLER2D             { $$ = ast_sampler2d; }
-       | SAMPLER2DRECT         { $$ = ast_sampler2drect; }
-       | SAMPLER3D             { $$ = ast_sampler3d; }
-       | SAMPLERCUBE           { $$ = ast_samplercube; }
-       | SAMPLER1DSHADOW       { $$ = ast_sampler1dshadow; }
-       | SAMPLER2DSHADOW       { $$ = ast_sampler2dshadow; }
-       | SAMPLER2DRECTSHADOW   { $$ = ast_sampler2drectshadow; }
-       | SAMPLERCUBESHADOW     { $$ = ast_samplercubeshadow; }
-       | SAMPLER1DARRAY        { $$ = ast_sampler1darray; }
-       | SAMPLER2DARRAY        { $$ = ast_sampler2darray; }
-       | SAMPLER1DARRAYSHADOW  { $$ = ast_sampler1darrayshadow; }
-       | SAMPLER2DARRAYSHADOW  { $$ = ast_sampler2darrayshadow; }
-       | ISAMPLER1D            { $$ = ast_isampler1d; }
-       | ISAMPLER2D            { $$ = ast_isampler2d; }
-       | ISAMPLER3D            { $$ = ast_isampler3d; }
-       | ISAMPLERCUBE          { $$ = ast_isamplercube; }
-       | ISAMPLER1DARRAY       { $$ = ast_isampler1darray; }
-       | ISAMPLER2DARRAY       { $$ = ast_isampler2darray; }
-       | USAMPLER1D            { $$ = ast_usampler1d; }
-       | USAMPLER2D            { $$ = ast_usampler2d; }
-       | USAMPLER3D            { $$ = ast_usampler3d; }
-       | USAMPLERCUBE          { $$ = ast_usamplercube; }
-       | USAMPLER1DARRAY       { $$ = ast_usampler1darray; }
-       | USAMPLER2DARRAY       { $$ = ast_usampler2darray; }
+       VOID_TOK                { $$ = "void"; }
+       | FLOAT_TOK             { $$ = "float"; }
+       | INT_TOK               { $$ = "int"; }
+       | UINT_TOK              { $$ = "uint"; }
+       | BOOL_TOK              { $$ = "bool"; }
+       | VEC2                  { $$ = "vec2"; }
+       | VEC3                  { $$ = "vec3"; }
+       | VEC4                  { $$ = "vec4"; }
+       | BVEC2                 { $$ = "bvec2"; }
+       | BVEC3                 { $$ = "bvec3"; }
+       | BVEC4                 { $$ = "bvec4"; }
+       | IVEC2                 { $$ = "ivec2"; }
+       | IVEC3                 { $$ = "ivec3"; }
+       | IVEC4                 { $$ = "ivec4"; }
+       | UVEC2                 { $$ = "uvec2"; }
+       | UVEC3                 { $$ = "uvec3"; }
+       | UVEC4                 { $$ = "uvec4"; }
+       | MAT2X2                { $$ = "mat2"; }
+       | MAT2X3                { $$ = "mat2x3"; }
+       | MAT2X4                { $$ = "mat2x4"; }
+       | MAT3X2                { $$ = "mat3x2"; }
+       | MAT3X3                { $$ = "mat3"; }
+       | MAT3X4                { $$ = "mat3x4"; }
+       | MAT4X2                { $$ = "mat4x2"; }
+       | MAT4X3                { $$ = "mat4x3"; }
+       | MAT4X4                { $$ = "mat4"; }
+       | SAMPLER1D             { $$ = "sampler1D"; }
+       | SAMPLER2D             { $$ = "sampler2D"; }
+       | SAMPLER2DRECT         { $$ = "sampler2DRect"; }
+       | SAMPLER3D             { $$ = "sampler3D"; }
+       | SAMPLERCUBE           { $$ = "samplerCube"; }
+       | SAMPLEREXTERNALOES    { $$ = "samplerExternalOES"; }
+       | SAMPLER1DSHADOW       { $$ = "sampler1DShadow"; }
+       | SAMPLER2DSHADOW       { $$ = "sampler2DShadow"; }
+       | SAMPLER2DRECTSHADOW   { $$ = "sampler2DRectShadow"; }
+       | SAMPLERCUBESHADOW     { $$ = "samplerCubeShadow"; }
+       | SAMPLER1DARRAY        { $$ = "sampler1DArray"; }
+       | SAMPLER2DARRAY        { $$ = "sampler2DArray"; }
+       | SAMPLER1DARRAYSHADOW  { $$ = "sampler1DArrayShadow"; }
+       | SAMPLER2DARRAYSHADOW  { $$ = "sampler2DArrayShadow"; }
+       | SAMPLERBUFFER         { $$ = "samplerBuffer"; }
+       | SAMPLERCUBEARRAY      { $$ = "samplerCubeArray"; }
+       | SAMPLERCUBEARRAYSHADOW { $$ = "samplerCubeArrayShadow"; }
+       | ISAMPLER1D            { $$ = "isampler1D"; }
+       | ISAMPLER2D            { $$ = "isampler2D"; }
+       | ISAMPLER2DRECT        { $$ = "isampler2DRect"; }
+       | ISAMPLER3D            { $$ = "isampler3D"; }
+       | ISAMPLERCUBE          { $$ = "isamplerCube"; }
+       | ISAMPLER1DARRAY       { $$ = "isampler1DArray"; }
+       | ISAMPLER2DARRAY       { $$ = "isampler2DArray"; }
+       | ISAMPLERBUFFER        { $$ = "isamplerBuffer"; }
+       | ISAMPLERCUBEARRAY     { $$ = "isamplerCubeArray"; }
+       | USAMPLER1D            { $$ = "usampler1D"; }
+       | USAMPLER2D            { $$ = "usampler2D"; }
+       | USAMPLER2DRECT        { $$ = "usampler2DRect"; }
+       | USAMPLER3D            { $$ = "usampler3D"; }
+       | USAMPLERCUBE          { $$ = "usamplerCube"; }
+       | USAMPLER1DARRAY       { $$ = "usampler1DArray"; }
+       | USAMPLER2DARRAY       { $$ = "usampler2DArray"; }
+       | USAMPLERBUFFER        { $$ = "usamplerBuffer"; }
+       | USAMPLERCUBEARRAY     { $$ = "usamplerCubeArray"; }
+       | SAMPLER2DMS           { $$ = "sampler2DMS"; }
+       | ISAMPLER2DMS          { $$ = "isampler2DMS"; }
+       | USAMPLER2DMS          { $$ = "usampler2DMS"; }
+       | SAMPLER2DMSARRAY      { $$ = "sampler2DMSArray"; }
+       | ISAMPLER2DMSARRAY     { $$ = "isampler2DMSArray"; }
+       | USAMPLER2DMSARRAY     { $$ = "usampler2DMSArray"; }
        ;
 
 precision_qualifier:
        HIGHP     {
-                    if (!state->es_shader && state->language_version < 130)
-                       _mesa_glsl_error(& @1, state,
-                                        "precision qualifier forbidden "
-                                        "in %s (1.30 or later "
-                                        "required)\n",
-                                        state->version_string);
+                     state->check_precision_qualifiers_allowed(&@1);
 
                     $$ = ast_precision_high;
                  }
        | MEDIUMP {
-                    if (!state->es_shader && state->language_version < 130)
-                       _mesa_glsl_error(& @1, state,
-                                        "precision qualifier forbidden "
-                                        "in %s (1.30 or later "
-                                        "required)\n",
-                                        state->version_string);
+                     state->check_precision_qualifiers_allowed(&@1);
 
                     $$ = ast_precision_medium;
                  }
        | LOWP    {
-                    if (!state->es_shader && state->language_version < 130)
-                       _mesa_glsl_error(& @1, state,
-                                        "precision qualifier forbidden "
-                                        "in %s (1.30 or later "
-                                        "required)\n",
-                                        state->version_string);
+                     state->check_precision_qualifiers_allowed(&@1);
 
                     $$ = ast_precision_low;
                  }
@@ -1430,6 +1534,7 @@ struct_specifier:
           $$ = new(ctx) ast_struct_specifier($2, $4);
           $$->set_location(yylloc);
           state->symbols->add_type($2, glsl_type::void_type);
+           state->symbols->add_type_ast($2, new(ctx) ast_type_specifier($$));
        }
        | STRUCT '{' struct_declaration_list '}'
        {
@@ -1442,12 +1547,12 @@ struct_specifier:
 struct_declaration_list:
        struct_declaration
        {
-          $$ = (ast_node *) $1;
+          $$ = $1;
           $1->link.self_link();
        }
        | struct_declaration_list struct_declaration
        {
-          $$ = (ast_node *) $1;
+          $$ = $1;
           $$->link.insert_before(& $2->link);
        }
        ;
@@ -1486,7 +1591,6 @@ struct_declarator:
           void *ctx = state;
           $$ = new(ctx) ast_declaration($1, false, NULL, NULL);
           $$->set_location(yylloc);
-          state->symbols->add_variable(new(state) ir_variable(NULL, $1, ir_var_auto));
        }
        | any_identifier '[' constant_expression ']'
        {
@@ -1498,6 +1602,28 @@ struct_declarator:
 
 initializer:
        assignment_expression
+       | '{' initializer_list '}'
+       {
+          $$ = $2;
+       }
+       | '{' initializer_list ',' '}'
+       {
+          $$ = $2;
+       }
+       ;
+
+initializer_list:
+       initializer
+       {
+          void *ctx = state;
+          $$ = new(ctx) ast_aggregate_initializer();
+          $$->set_location(yylloc);
+          $$->expressions.push_tail(& $1->link);
+       }
+       | initializer_list ',' initializer
+       {
+          $1->expressions.push_tail(& $3->link);
+       }
        ;
 
 declaration_statement:
@@ -1515,8 +1641,7 @@ simple_statement:
        declaration_statement
        | expression_statement
        | selection_statement
-       | switch_statement              { $$ = NULL; }
-       | case_label                    { $$ = NULL; }
+       | switch_statement
        | iteration_statement
        | jump_statement
        ;
@@ -1638,13 +1763,90 @@ condition:
        }
        ;
 
+/*
+ * siwtch_statement grammar is based on the syntax described in the body
+ * of the GLSL spec, not in it's appendix!!!
+ */
 switch_statement:
-       SWITCH '(' expression ')' compound_statement
+       SWITCH '(' expression ')' switch_body
+       {
+          $$ = new(state) ast_switch_statement($3, $5);
+          $$->set_location(yylloc);
+       }
+       ;
+
+switch_body:
+       '{' '}'
+       {
+          $$ = new(state) ast_switch_body(NULL);
+          $$->set_location(yylloc);
+       }
+       | '{' case_statement_list '}'
+       {
+          $$ = new(state) ast_switch_body($2);
+          $$->set_location(yylloc);
+       }
        ;
 
 case_label:
        CASE expression ':'
+       {
+          $$ = new(state) ast_case_label($2);
+          $$->set_location(yylloc);
+       }
        | DEFAULT ':'
+       {
+          $$ = new(state) ast_case_label(NULL);
+          $$->set_location(yylloc);
+       }
+       ;
+
+case_label_list:
+       case_label
+       {
+          ast_case_label_list *labels = new(state) ast_case_label_list();
+
+          labels->labels.push_tail(& $1->link);
+          $$ = labels;
+          $$->set_location(yylloc);
+       }
+       | case_label_list case_label
+       {
+          $$ = $1;
+          $$->labels.push_tail(& $2->link);
+       }
+       ;
+
+case_statement:
+       case_label_list statement
+       {
+          ast_case_statement *stmts = new(state) ast_case_statement($1);
+          stmts->set_location(yylloc);
+
+          stmts->stmts.push_tail(& $2->link);
+          $$ = stmts;
+       }
+       | case_statement statement
+       {
+          $$ = $1;
+          $$->stmts.push_tail(& $2->link);
+       }
+       ;
+
+case_statement_list:
+       case_statement
+       {
+          ast_case_statement_list *cases= new(state) ast_case_statement_list();
+          cases->set_location(yylloc);
+
+          cases->cases.push_tail(& $1->link);
+          $$ = cases;
+       }
+       | case_statement_list case_statement
+       {
+          $$ = $1;
+          $$->cases.push_tail(& $2->link);
+       }
        ;
 
 iteration_statement:
@@ -1735,6 +1937,7 @@ external_declaration:
        function_definition     { $$ = $1; }
        | declaration           { $$ = $1; }
        | pragma_statement      { $$ = NULL; }
+       | layout_defaults       { $$ = NULL; }
        ;
 
 function_definition:
@@ -1749,3 +1952,211 @@ function_definition:
           state->symbols->pop_scope();
        }
        ;
+
+/* layout_qualifieropt is packed into this rule */
+interface_block:
+       basic_interface_block
+       {
+          $$ = $1;
+       }
+       | layout_qualifier basic_interface_block
+       {
+          ast_interface_block *block = $2;
+          if (!block->layout.merge_qualifier(& @1, state, $1)) {
+             YYERROR;
+          }
+          $$ = block;
+       }
+       ;
+
+basic_interface_block:
+       interface_qualifier NEW_IDENTIFIER '{' member_list '}' instance_name_opt ';'
+       {
+          ast_interface_block *const block = $6;
+
+          block->block_name = $2;
+          block->declarations.push_degenerate_list_at_head(& $4->link);
+
+          if ($1.flags.q.uniform) {
+             if (!state->ARB_uniform_buffer_object_enable) {
+                _mesa_glsl_error(& @1, state,
+                                 "#version 140 / GL_ARB_uniform_buffer_object "
+                                 "required for defining uniform blocks\n");
+             } else if (state->ARB_uniform_buffer_object_warn) {
+                _mesa_glsl_warning(& @1, state,
+                                   "#version 140 / GL_ARB_uniform_buffer_object "
+                                   "required for defining uniform blocks\n");
+             }
+          } else {
+             if (state->es_shader || state->language_version < 150) {
+                _mesa_glsl_error(& @1, state,
+                                "#version 150 required for using "
+                                "interface blocks.\n");
+             }
+          }
+
+          /* From the GLSL 1.50.11 spec, section 4.3.7 ("Interface Blocks"):
+           * "It is illegal to have an input block in a vertex shader
+           *  or an output block in a fragment shader"
+           */
+          if ((state->target == vertex_shader) && $1.flags.q.in) {
+             _mesa_glsl_error(& @1, state,
+                              "`in' interface block is not allowed for "
+                              "a vertex shader\n");
+          } else if ((state->target == fragment_shader) && $1.flags.q.out) {
+             _mesa_glsl_error(& @1, state,
+                              "`out' interface block is not allowed for "
+                              "a fragment shader\n");
+          }
+
+          /* Since block arrays require names, and both features are added in
+           * the same language versions, we don't have to explicitly
+           * version-check both things.
+           */
+          if (block->instance_name != NULL) {
+             state->check_version(150, 300, & @1, "interface blocks with "
+                       "an instance name are not allowed");
+          }
+
+          unsigned interface_type_mask;
+          struct ast_type_qualifier temp_type_qualifier;
+
+       /* Get a bitmask containing only the in/out/uniform flags, allowing us
+        * to ignore other irrelevant flags like interpolation qualifiers.
+        */
+          temp_type_qualifier.flags.i = 0;
+          temp_type_qualifier.flags.q.uniform = true;
+          temp_type_qualifier.flags.q.in = true;
+          temp_type_qualifier.flags.q.out = true;
+          interface_type_mask = temp_type_qualifier.flags.i;
+
+       /* Get the block's interface qualifier.  The interface_qualifier
+        * production rule guarantees that only one bit will be set (and
+        * it will be in/out/uniform).
+        */
+       unsigned block_interface_qualifier = $1.flags.i;
+
+          block->layout.flags.i |= block_interface_qualifier;
+
+          foreach_list_typed (ast_declarator_list, member, link, &block->declarations) {
+             ast_type_qualifier& qualifier = member->type->qualifier;
+             if ((qualifier.flags.i & interface_type_mask) == 0) {
+             /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+              * "If no optional qualifier is used in a member declaration, the
+              *  qualifier of the variable is just in, out, or uniform as declared
+              *  by interface-qualifier."
+              */
+                qualifier.flags.i |= block_interface_qualifier;
+             } else if ((qualifier.flags.i & interface_type_mask) !=
+                        block_interface_qualifier) {
+                /* GLSLangSpec.1.50.11, 4.3.7 (Interface Blocks):
+              * "If optional qualifiers are used, they can include interpolation
+              *  and storage qualifiers and they must declare an input, output,
+              *  or uniform variable consistent with the interface qualifier of
+              *  the block."
+                 */
+                _mesa_glsl_error(& @1, state,
+                                 "uniform/in/out qualifier on "
+                                 "interface block member does not match "
+                                 "the interface block\n");
+             }
+          }
+
+          $$ = block;
+       }
+       ;
+
+interface_qualifier:
+       IN_TOK
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.in = 1;
+       }
+       | OUT_TOK
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.out = 1;
+       }
+       | UNIFORM
+       {
+          memset(& $$, 0, sizeof($$));
+          $$.flags.q.uniform = 1;
+       }
+       ;
+
+instance_name_opt:
+       /* empty */
+       {
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            NULL,
+                                            NULL);
+       }
+       | NEW_IDENTIFIER
+       {
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            $1,
+                                            NULL);
+       }
+       | NEW_IDENTIFIER '[' constant_expression ']'
+       {
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            $1,
+                                            $3);
+       }
+       | NEW_IDENTIFIER '[' ']'
+       {
+          _mesa_glsl_error(& @1, state,
+                           "instance block arrays must be explicitly sized\n");
+
+          $$ = new(state) ast_interface_block(*state->default_uniform_qualifier,
+                                            $1,
+                                            NULL);
+       }
+       ;
+
+member_list:
+       member_declaration
+       {
+          $$ = $1;
+          $1->link.self_link();
+       }
+       | member_declaration member_list
+       {
+          $$ = $1;
+          $2->link.insert_before(& $$->link);
+       }
+       ;
+
+member_declaration:
+       fully_specified_type struct_declarator_list ';'
+       {
+          void *ctx = state;
+          ast_fully_specified_type *type = $1;
+          type->set_location(yylloc);
+
+          if (type->qualifier.flags.q.attribute) {
+             _mesa_glsl_error(& @1, state,
+                             "keyword 'attribute' cannot be used with "
+                             "interface block member\n");
+          } else if (type->qualifier.flags.q.varying) {
+             _mesa_glsl_error(& @1, state,
+                             "keyword 'varying' cannot be used with "
+                             "interface block member\n");
+          }
+
+          $$ = new(ctx) ast_declarator_list(type);
+          $$->set_location(yylloc);
+          $$->ubo_qualifiers_valid = true;
+
+          $$->declarations.push_degenerate_list_at_head(& $2->link);
+       }
+       ;
+
+layout_defaults:
+       layout_qualifier UNIFORM ';'
+       {
+          if (!state->default_uniform_qualifier->merge_qualifier(& @1, state,
+                                                                 $1)) {
+             YYERROR;
+          }
+       }