slang: ensure structure elements have their array length set
[mesa.git] / src / mesa / shader / slang / slang_typeinfo.c
index b1afd969d9559e687aa34e5578e46398393eefa4..4a48bc8b8ee3aec83ecfaf98bb7abba0228fac47 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 /**
- * \file slang_assemble_typeinfo.c
+ * \file slang_typeinfo.c
  * slang type info
  * \author Michal Krol
  */
@@ -130,7 +130,7 @@ _slang_is_swizzle(const char *field, GLuint rows, slang_swizzle * swz)
  * do not have duplicated fields.  Returns GL_TRUE if this is a
  * swizzle mask.  Returns GL_FALSE otherwise
  */
-GLboolean
+static GLboolean
 _slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows)
 {
    GLuint i, c = 0;
@@ -154,7 +154,7 @@ _slang_is_swizzle_mask(const slang_swizzle * swz, GLuint rows)
  * Combines (multiplies) two swizzles to form single swizzle.
  * Example: "vec.wzyx.yx" --> "vec.zw".
  */
-GLvoid
+static void
 _slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left,
                          const slang_swizzle * right)
 {
@@ -166,6 +166,110 @@ _slang_multiply_swizzles(slang_swizzle * dst, const slang_swizzle * left,
 }
 
 
+typedef struct
+{
+   const char *name;
+   slang_type_specifier_type type;
+} type_specifier_type_name;
+
+static const type_specifier_type_name type_specifier_type_names[] = {
+   {"void", SLANG_SPEC_VOID},
+   {"bool", SLANG_SPEC_BOOL},
+   {"bvec2", SLANG_SPEC_BVEC2},
+   {"bvec3", SLANG_SPEC_BVEC3},
+   {"bvec4", SLANG_SPEC_BVEC4},
+   {"int", SLANG_SPEC_INT},
+   {"ivec2", SLANG_SPEC_IVEC2},
+   {"ivec3", SLANG_SPEC_IVEC3},
+   {"ivec4", SLANG_SPEC_IVEC4},
+   {"float", SLANG_SPEC_FLOAT},
+   {"vec2", SLANG_SPEC_VEC2},
+   {"vec3", SLANG_SPEC_VEC3},
+   {"vec4", SLANG_SPEC_VEC4},
+   {"mat2", SLANG_SPEC_MAT2},
+   {"mat3", SLANG_SPEC_MAT3},
+   {"mat4", SLANG_SPEC_MAT4},
+   {"mat2x3", SLANG_SPEC_MAT23},
+   {"mat3x2", SLANG_SPEC_MAT32},
+   {"mat2x4", SLANG_SPEC_MAT24},
+   {"mat4x2", SLANG_SPEC_MAT42},
+   {"mat3x4", SLANG_SPEC_MAT34},
+   {"mat4x3", SLANG_SPEC_MAT43},
+   {"sampler1D", SLANG_SPEC_SAMPLER1D},
+   {"sampler2D", SLANG_SPEC_SAMPLER2D},
+   {"sampler3D", SLANG_SPEC_SAMPLER3D},
+   {"samplerCube", SLANG_SPEC_SAMPLERCUBE},
+   {"sampler1DShadow", SLANG_SPEC_SAMPLER1DSHADOW},
+   {"sampler2DShadow", SLANG_SPEC_SAMPLER2DSHADOW},
+   {"sampler2DRect", SLANG_SPEC_SAMPLER2DRECT},
+   {"sampler2DRectShadow", SLANG_SPEC_SAMPLER2DRECTSHADOW},
+   {NULL, SLANG_SPEC_VOID}
+};
+
+slang_type_specifier_type
+slang_type_specifier_type_from_string(const char *name)
+{
+   const type_specifier_type_name *p = type_specifier_type_names;
+   while (p->name != NULL) {
+      if (slang_string_compare(p->name, name) == 0)
+         break;
+      p++;
+   }
+   return p->type;
+}
+
+const char *
+slang_type_specifier_type_to_string(slang_type_specifier_type type)
+{
+   const type_specifier_type_name *p = type_specifier_type_names;
+   while (p->name != NULL) {
+      if (p->type == type)
+         break;
+      p++;
+   }
+   return p->name;
+}
+
+/* slang_fully_specified_type */
+
+int
+slang_fully_specified_type_construct(slang_fully_specified_type * type)
+{
+   type->qualifier = SLANG_QUAL_NONE;
+   slang_type_specifier_ctr(&type->specifier);
+   return 1;
+}
+
+void
+slang_fully_specified_type_destruct(slang_fully_specified_type * type)
+{
+   slang_type_specifier_dtr(&type->specifier);
+}
+
+int
+slang_fully_specified_type_copy(slang_fully_specified_type * x,
+                                const slang_fully_specified_type * y)
+{
+   slang_fully_specified_type z;
+
+   if (!slang_fully_specified_type_construct(&z))
+      return 0;
+   z.qualifier = y->qualifier;
+   z.precision = y->precision;
+   z.variant = y->variant;
+   z.centroid = y->centroid;
+   z.array_len = y->array_len;
+   if (!slang_type_specifier_copy(&z.specifier, &y->specifier)) {
+      slang_fully_specified_type_destruct(&z);
+      return 0;
+   }
+   slang_fully_specified_type_destruct(x);
+   *x = z;
+   return 1;
+}
+
+
+
 GLvoid
 slang_type_specifier_ctr(slang_type_specifier * self)
 {
@@ -187,6 +291,21 @@ slang_type_specifier_dtr(slang_type_specifier * self)
    }
 }
 
+slang_type_specifier *
+slang_type_specifier_new(slang_type_specifier_type type,
+                         struct slang_struct_ *_struct,
+                         struct slang_type_specifier_ *_array)
+{
+   slang_type_specifier *spec =
+      (slang_type_specifier *) _slang_alloc(sizeof(slang_type_specifier));
+   if (spec) {
+      spec->type = type;
+      spec->_struct = _struct;
+      spec->_array = _array;
+   }
+   return spec;
+}
+
 GLboolean
 slang_type_specifier_copy(slang_type_specifier * x,
                           const slang_type_specifier * y)
@@ -250,7 +369,7 @@ slang_type_specifier_equal(const slang_type_specifier * x,
 /**
  * As above, but allow float/int casting.
  */
-static GLboolean
+GLboolean
 slang_type_specifier_compatible(const slang_type_specifier * x,
                                 const slang_type_specifier * y)
 {
@@ -307,7 +426,7 @@ _slang_typeof_function(slang_atom a_name,
 {
    GLboolean error;
 
-   *funFound = _slang_locate_function(space->funcs, a_name, params,
+   *funFound = _slang_function_locate(space->funcs, a_name, params,
                                       num_params, space, atoms, log, &error);
    if (error)
       return GL_FALSE;
@@ -362,14 +481,6 @@ typeof_math_call(const char *name, slang_operation *call,
    }
 }
 
-GLboolean
-_slang_typeof_operation(const slang_assemble_ctx * A,
-                        slang_operation * op,
-                        slang_typeinfo * ti)
-{
-   return _slang_typeof_operation_(op, &A->space, ti, A->atoms, A->log);
-}
-
 
 /**
  * Determine the return type of an operation.
@@ -380,7 +491,7 @@ _slang_typeof_operation(const slang_assemble_ctx * A,
  * \return GL_TRUE for success, GL_FALSE if failure
  */
 GLboolean
-_slang_typeof_operation_(slang_operation * op,
+_slang_typeof_operation(slang_operation * op,
                          const slang_name_space * space,
                          slang_typeinfo * ti,
                          slang_atom_pool * atoms,
@@ -412,7 +523,7 @@ _slang_typeof_operation_(slang_operation * op,
    case SLANG_OPER_DIVASSIGN:
    case SLANG_OPER_PREINCREMENT:
    case SLANG_OPER_PREDECREMENT:
-      if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
+      if (!_slang_typeof_operation(op->children, space, ti, atoms, log))
          return GL_FALSE;
       break;
    case SLANG_OPER_LITERAL_BOOL:
@@ -479,7 +590,7 @@ _slang_typeof_operation_(slang_operation * op,
    case SLANG_OPER_VARIABLE_DECL:
       {
          slang_variable *var;
-         var = _slang_locate_variable(op->locals, op->a_id, GL_TRUE);
+         var = _slang_variable_locate(op->locals, op->a_id, GL_TRUE);
          if (!var) {
             slang_info_log_error(log, "undefined variable '%s'",
                                  (char *) op->a_id);
@@ -490,12 +601,20 @@ _slang_typeof_operation_(slang_operation * op,
             return GL_FALSE;
          }
          ti->can_be_referenced = GL_TRUE;
-         ti->array_len = var->array_len;
+         if (var->type.specifier.type == SLANG_SPEC_ARRAY &&
+             var->type.array_len >= 1) {
+            /* the datatype is an array, ex: float[3] x; */
+            ti->array_len = var->type.array_len;
+         }
+         else {
+            /* the variable is an array, ex: float x[3]; */
+            ti->array_len = var->array_len;
+         }
       }
       break;
    case SLANG_OPER_SEQUENCE:
       /* TODO: check [0] and [1] if they match */
-      if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms, log)) {
+      if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) {
          return GL_FALSE;
       }
       ti->can_be_referenced = GL_FALSE;
@@ -509,7 +628,7 @@ _slang_typeof_operation_(slang_operation * op,
       /*case SLANG_OPER_ANDASSIGN: */
    case SLANG_OPER_SELECT:
       /* TODO: check [1] and [2] if they match */
-      if (!_slang_typeof_operation_(&op->children[1], space, ti, atoms, log)) {
+      if (!_slang_typeof_operation(&op->children[1], space, ti, atoms, log)) {
          return GL_FALSE;
       }
       ti->can_be_referenced = GL_FALSE;
@@ -542,7 +661,7 @@ _slang_typeof_operation_(slang_operation * op,
       break;
    /*case SLANG_OPER_MODULUS: */
    case SLANG_OPER_PLUS:
-      if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
+      if (!_slang_typeof_operation(op->children, space, ti, atoms, log))
          return GL_FALSE;
       ti->can_be_referenced = GL_FALSE;
       ti->is_swizzled = GL_FALSE;
@@ -559,7 +678,7 @@ _slang_typeof_operation_(slang_operation * op,
 
          if (!slang_typeinfo_construct(&_ti))
             return GL_FALSE;
-         if (!_slang_typeof_operation_(op->children, space, &_ti, atoms, log)) {
+         if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) {
             slang_typeinfo_destruct(&_ti);
             return GL_FALSE;
          }
@@ -583,7 +702,18 @@ _slang_typeof_operation_(slang_operation * op,
       }
       break;
    case SLANG_OPER_CALL:
-      if (op->fun) {
+      if (op->array_constructor) {
+         /* build array typeinfo */
+         ti->spec.type = SLANG_SPEC_ARRAY;
+         ti->spec._array = (slang_type_specifier *)
+            _slang_alloc(sizeof(slang_type_specifier));
+         slang_type_specifier_ctr(ti->spec._array);
+
+         ti->spec._array->type =
+            slang_type_specifier_type_from_string((char *) op->a_id);
+         ti->array_len = op->num_children;
+      }
+      else if (op->fun) {
          /* we've resolved this call before */
          slang_type_specifier_copy(&ti->spec, &op->fun->header.type.specifier);
       }
@@ -642,14 +772,14 @@ _slang_typeof_operation_(slang_operation * op,
 
          if (!slang_typeinfo_construct(&_ti))
             return GL_FALSE;
-         if (!_slang_typeof_operation_(op->children, space, &_ti, atoms, log)) {
+         if (!_slang_typeof_operation(op->children, space, &_ti, atoms, log)) {
             slang_typeinfo_destruct(&_ti);
             return GL_FALSE;
          }
          if (_ti.spec.type == SLANG_SPEC_STRUCT) {
             slang_variable *field;
 
-            field = _slang_locate_variable(_ti.spec._struct->fields, op->a_id,
+            field = _slang_variable_locate(_ti.spec._struct->fields, op->a_id,
                                            GL_FALSE);
             if (field == NULL) {
                slang_typeinfo_destruct(&_ti);
@@ -660,6 +790,7 @@ _slang_typeof_operation_(slang_operation * op,
                return GL_FALSE;
             }
             ti->can_be_referenced = _ti.can_be_referenced;
+            ti->array_len = field->array_len;
          }
          else {
             GLuint rows;
@@ -748,7 +879,7 @@ _slang_typeof_operation_(slang_operation * op,
       break;
    case SLANG_OPER_POSTINCREMENT:
    case SLANG_OPER_POSTDECREMENT:
-      if (!_slang_typeof_operation_(op->children, space, ti, atoms, log))
+      if (!_slang_typeof_operation(op->children, space, ti, atoms, log))
          return GL_FALSE;
       ti->can_be_referenced = GL_FALSE;
       ti->is_swizzled = GL_FALSE;
@@ -761,77 +892,6 @@ _slang_typeof_operation_(slang_operation * op,
 }
 
 
-/**
- * Lookup a function according to name and parameter count/types.
- */
-slang_function *
-_slang_locate_function(const slang_function_scope * funcs, slang_atom a_name,
-                       slang_operation * args, GLuint num_args,
-                       const slang_name_space * space, slang_atom_pool * atoms,
-                       slang_info_log *log, GLboolean *error)
-{
-   slang_typeinfo arg_ti[100];
-   GLuint i;
-
-   *error = GL_FALSE;
-
-   /* determine type of each argument */
-   assert(num_args < 100);
-   for (i = 0; i < num_args; i++) {
-      if (!slang_typeinfo_construct(&arg_ti[i]))
-         return NULL;
-      if (!_slang_typeof_operation_(&args[i], space, &arg_ti[i], atoms, log)) {
-         return NULL;
-      }
-   }
-
-   /* loop over function scopes */
-   while (funcs) {
-
-      /* look for function with matching name and argument/param types */
-      for (i = 0; i < funcs->num_functions; i++) {
-         slang_function *f = &funcs->functions[i];
-         const GLuint haveRetValue = _slang_function_has_return_value(f);
-         GLuint j;
-
-         if (a_name != f->header.a_name)
-            continue;
-         if (f->param_count - haveRetValue != num_args)
-            continue;
-
-         /* compare parameter / argument types */
-         for (j = 0; j < num_args; j++) {
-            if (!slang_type_specifier_compatible(&arg_ti[j].spec,
-                              &f->parameters->variables[j]->type.specifier)) {
-               /* param/arg types don't match */
-               break;
-            }
-
-            /* "out" and "inout" formal parameter requires the actual
-             * argument to be an l-value.
-             */
-            if (!arg_ti[j].can_be_referenced &&
-                (f->parameters->variables[j]->type.qualifier == SLANG_QUAL_OUT ||
-                 f->parameters->variables[j]->type.qualifier == SLANG_QUAL_INOUT)) {
-               /* param is not an lvalue! */
-               *error = GL_TRUE;
-               return NULL;
-            }
-         }
-
-         if (j == num_args) {
-            /* name and args match! */
-            return f;
-         }
-      }
-
-      funcs = funcs->outer_scope;
-   }
-
-   return NULL;
-}
-
-
 /**
  * Determine if a type is a matrix.
  * \return GL_TRUE if is a matrix, GL_FALSE otherwise.