Use glsl_type::element_type to get the type of array elements
[mesa.git] / ast_function.cpp
index 6470057a905e7e522907861d03b89878c8c3f2ac..cd57c32040bf1f96a9fb071f17d4454e32ef36db 100644 (file)
 #include "glsl_types.h"
 #include "ir.h"
 
-static ir_rvalue *
-match_function_by_name(exec_list *instructions, const char *name,
-                      YYLTYPE *loc, simple_node *parameters,
-                      struct _mesa_glsl_parse_state *state)
+static unsigned
+process_parameters(exec_list *instructions, exec_list *actual_parameters,
+                  simple_node *parameters,
+                  struct _mesa_glsl_parse_state *state)
 {
-   ir_function *f = state->symbols->get_function(name);
-
-   if (f == NULL) {
-      _mesa_glsl_error(loc, state, "function `%s' undeclared", name);
-      return ir_call::get_error_instruction();
-   }
-
-   /* Once we've determined that the function being called might exist,
-    * process the parameters.
-    */
-   exec_list actual_parameters;
    simple_node *const first = parameters;
+   unsigned count = 0;
+
    if (first != NULL) {
       simple_node *ptr = first;
       do {
@@ -51,20 +42,62 @@ match_function_by_name(exec_list *instructions, const char *name,
            ((ast_node *) ptr)->hir(instructions, state);
         ptr = ptr->next;
 
-        actual_parameters.push_tail(result);
+        actual_parameters->push_tail(result);
+        count++;
       } while (ptr != first);
    }
 
-   /* After processing the function's actual parameters, try to find an
-    * overload of the function that matches.
-    */
+   return count;
+}
+
+
+static ir_rvalue *
+process_call(exec_list *instructions, ir_function *f,
+            YYLTYPE *loc, exec_list *actual_parameters,
+            struct _mesa_glsl_parse_state *state)
+{
    const ir_function_signature *sig =
-      f->matching_signature(& actual_parameters);
+      f->matching_signature(actual_parameters);
+
+   /* The instructions param will be used when the FINISHMEs below are done */
+   (void) instructions;
+
    if (sig != NULL) {
+      /* Verify that 'out' and 'inout' actual parameters are lvalues.  This
+       * isn't done in ir_function::matching_signature because that function
+       * cannot generate the necessary diagnostics.
+       */
+      exec_list_iterator actual_iter = actual_parameters->iterator();
+      exec_list_iterator formal_iter = sig->parameters.iterator();
+
+      while (actual_iter.has_next()) {
+        ir_rvalue *actual =
+           ((ir_instruction *) actual_iter.get())->as_rvalue();
+        ir_variable *formal =
+           ((ir_instruction *) formal_iter.get())->as_variable();
+
+        assert(actual != NULL);
+        assert(formal != NULL);
+
+        if ((formal->mode == ir_var_out)
+            || (formal->mode == ir_var_inout)) {
+           if (! actual->is_lvalue()) {
+              /* FINISHME: Log a better diagnostic here.  There is no way
+               * FINISHME: to tell the user which parameter is invalid.
+               */
+              _mesa_glsl_error(loc, state, "`%s' parameter is not lvalue",
+                               (formal->mode == ir_var_out) ? "out" : "inout");
+           }
+        }
+
+        actual_iter.next();
+        formal_iter.next();
+      }
+
       /* FINISHME: The list of actual parameters needs to be modified to
        * FINISHME: include any necessary conversions.
        */
-      return new ir_call(sig, actual_parameters);
+      return new ir_call(sig, actual_parameters);
    } else {
       /* FINISHME: Log a better error message here.  G++ will show the types
        * FINISHME: of the actual parameters and the set of candidate
@@ -72,12 +105,37 @@ match_function_by_name(exec_list *instructions, const char *name,
        * FINISHME: multiple functions match.
        */
       _mesa_glsl_error(loc, state, "no matching function for call to `%s'",
-                      name);
+                      f->name);
       return ir_call::get_error_instruction();
    }
 }
 
 
+static ir_rvalue *
+match_function_by_name(exec_list *instructions, const char *name,
+                      YYLTYPE *loc, simple_node *parameters,
+                      struct _mesa_glsl_parse_state *state)
+{
+   ir_function *f = state->symbols->get_function(name);
+
+   if (f == NULL) {
+      _mesa_glsl_error(loc, state, "function `%s' undeclared", name);
+      return ir_call::get_error_instruction();
+   }
+
+   /* Once we've determined that the function being called might exist,
+    * process the parameters.
+    */
+   exec_list actual_parameters;
+   process_parameters(instructions, &actual_parameters, parameters, state);
+
+   /* After processing the function's actual parameters, try to find an
+    * overload of the function that matches.
+    */
+   return process_call(instructions, f, loc, &actual_parameters, state);
+}
+
+
 /**
  * Perform automatic type conversion of constructor parameters
  */
@@ -103,7 +161,7 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type)
         return new ir_expression(ir_unop_f2i, desired_type, src, NULL);
       else {
         assert(b == GLSL_TYPE_BOOL);
-        assert(!"FINISHME: Convert bool to int / uint.");
+        return new ir_expression(ir_unop_f2b, desired_type, src, NULL);
       }
    case GLSL_TYPE_FLOAT:
       switch (b) {
@@ -112,7 +170,7 @@ convert_component(ir_rvalue *src, const glsl_type *desired_type)
       case GLSL_TYPE_INT:
         return new ir_expression(ir_unop_i2f, desired_type, src, NULL);
       case GLSL_TYPE_BOOL:
-        assert(!"FINISHME: Convert bool to float.");
+        return new ir_expression(ir_unop_b2f, desired_type, src, NULL);
       }
       break;
    case GLSL_TYPE_BOOL: {
@@ -161,6 +219,77 @@ dereference_component(ir_rvalue *src, unsigned component)
 }
 
 
+static ir_rvalue *
+process_array_constructor(exec_list *instructions,
+                         const glsl_type *constructor_type,
+                         YYLTYPE *loc, simple_node *parameters,
+                         struct _mesa_glsl_parse_state *state)
+{
+   /* Array constructors come in two forms: sized and unsized.  Sized array
+    * constructors look like 'vec4[2](a, b)', where 'a' and 'b' are vec4
+    * variables.  In this case the number of parameters must exactly match the
+    * specified size of the array.
+    *
+    * Unsized array constructors look like 'vec4[](a, b)', where 'a' and 'b'
+    * are vec4 variables.  In this case the size of the array being constructed
+    * is determined by the number of parameters.
+    *
+    * From page 52 (page 58 of the PDF) of the GLSL 1.50 spec:
+    *
+    *    "There must be exactly the same number of arguments as the size of
+    *    the array being constructed. If no size is present in the
+    *    constructor, then the array is explicitly sized to the number of
+    *    arguments provided. The arguments are assigned in order, starting at
+    *    element 0, to the elements of the constructed array. Each argument
+    *    must be the same type as the element type of the array, or be a type
+    *    that can be converted to the element type of the array according to
+    *    Section 4.1.10 "Implicit Conversions.""
+    */
+   exec_list actual_parameters;
+   const unsigned parameter_count =
+      process_parameters(instructions, &actual_parameters, parameters, state);
+
+   if ((parameter_count == 0)
+       || ((constructor_type->length != 0)
+          && (constructor_type->length != parameter_count))) {
+      const unsigned min_param = (constructor_type->length == 0)
+        ? 1 : constructor_type->length;
+
+      _mesa_glsl_error(loc, state, "array constructor must have %s %u "
+                      "parameter%s",
+                      (constructor_type->length != 0) ? "at least" : "exactly",
+                      min_param, (min_param <= 1) ? "" : "s");
+      return ir_call::get_error_instruction();
+   }
+
+   if (constructor_type->length == 0) {
+      constructor_type =
+        glsl_type::get_array_instance(constructor_type->element_type(),
+                                      parameter_count);
+      assert(constructor_type != NULL);
+      assert(constructor_type->length == parameter_count);
+   }
+
+   ir_function *f = state->symbols->get_function(constructor_type->name);
+
+   /* If the constructor for this type of array does not exist, generate the
+    * prototype and add it to the symbol table.  The code will be generated
+    * later.
+    */
+   if (f == NULL) {
+      f = constructor_type->generate_constructor_prototype(state->symbols);
+   }
+
+   ir_rvalue *const r =
+      process_call(instructions, f, loc, &actual_parameters, state);
+
+   assert(r != NULL);
+   assert(r->type->is_error() || (r->type == constructor_type));
+
+   return r;
+}
+
+
 ir_rvalue *
 ast_function_expression::hir(exec_list *instructions,
                             struct _mesa_glsl_parse_state *state)
@@ -177,9 +306,9 @@ ast_function_expression::hir(exec_list *instructions,
    if (is_constructor()) {
       const ast_type_specifier *type = (ast_type_specifier *) subexpressions[0];
       YYLTYPE loc = type->get_location();
+      const char *name;
 
-      const glsl_type *const constructor_type =
-        state->symbols->get_type(type->type_name);
+      const glsl_type *const constructor_type = type->glsl_type(& name, state);
 
 
       /* Constructors for samplers are illegal.
@@ -190,6 +319,16 @@ ast_function_expression::hir(exec_list *instructions,
         return ir_call::get_error_instruction();
       }
 
+      if (constructor_type->is_array()) {
+        if (state->language_version <= 110) {
+           _mesa_glsl_error(& loc, state,
+                            "array constructors forbidden in GLSL 1.10");
+           return ir_call::get_error_instruction();
+        }
+
+        return process_array_constructor(instructions, constructor_type,
+                                         & loc, subexpressions[1], state);
+      }
 
       /* There are two kinds of constructor call.  Constructors for built-in
        * language types, such as mat4 and vec2, are free form.  The only
@@ -327,7 +466,7 @@ ast_function_expression::hir(exec_list *instructions,
          *    arguments to provide an initializer for every component in the
          *    constructed value."
          */
-        if (components_used < type_components) {
+        if ((components_used < type_components) && (components_used != 1)) {
            _mesa_glsl_error(& loc, state, "too few components to construct "
                             "`%s'",
                             constructor_type->name);