Use ir_dereference::set_swizzle
[mesa.git] / ast_to_hir.cpp
index 1379ec9801357c2ef4b70adaef9f390b3f580f9e..f7c82fab4bf627bce1dc8d6480fef098a4281c1e 100644 (file)
@@ -50,7 +50,7 @@
  */
 #include <stdio.h>
 #include "main/imports.h"
-#include "symbol_table.h"
+#include "glsl_symbol_table.h"
 #include "glsl_parser_extras.h"
 #include "ast.h"
 #include "glsl_types.h"
@@ -63,6 +63,8 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
 
    _mesa_glsl_initialize_variables(instructions, state);
 
+   state->current_function = NULL;
+
    foreach (ptr, & state->translation_unit) {
       ((ast_node *)ptr)->hir(instructions, state);
    }
@@ -208,8 +210,7 @@ arithmetic_result_type(const struct glsl_type *type_a,
               type_name[6] = '\0';
            }
 
-           t = (glsl_type *)
-              _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
+           t = state->symbols->get_type(type_name);
            return (t != NULL) ? t : glsl_error_type;
         }
       } else if (type_a->is_matrix()) {
@@ -330,6 +331,45 @@ relational_result_type(const struct glsl_type *type_a,
 }
 
 
+/**
+ * Validates that a value can be assigned to a location with a specified type
+ *
+ * Validates that \c rhs can be assigned to some location.  If the types are
+ * not an exact match but an automatic conversion is possible, \c rhs will be
+ * converted.
+ *
+ * \return
+ * \c NULL if \c rhs cannot be assigned to a location with type \c lhs_type.
+ * Otherwise the actual RHS to be assigned will be returned.  This may be
+ * \c rhs, or it may be \c rhs after some type conversion.
+ *
+ * \note
+ * In addition to being used for assignments, this function is used to
+ * type-check return values.
+ */
+ir_instruction *
+validate_assignment(const glsl_type *lhs_type, ir_instruction *rhs)
+{
+   const glsl_type *const rhs_type = rhs->type;
+
+   /* If there is already some error in the RHS, just return it.  Anything
+    * else will lead to an avalanche of error message back to the user.
+    */
+   if (rhs_type->is_error())
+      return rhs;
+
+   /* FINISHME: For GLSL 1.10, check that the types are not arrays. */
+
+   /* If the types are identical, the assignment can trivially proceed.
+    */
+   if (rhs_type == lhs_type)
+      return rhs;
+
+   /* FINISHME: Check for and apply automatic conversions. */
+   return NULL;
+}
+
+
 ir_instruction *
 ast_node::hir(exec_list *instructions,
              struct _mesa_glsl_parse_state *state)
@@ -447,8 +487,11 @@ ast_expression::hir(exec_list *instructions,
         }
       }
 
-      /* FINISHME: Check that the LHS and RHS have matching types. */
-      /* FINISHME: For GLSL 1.10, check that the types are not arrays. */
+      ir_instruction *rhs = validate_assignment(op[0]->type, op[1]);
+      if (rhs == NULL) {
+        type = glsl_error_type;
+        rhs = op[1];
+      }
 
       ir_instruction *tmp = new ir_assignment(op[0], op[1], NULL);
       instructions->push_tail(tmp);
@@ -630,21 +673,10 @@ ast_expression::hir(exec_list *instructions,
       break;
 
    case ast_function_call:
-      /* There are three sorts of function calls.
-       *
-       * 1. contstructors - The first subexpression is an ast_type_specifier.
-       * 2. methods - Only the .length() method of array types.
-       * 3. functions - Calls to regular old functions.
-       *
-       * Method calls are actually detected when the ast_field_selection
-       * expression is handled.
+      /* Should *NEVER* get here.  ast_function_call should always be handled
+       * by ast_function_expression::hir.
        */
-#if 0
-      result = _mesa_ast_function_call_to_hir(this->subexpressions[0],
-                                             this->subexpressions[1],
-                                             state);
-      type = result->type;
-#endif
+      assert(0);
       break;
 
    case ast_identifier: {
@@ -652,16 +684,15 @@ ast_expression::hir(exec_list *instructions,
        * tree.  This particular use must be at location specified in the grammar
        * as 'variable_identifier'.
        */
-      ir_variable *var = (ir_variable *)
-        _mesa_symbol_table_find_symbol(state->symbols, 0,
-                                       this->primary_expression.identifier);
+      ir_variable *var = 
+        state->symbols->get_variable(this->primary_expression.identifier);
 
       result = new ir_dereference(var);
 
       if (var != NULL) {
         type = result->type;
       } else {
-        _mesa_glsl_error(& loc, NULL, "`%s' undeclared",
+        _mesa_glsl_error(& loc, state, "`%s' undeclared",
                          this->primary_expression.identifier);
 
         error_emitted = true;
@@ -715,7 +746,7 @@ ast_expression::hir(exec_list *instructions,
    }
 
    if (is_error_type(type) && !error_emitted)
-      _mesa_glsl_error(& loc, NULL, "type mismatch");
+      _mesa_glsl_error(& loc, state, "type mismatch");
 
    return result;
 }
@@ -751,13 +782,13 @@ ast_compound_statement::hir(exec_list *instructions,
 
 
    if (new_scope)
-      _mesa_symbol_table_push_scope(state->symbols);
+      state->symbols->push_scope();
 
    foreach (ptr, &statements)
       ((ast_node *)ptr)->hir(instructions, state);
 
    if (new_scope)
-      _mesa_symbol_table_pop_scope(state->symbols);
+      state->symbols->pop_scope();
 
    /* Compound statements do not have r-values.
     */
@@ -770,76 +801,17 @@ type_specifier_to_glsl_type(const struct ast_type_specifier *spec,
                            const char **name,
                            struct _mesa_glsl_parse_state *state)
 {
-   static const char *const type_names[] = {
-      "void",
-      "float",
-      "int",
-      "uint",
-      "bool",
-      "vec2",
-      "vec3",
-      "vec4",
-      "bvec2",
-      "bvec3",
-      "bvec4",
-      "ivec2",
-      "ivec3",
-      "ivec4",
-      "uvec2",
-      "uvec3",
-      "uvec4",
-      "mat2",
-      "mat2x3",
-      "mat2x4",
-      "mat3x2",
-      "mat3",
-      "mat3x4",
-      "mat4x2",
-      "mat4x3",
-      "mat4",
-      "sampler1D",
-      "sampler2D",
-      "sampler3D",
-      "samplerCube",
-      "sampler1DShadow",
-      "sampler2DShadow",
-      "samplerCubeShadow",
-      "sampler1DArray",
-      "sampler2DArray",
-      "sampler1DArrayShadow",
-      "sampler2DArrayShadow",
-      "isampler1D",
-      "isampler2D",
-      "isampler3D",
-      "isamplerCube",
-      "isampler1DArray",
-      "isampler2DArray",
-      "usampler1D",
-      "usampler2D",
-      "usampler3D",
-      "usamplerCube",
-      "usampler1DArray",
-      "usampler2DArray",
-
-      NULL, /* ast_struct */
-      NULL  /* ast_type_name */
-   };
    struct glsl_type *type;
-   const char *type_name = NULL;
 
    if (spec->type_specifier == ast_struct) {
       /* FINISHME: Handle annonymous structures. */
       type = NULL;
    } else {
-      type_name = (spec->type_specifier == ast_type_name)
-        ? spec->type_name : type_names[spec->type_specifier];
-
-      type = (glsl_type *)
-        _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
-      *name = type_name;
+      type = state->symbols->get_type(spec->type_name);
+      *name = spec->type_name;
 
       /* FINISHME: Handle array declarations.  Note that this requires complete
-       * FINSIHME: handling of constant expressions.
+       * FINISHME: handling of constant expressions.
        */
    }
 
@@ -911,7 +883,7 @@ ast_declarator_list::hir(exec_list *instructions,
        * FINISHME: declaration at a higher scope.
        */
 
-      if (decl_type == NULL) {
+      if ((decl_type == NULL) || decl_type->is_void()) {
         YYLTYPE loc;
 
         loc = this->get_location();
@@ -939,7 +911,7 @@ ast_declarator_list::hir(exec_list *instructions,
 
       var = new ir_variable(var_type, decl->identifier);
 
-      /* FINSIHME: Variables that are attribute, uniform, varying, in, or
+      /* FINISHME: Variables that are attribute, uniform, varying, in, or
        * FINISHME: out varibles must be declared either at global scope or
        * FINISHME: in a parameter list (in and out only).
        */
@@ -949,8 +921,7 @@ ast_declarator_list::hir(exec_list *instructions,
       /* Attempt to add the variable to the symbol table.  If this fails, it
        * means the variable has already been declared at this scope.
        */
-      if (_mesa_symbol_table_add_symbol(state->symbols, 0, decl->identifier,
-                                       var) != 0) {
+      if (state->symbols->name_declared_this_scope(decl->identifier)) {
         YYLTYPE loc = this->get_location();
 
         _mesa_glsl_error(& loc, state, "`%s' redeclared",
@@ -958,6 +929,10 @@ ast_declarator_list::hir(exec_list *instructions,
         continue;
       }
 
+      const bool added_variable =
+        state->symbols->add_variable(decl->identifier, var);
+      assert(added_variable);
+
       instructions->push_tail(var);
 
       /* FINISHME: Process the declaration initializer. */
@@ -1000,7 +975,12 @@ ast_parameter_declarator::hir(exec_list *instructions,
     * FINISHME: complete handling of constant expressions.
     */
 
+   /* Apply any specified qualifiers to the parameter declaration.  Note that
+    * for function parameters the default mode is 'in'.
+    */
    apply_type_qualifier_to_variable(& this->type->qualifier, var, state);
+   if (var->mode == ir_var_auto)
+      var->mode = ir_var_in;
 
    instructions->push_tail(var);
 
@@ -1068,14 +1048,20 @@ ast_function_definition::hir(exec_list *instructions,
    ast_function_parameters_to_hir(& this->prototype->parameters, & parameters,
                                  state);
 
+   const char *return_type_name;
+   const glsl_type *return_type =
+      type_specifier_to_glsl_type(this->prototype->return_type->specifier,
+                                 & return_type_name, state);
+
+   assert(return_type != NULL);
+
 
    /* Verify that this function's signature either doesn't match a previously
     * seen signature for a function with the same name, or, if a match is found,
     * that the previously seen signature does not have an associated definition.
     */
-   f = (ir_function *)
-      _mesa_symbol_table_find_symbol(state->symbols, 0,
-                                    this->prototype->identifier);
+   const char *const name = this->prototype->identifier;
+   f = state->symbols->get_function(name);
    if (f != NULL) {
       foreach_iter(exec_list_iterator, iter, f->signatures) {
         signature = (struct ir_function_signature *) iter.get();
@@ -1091,8 +1077,7 @@ ast_function_definition::hir(exec_list *instructions,
            if (signature->definition != NULL) {
               YYLTYPE loc = this->get_location();
 
-              _mesa_glsl_error(& loc, state, "function `%s' redefined",
-                               this->prototype->identifier);
+              _mesa_glsl_error(& loc, state, "function `%s' redefined", name);
               signature = NULL;
               break;
            }
@@ -1101,18 +1086,24 @@ ast_function_definition::hir(exec_list *instructions,
         signature = NULL;
       }
 
-   } else {
-      f = new ir_function();
-      f->name = this->prototype->identifier;
+   } else if (state->symbols->name_declared_this_scope(name)) {
+      /* This function name shadows a non-function use of the same name.
+       */
+      YYLTYPE loc = this->get_location();
 
-      _mesa_symbol_table_add_symbol(state->symbols, 0, f->name, f);
+      _mesa_glsl_error(& loc, state, "function name `%s' conflicts with "
+                      "non-function", name);
+      signature = NULL;
+   } else {
+      f = new ir_function(name);
+      state->symbols->add_function(f->name, f);
    }
 
 
    /* Finish storing the information about this new function in its signature.
     */
    if (signature == NULL) {
-      signature = new ir_function_signature();
+      signature = new ir_function_signature(return_type);
       f->signatures.push_tail(signature);
    } else {
       /* Destroy all of the previous parameter information.  The previous
@@ -1128,12 +1119,15 @@ ast_function_definition::hir(exec_list *instructions,
    }
 
 
+   assert(state->current_function == NULL);
+   state->current_function = signature;
+
    ast_function_parameters_to_hir(& this->prototype->parameters,
                                  & signature->parameters,
                                  state);
    /* FINISHME: Set signature->return_type */
 
-   label = new ir_label(this->prototype->identifier);
+   label = new ir_label(name);
    if (signature->definition == NULL) {
       signature->definition = label;
    }
@@ -1144,16 +1138,25 @@ ast_function_definition::hir(exec_list *instructions,
     * to the instruction list.  There are other more efficient ways to do this,
     * but they involve ugly linked-list gymnastics.
     */
-   _mesa_symbol_table_push_scope(state->symbols);
+   state->symbols->push_scope();
    foreach_iter(exec_list_iterator, iter, parameters) {
       ir_variable *const var = (ir_variable *) iter.get();
 
-      assert(var->mode == ir_op_var_decl);
+      assert(((ir_instruction *)var)->mode == ir_op_var_decl);
 
       iter.remove();
       instructions->push_tail(var);
 
-      _mesa_symbol_table_add_symbol(state->symbols, 0, var->name, var);
+      /* The only way a parameter would "exist" is if two parameters have
+       * the same name.
+       */
+      if (state->symbols->name_declared_this_scope(var->name)) {
+        YYLTYPE loc = this->get_location();
+
+        _mesa_glsl_error(& loc, state, "parameter `%s' redeclared", var->name);
+      } else {
+        state->symbols->add_variable(var->name, var);
+      }
    }
 
    /* Convert the body of the function to HIR, and append the resulting
@@ -1162,10 +1165,49 @@ ast_function_definition::hir(exec_list *instructions,
     */
    this->body->hir(instructions, state);
 
-   _mesa_symbol_table_pop_scope(state->symbols);
+   state->symbols->pop_scope();
 
+   assert(state->current_function == signature);
+   state->current_function = NULL;
 
    /* Function definitions do not have r-values.
     */
    return NULL;
 }
+
+
+ir_instruction *
+ast_jump_statement::hir(exec_list *instructions,
+                       struct _mesa_glsl_parse_state *state)
+{
+
+   if (mode == ast_return) {
+      ir_return *inst;
+
+      if (opt_return_value) {
+        /* FINISHME: Make sure the enclosing function has a non-void return
+         * FINISHME: type.
+         */
+
+        ir_expression *const ret = (ir_expression *)
+           opt_return_value->hir(instructions, state);
+        assert(ret != NULL);
+
+        /* FINISHME: Make sure the type of the return value matches the return
+         * FINISHME: type of the enclosing function.
+         */
+
+        inst = new ir_return(ret);
+      } else {
+        /* FINISHME: Make sure the enclosing function has a void return type.
+         */
+        inst = new ir_return;
+      }
+
+      instructions->push_tail(inst);
+   }
+
+   /* Jump instructions do not have r-values.
+    */
+   return NULL;
+}